Solution 1:

When talking about listeners, yes, you need to remove them accordingly to the life-cycle of your activity and for this you need to use the following line of code:

databaseReference.removeEventListener(valueEventListener);

Remember if you don't do this, you'll end up wasting your battery and bandwidth. So:

  1. If you have added the listener in onStart you have to remove it in onStop.
  2. If you have added the listener in onResume you have to remove it in onPause.
  3. If you have added the listener in onCreate you have to remove it in onDestroy.

But remember onDestroy is not always called, so the last option in not always a good choice.

There is another approach in which there is no need to remove the listener and that is when using addListenerForSingleValueEvent:

Add a listener for a single change in the data at this location.

Solution 2:

To remove the ValueEventListener, you can then do this:

Remove the anonymity of the listener.

Change the code from this:-

      Ref.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });

into this:

   ValueEventListener listener= new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {

        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });
Ref.addValueEventListener(listener);

Now you will be able to remove the listener:

   @Override
public void onDestroy() {
if (Ref != null && listener != null) {
   Ref.removeEventListener(listener);
    }
 }

You need to remove it, so the listener does not stay running in the other activity lifecycles like onDestroy()

Solution 3:

I had the same issue and was causing a lot of memory leaks. So I created a new class that handles added listeners and removes them when the corresponding method (onPause(), onStop() or onDestroy()) is called. Uses the androidx.lifecycle library and is applicable to both activities and fragments (in fact, any class that implements LifecycleOwner).

You can check the code here. You will probably be good to go without manually adding the androidx.lifecycle dependency, but you can also add this to your module-level build.gradle:

implementation 'androidx.lifecycle:lifecycle-runtime:VERSION'

In your current code, instead of:

databaseReference.addValueEventListener(valueEventListener);
// or
databaseReference.addListenerForSingleValueEvent(valueEventListener);

you need to use:

addValueEventListener(databaseReference, valueEventListener); 
// or
addListenerForSingleValueEvent(databaseReference, valueEventListener);

This is valid when called from activities or fragments that use FirebaseListenerHandler, as shown in the gist. If you need to add a Firebase listener in another situation (like services), you still have to manually remove them.