Ryan Ryan - 2 months ago 61
Android Question

Android - Firebase - Do I need to remove EVERY single listener?

I did a reasonable amount of research and can not find the answer I need.

What I DO know: When I attach a ValueEventListener to a database reference, I know I need to remove it later (finding that out the hard way now with some massive memory leakage.

What I DON'T know: Do I also need to detach all other listeners? (This is to include Firebase Database, Storage, and Auth, the three APIs I am using)

Example:

UploadTask uploadTask = ref.putFile(uploadFile);

uploadTask.addOnFailureListener(new OnFailureListener() {
//@Override code here
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TakeSnapshot>() {
//@Override code here
}).addOnProgressListner(new OnProgressListner<UploadTask.TakeSnapshot>() {
//@Override code here
};


I think that's enough to show you the point of what I mean. This is how my actual code is currently structured.

Questions:


  1. Do I need to remove all of those listeners just in case the activity
    is terminated (system decision, phone dies, whatever) before that
    callback happens?

  2. Can I bundle them up somehow and terminate them all three at once
    because I have like 30 of these in my code and really don't feel
    like restructuring all of it in order to assign all these listeners
    to variables JUST so I can pass them into the
    "removeBlahBlahBlahListener(listenerVariable)" over and over.

  3. Slightly off topic, but, I am too lazy to move all my code from
    onCreate to onStart... is is bad practice for me to remove all these
    listeners, finish things up, call finish() (or whatever it is that
    kills off an activity) and just recreate the activity from scratch?
    It's a small simple app so the overhead of re-creating the activity
    is no biggie. Just curious what is "right".



I imagine this is just a result of poor planning and lack of knowledge (I only program for fun, not for a job unfortunately) so if I have to take the hard route I guess it's a learning experience, right?

Answer

Auto unregistering listeners when an activity stops is a feature on the class "Task" in android and its derived classes (StorageTask).

This means you can do something like this:

UploadTask uploadTask = ref.putFile(uploadFile);

uploadTask.addOnFailureListener(thisActivity, new OnFailureListener() {
//@Override code here
}).addOnSuccessListener(thisActivity, new OnSuccessListener<UploadTask.TaskSnapshot>() {
//@Override code here
}).addOnProgressListner(thisActivity, new OnProgressListner<UploadTask.TaskSnapshot>() {
//@Override code here
};

You can also do this with Task objects returned from the realtime Database such as setValue as in:

databaseReference.setValue("newValue").addOnSuccessListener(thisActivity, ...)

So to answer your questions directly:

  1. Use the activity scoped version to automatically unregister the listeners on activity stop. Note that for storage, you can query running operations when your activity starts using StorageReference.getActiveUploadTasks and StorageReference.getActiveDownloadTasks and re-subscribe.

  2. You shouldn't need to unsubscribe manually if using scoped listeners. I do not know of a way to batch unsubscribe to non-task based listeners.

  3. Well I'm not sure how you can guarantee that the OS will always kill your task instead of stopping/starting it again -- and how your finish code will be guaranteed to run. I would advise you move the code to onStart