如何在存储库 (MVVM) 中分离 Firestore SnapshotListener

How to Detach Firestore SnapshotListener in Repository (MVVM)

我认为我需要分离 Firestore 侦听器,但如果不将上下文传递到我的存储库,我不知道如何执行此操作。下面是一个例子:

片段

此方法在 onViewCreated 中调用并简单地更新 private var sitesList = ArrayList<SiteObject>() 用于在我的 recyclerview 中设置列​​表:

    private fun setupObservers() {
        Log.d(TAG, "setupObservers()")
        businessViewModel.listenToSites().observe(viewLifecycleOwner, Observer { allSites ->
            if (sitesList != allSites && allSites != null) {
                sitesList.clear()
                sitesList.addAll(allSites)
                sitesAdapter.setList(sitesList)
                sitesAdapter.notifyDataSetChanged()
            }
        })
    }

ViewModel

    fun listenToSites(): LiveData<ArrayList<SiteObject>> {
        Log.d(TAG, "listenToSites()")
        return businessRepository.listenToSites()
    }

存储库

这是创建 Firestore addSnapshotListener 的地方:

  fun listenToSites(): LiveData<ArrayList<SiteObject>> {

        Log.d(TAG, "listenToSites(), firebaseUser = ${firebaseUser?.uid}")
        val userId = firebaseUser?.uid

        firestore.collection(SITES).whereEqualTo("users.${userId}", true)
            .addSnapshotListener(MetadataChanges.INCLUDE, EventListener { snapshots, e ->
                if (e != null) {
                    Log.w(TAG, "listenToSites(), listen error:", e)
                    return@EventListener
                }
                val allSites = ArrayList<SiteObject>()
                if (snapshots != null) {
                    for (document in snapshots) {
                        val site = document.toObject(SiteObject::class.java)
                        site.siteID = document.id
                        allSites.add(site)
                    }

                    for (docChange in snapshots.documentChanges) {
                        when (docChange) {
                            DocumentChange.Type.ADDED -> Log.d(TAG, "New site: ${docChange.document.data}")
                            DocumentChange.Type.MODIFIED -> Log.d(TAG, "Modified site: ${docChange.document.data}")
                            DocumentChange.Type.REMOVED -> Log.d(TAG, "Removed site: ${docChange.document.data}")
                        }
                    }

                    val source = if (snapshots.metadata.isFromCache){
                        "local cache"
                    }
                    else {
                        "server"
                    }
                    Log.d(TAG, "Sites data fetched from $source")
                }
                sitesMutableLiveData.value = allSites

            })

        return sitesMutableLiveData
    }

所以我想我可以通过将片段上下文作为参数向上传递到链中来传递,如下所示:

businessViewModel.listenToSites(context)

通过 VM、Repository 将其传递给 snapshotListener,如下所示:

addSnapshotListener(context, MetadataChanges.INCLUDE, EventListener....

但不确定这是否是推荐的方法或如何最好地捕获片段中的上下文?

出于兴趣的快速奖金问题; snapshots.documentChanges 代码会创建额外的侦听器吗?我只是在调试时使用,但认为它可以..

您的存储库层永远不应包含一行 Android 相关代码。您的 ViewModel 是 Android 和回购层代码的共同点。您可以通过实现 LifeCycleObserver 接口使 ViewModel 生命周期感知。

class YourViewModel : LifeCycleObserver {

  @OnLifecycleEvent(Lifecycle.Event.ON_STOP) //Annotate it with any lifecycle event of your choice.
  fun aMethodThatRemovesObserver() {
      //Invoked on onStop()
  }

}

在你的activity中:

onCreate() {
   lifecycle.addObserver(yourViewModel)
}

无需担心手动删除 ViewModel 观察器,它会在您的 ViewModel 的 uncleared 状态下消失。请记住,存储库层不应包含 Android 相关代码。如果您需要上下文,您可以使用 AndroidViewModel (作用域为应用程序)。有时无法分离出上下文,在这种情况下,我只会为它提供一个 applicationContext 而不是 Activity 上下文。