No event listener removal for Firebase DatabaseReference?
Solution 1
As the answer superman links to show: you indeed will need to remove the listener in the opposite lifecycle event.
To remove a listener, you need to keep the handle that is returned when you call addChildListener()
:
Query query = mDatabase.child("projects").orderByChild("viewCount").limitToLast(15);
ChildEventListener listener = query.addChildEventListener(new ChildEventListener() { ...
And then pass it to removeEventListener()
:
query.removeChildEventListener(listener);
You can see that I explicitly use a Query
here, since that is what you actually attach your listener to. But if you have a plain DatabaseReference
the same methods are available, since DatabaseReference
inherits from Query
.
Solution 2
Firebase objects are lightweight references to locations in your Firebase Database. There is no need (nor ability) to manage their life-cycle. So, you can just let the Java garbage collector take care of them.
However, once you start attaching listeners (e.g. addValueEventListener()
) you should detach them in the corresponding life-cycle event with removeEventListener()
. Also see Firebase adding listeners in adapters in Android and How stop Listening to firebase location in android.
Solution 3
As Frank says, you need to remove the listener from the exact DatabaseReference, not just the root DatabaseReference as I was doing.
To simplify this, I created a small class below:
public class FirebaseListenerRef {
private ValueEventListener listener;
private DatabaseReference ref;
public FirebaseListenerRef(DatabaseReference ref, ValueEventListener listener) {
this.listener = listener;
this.ref = ref;
// Start listening on this ref.
ref.addValueEventListener(listener);
}
public void detach() {
ref.removeEventListener(listener);
}
}
To use this, just create and detach it in paired lifecycle events, e.g.
private FirebaseListenerRef myFirebaseListenerRef;
public void onAttach(Content context) {
super.onAttach(context);
myFirebaseListenerRef = new FirebaseListenerRef(
FirebaseDatabase.getInstance().getReference().child("path-to-listen-on",
new ValueEventListener() {
... implement the listener logic
}
);
}
public void onDetach() {
super.onDetach();
if ( myFirebaseListenerRef != null ) {
// Detach our listener from its reference
myFirebaseListenerRef.detach();
myFirebaseListenerRef == null;
}
}
Solution 4
If you use Query
to add addValueEventListener
. Then you should remove the listener using Query
instance not DatabaseReference
instance.
In question with DatabaseReference
the developer was using orderByChild
which is of type Query
So to remove the listener we need to get reference to Query instance and then use removeEventListener
.
Here is my example of removing the listener:
ValueEventListener carChangesListener;
Query ownerId_Query;
Then
DatabaseReference bikeRef = FirebaseDatabase.getInstance().getReference().child("Cars");
ownerId_Query = bikeRef.orderByChild("ownerId").equalTo(FirebaseAuth.getInstance().getCurrentUser().getUid());
carChangesListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue() != null) {
/*NOTE: handle cars response here*/
}else{
Toast.makeText(getActivity(), "No car found for this user.",
Toast.LENGTH_LONG).show();
}
}
@Override
public void onCancelled(DatabaseError databaseError) {
Log.w(HOME_TAG, "Failed to read value.", databaseError.toException());
Toast.makeText(getActivity(), "Error!" + databaseError.toException().getMessage(),
Toast.LENGTH_LONG).show();
}
};
ownerId_Query.addValueEventListener(bikeChangesListener);
Now to remove the carChangesListener
I will do following:
ownerId_Query.removeEventListener(carChangesListener);
Lion789
Updated on June 05, 2022Comments
-
Lion789 about 2 years
Hey do I need to remove this listener at some point, or does it get removed on its own? I have this called in a fragment within my activity, and users can go to another view without this one being destroyed. Therefore not sure if I am somehow suppose to remove this in an
onDestroy
,onPause
call? I do not see a way to remove it since it is aDatabaseReference
Here is the code:
private DatabaseReference mDatabase; mDatabase.child("projects").orderByChild("viewCount").limitToLast(15).addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String s) {
-
Lion789 over 7 yearsso adding a ChildEventListener ... does that require then for the listener to be removed if so how do I call it because there is no method like that on the DatabaseReference?
-
Tamas about 6 yearsThanks, I had the exact same problem. Removing the listener from DatabaseReference does nothing. This mistake doesn't event show up in the logs, and most tutorials fail to mention it.
-
DragonFire about 4 yearsI think it is about time for android to think about a class of variables and methods which are not null by birth (so they could be declared as private nonNull -> and so on) if they have not got them already.. the null pointer reference is mostly a nuisance in my experience...
-
DragonFire about 4 yearsyou may like to reattach the listener like query.addChildEventListener(listener) on your on onResume, onRestart or onStart depending on requirement.... because if you remove the listeners and minimize the app and bring it up again it will have stopped listening