Как отключить прослушиватель моментальных снимков Firestore в репозитории (MVVM) - PullRequest
0 голосов
/ 28 мая 2020

Я считаю, что мне нужно отсоединить слушателей 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)

Передав это через виртуальную машину , Репозиторий для snapshotListener, как показано ниже:

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

Но не был уверен, рекомендуется ли это сделать или как лучше всего захватить контекст во фрагменте?

Быстрый бонусный вопрос из интереса; создает ли код snapshots.documentChanges дополнительных слушателей? Я просто использую во время отладки, но думал, что может ..

1 Ответ

2 голосов
/ 28 мая 2020

Уровень вашего репозитория никогда не должен содержать ни одной строки кода, относящегося к Android. Ваша ViewModel является общей основой для кода Android и уровня репо. Вы можете сделать жизненный цикл ViewModel осведомленным, реализовав интерфейс LifeCycleObserver.

class YourViewModel : LifeCycleObserver {

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

}

В вашей деятельности:

onCreate() {
   lifecycle.addObserver(yourViewModel)
}

Не нужно беспокоиться об удалении наблюдателя ViewModel вручную, он исчезнет в uncleared состояние вашей ViewModel. Просто имейте в виду, что на уровне репозитория не должно быть кода, связанного с Android. Если вам нужен контекст, вы можете использовать AndroidViewModel (в пределах приложения). Иногда невозможно выделить контекст, в этом случае я бы просто предоставил ему applicationContext, но не контекст Activity.

...