Emilio Schepis
Emilio Schepis

Reputation: 1997

Removing Firestore snapshot listener inside of LiveData-returning function

I'm trying to optimise the performances in my app and I noticed that I do not remove Firestore listeners from my repository.

My repository has a number of functions that return a LiveData, that is then observed via Transformations from ViewModels and then the views.

One-time operations work absolutely fine (upload, delete etc.) but permanent listeners don't get garbage collected when the activity finishes.

Right now the function inside the repository looks like this:

// [...]
class Repository {   
  // [...]
  fun retrieveCode() {
  val observable = MutableLiveData<Code>()
  val reference = 
    FirebaseFirestore.getInstance().collection(/**/).document(/**/)

  reference
    .addSnapshotListener { snapshot, exception -> 
      if(exception != null) {
        observable.value = null
      }

      if(snapshot != null {
        observable.value = snapshot.//[convert to object]
      }
   }

   return observable
  }
}

I found a workaround which is to create a custom LiveData object that handles the listener removal when it becomes inactive, like this:

class CodeLiveData(private val reference: DocumentReference): 
  LiveData<Code>(), EventListener<DocumentSnapshot>{
  private var registration: ListenerRegistration? = null

  override fun onEvent(snapshot: DocumentSnapshot?, 
    exception: FirebaseFirestoreException?) {
    if(exception != null) {
      this.value = null
    }

    if(snapshot != null) {
      this.value = snapshot.//[convert to object]
    }
  }

  override fun onActive() {
    super.onActive()
    registration = reference.addSnapshotListener(this)
  }

  override fun onInactive() {
    super.onInactive()
    registration?.remove()
  }
}

Is there a way to solve this problem without creating a custom class, but rather by improving a function similar to the first example?

Thanks,

Emilio

Upvotes: 3

Views: 4455

Answers (1)

Alex Mamo
Alex Mamo

Reputation: 138824

There are two ways in which you can achieve this. The first one would be to stop listening for changes and this can be done in your onStop() function by calling remove() function on your ListenerRegistration object like this:

if (registration != null) {
    registration.remove();
}

The approach would be to you pass your activity as the first argument in the addSnapshotListener() function, so Firestore can clean up the listeners automatically when the activity is stopped.

var registration = dataDocumentReference
        .addSnapshotListener(yourActivity, listener)

Upvotes: 7

Related Questions