0

To preface, I already have a fragment which observes the LiveData in the same way as below, and it works perfectly. For some reason, when trying to use the service as lifecycle owner I think this is causing a problem, and the observer is not being called.

I have checked the answer here but as I am using the same instance of ViewModel/Dao this shouldn't be my problem. (I think? Correct me if I'm wrong please.)

I have a service which extends HoverMenuService from MattCarroll's Hover. These services display overlay UI's, so I wanted to observe some LiveData from the service to update this UI. I made my service implement LifecycleOwner and basically copied LifecycleService implementation from the source code, so I could use the service as the lifecycle owner and add Observers to the LiveData.

Here's my service

class MyHoverMenuService : HoverMenuService(), LifecycleOwner {

    val TAG = "MyHoverMenuService"

    val mDispatcher = ServiceLifecycleDispatcher(this)

    override fun onHoverMenuLaunched(intent: Intent, hoverView: HoverView) {
        Timber.i("onHoverMenuLaunched called.")
        val menu: HoverMenu = MyHoverMenu(this, application, ContextThemeWrapper(this, R.style.AppTheme))
        hoverView.setMenu(menu)
        hoverView.collapse()
    }

    @CallSuper
    override fun onCreate() {
        mDispatcher.onServicePreSuperOnCreate()
        super.onCreate()
    }

    @CallSuper
    override fun onBind(intent: Intent?): IBinder? {
        mDispatcher.onServicePreSuperOnBind()
        return super.onBind(intent)
    }

    @CallSuper
    override fun onStart(intent: Intent?, startId: Int) {
        mDispatcher.onServicePreSuperOnStart()
        super.onStart(intent, startId)
    }

    @CallSuper
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        return super.onStartCommand(intent, flags, startId)
    }

    @CallSuper
    override fun onDestroy() {
        mDispatcher.onServicePreSuperOnDestroy()
        super.onDestroy()
    }

    @CallSuper
    override fun getLifecycle(): Lifecycle {
        return mDispatcher.lifecycle
    }


}

MyHoverMenu displays 2 Sections, but essentially the ownerService variable is passed through to this HoverDictionaryScreen class, where the UI is shown.

My HoverDictionaryScreen

class HoverDictionaryScreen(
    private val ownerService: MyHoverMenuService
    , val application:Application
    , val context: Context
) : Content {
    private val applicationContext: Context = context.applicationContext
    lateinit var dictViewModel: DictionaryInterfaceViewModel
    ...
    fun createScreenView(): View {
        val container: ViewGroup = FrameLayout(ContextThemeWrapper(applicationContext, R.style.AppTheme))


        binding = DataBindingUtil.inflate(
            LayoutInflater.from(applicationContext),
            R.layout.fragment_dictionary_interface,
            container,
            false
        )
        dictViewModel = ViewModelProvider
            .AndroidViewModelFactory.getInstance(application)
            .create(DictionaryInterfaceViewModel::class.java)
        dictViewModel.totalEntries.observe(ownerService, Observer { totalEntries ->
            binding.numberOfEntries.text = "Total number of entries in database : $totalEntries"
        })
    ...

In my DictionaryInterfaceViewModel the totalEntries var is initialised from the dao. So essentially the observer should be called as soon as it is applied (Which does happen in my fragment).

When I check the binding.numberOfEntries isn't updated, and I also checked that the observer isn't called with a log statement.

AlpacaJones
  • 114
  • 8

1 Answers1

1

Ok so I noticed my ownerService.lifecycle.currentState was never reaching STARTED. This was because the HoverMenuService, which extends Service was overriding/ removing the onStart method, so where I had:

@CallSuper
override fun onStart(intent: Intent?, startId: Int) {
    mDispatcher.onServicePreSuperOnStart()
    super.onStart(intent, startId)
}

It seemed this wasn't cutting it, but in the docs for ServiceLifecycleDispatcher.onServicePreSuperOnStart() it mentioned this could go in either onStart() or onStartCommand() and so by putting this into onStartCommand() (which is implemented in the HoverMenuService abstract class) my service lifecycle now reaches a STARTED state and everything works.

@CallSuper
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    mDispatcher.onServicePreSuperOnStart()
    return super.onStartCommand(intent, flags, startId)
}
AlpacaJones
  • 114
  • 8