如何在存储库 (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 上下文。
我认为我需要分离 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 上下文。