LiveData 未通知我的服务(LifecyclerOwner 实施)观察者

Posted

技术标签:

【中文标题】LiveData 未通知我的服务(LifecyclerOwner 实施)观察者【英文标题】:My service's (LifecyclerOwner Implementation) observers are not being notified by LiveData 【发布时间】:2020-11-11 08:42:51 【问题描述】:

首先,我已经有一个片段,它以与下面相同的方式观察 LiveData,并且它工作得很好。出于某种原因,当尝试将服务用作生命周期所有者时,我认为这会导致问题,并且没有调用观察者。

我已经检查了答案here,但由于我使用的是相同的 ViewModel/Dao 实例,所以这不应该是我的问题。 (我认为?如果我错了,请纠正我。)

我有一项从 MattCarroll 的 Hover 扩展 HoverMenuService 的服务。这些服务显示覆盖 UI,因此我想从服务中观察一些 LiveData 以更新此 UI。我让我的服务实现了 LifecycleOwner 并基本上从 the source code 复制了 LifecycleService 实现,所以我可以将该服务用作生命周期所有者并将观察者添加到 LiveData。

这是我的服务

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 显示 2 个部分,但本质上 ownerService 变量被传递到显示 UI 的 HoverDictionaryScreen 类。

我的 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"
        )
    ...

在我的 DictionaryInterfaceViewModel 中,totalEntries 变量是从 dao 初始化的。所以基本上观察者应该在应用后立即被调用(这确实发生在我的片段中)。

当我检查 binding.numberOfEntries 没有更新时,我还检查了观察者没有被日志语句调用。

【问题讨论】:

【参考方案1】:

好的,所以我注意到我的 ownerService.lifecycle.currentState 从未达到 STARTED。这是因为扩展 Service 的 HoverMenuService 覆盖/删除了 onStart 方法,所以我有:

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

似乎这不是削减它,但在 the docs for ServiceLifecycleDispatcher.onServicePreSuperOnStart() 中提到这可以进入 onStart()onStartCommand() 等通过将其放入 onStartCommand() (已实现在 HoverMenuService 抽象类中)我的服务生命周期现在达到 STARTED 状态并且一切正常。

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

【讨论】:

以上是关于LiveData 未通知我的服务(LifecyclerOwner 实施)观察者的主要内容,如果未能解决你的问题,请参考以下文章

onChanged LiveData 未调用,RecyclerView 保持为空

Android AAC第一篇 Lifecycle的源码解析

Android AAC第一篇 Lifecycle的源码解析

未解决的参考:asLiveData 同时将 Flow 转换为 LiveData

将项目添加到 LiveData 列表时通知观察者

从服务器发送通知时未触发推送事件