I’m new to FireStore. I created a ListenerRegistration to update my Recycler View. I know my implementation may not be perfect, but every time my activity got destroyed, my app throws an error on the lines that are inside this Listener. I don’t know why, but mt registration.remove() is not working before on destroy or after finish() activity. Can someone help?
public class MainActivity extends AppCompatActivity {
private ListenerRegistration registration;
private com.google.firebase.firestore.Query query;
private void requestPacienteList(){
FirebaseFirestore db = FirebaseFirestore.getInstance();
progress.setVisibility(View.VISIBLE);
query = db.collection("Hospital");
registration = query.addSnapshotListener(new EventListener<QuerySnapshot>() {
@Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
for(DocumentSnapshot documentSnapshot : documentSnapshots){
if(documentSnapshot.get("nome").equals("Santa Clara")){
hospital = documentSnapshot.toObject(Hospital.class);
hospital.setHospitalDocumentKey(documentSnapshot.getId());
FirebaseFirestore db = FirebaseFirestore.getInstance();
db.collection("Hospital")
.document(hospital.getHospitalDocumentKey())
.collection("Pacientes")
.addSnapshotListener(new EventListener<QuerySnapshot>() {
@Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
homeModelList.clear();
for(DocumentSnapshot documentSnapshot : documentSnapshots){
final Paciente paciente = documentSnapshot.toObject(Paciente.class);
paciente.setPacienteKey(documentSnapshot.getId());
FirebaseFirestore db = FirebaseFirestore.getInstance();
db.collection("Pessoa")
.document(paciente.getProfissionalResponsavel())
.addSnapshotListener(new EventListener<DocumentSnapshot>() {
@Override
public void onEvent(DocumentSnapshot documentSnapshot, FirebaseFirestoreException e) {
Profissional profissional = documentSnapshot.toObject(Profissional.class);
int[] covers = new int[]{R.drawable.ic_person_black};
HomeModel p = new HomeModel(paciente.getNome()+" "+paciente.getSobrenome(),paciente.getBox(),paciente.getLeito(),
covers[0],profissional.getNome()+ " "+profissional.getSobrenome(),paciente.getPacienteKey());
homeModelList.add(p);
homeAdapter.notifyDataSetChanged();
prepareListaPacientes();
}
});
}
}
});
}
}
}
});
switch (id){
case R.id.logout:
if(FirebaseAuth.getInstance().getCurrentUser()!=null)
FirebaseAuth.getInstance().signOut();
Intent it = new Intent(HomeActivity.this, MainActivity.class);
startActivity(it);
if(registration!=null)
registration.remove();
finish();
drawerLayout.closeDrawers();
break;
}
}
}
My onDestroy method:
@Override
protected void onDestroy() {
super.onDestroy();
registration.remove();
}
When I remove this if:
if(FirebaseAuth.getInstance().getCurrentUser()!=null)
FirebaseAuth.getInstance().signOut();
My problem is gone. But if I don’t, I get the following error:
java.lang.NullPointerException: Attempt to invoke virtual method
‘java.lang.Object
com.google.firebase.firestore.DocumentSnapshot.toObject(java.lang.Class)’
on a null object reference
at santauti.app.Activities.Home.HomeActivity$4$1$1.onEvent(HomeActivity.java:200)
at santauti.app.Activities.Home.HomeActivity$4$1$1.onEvent(HomeActivity.java:197)
at com.google.firebase.firestore.DocumentReference.zza(Unknown Source)
at com.google.firebase.firestore.zzd.onEvent(Unknown Source)
at com.google.android.gms.internal.zzejz.zza(Unknown Source)
at com.google.android.gms.internal.zzeka.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
When you use addSnapshotListener
you attach a listener that gets called for any changes. Apparently you have to detach those listeners before the activity gets destroyed. An alternative is to add the activity
to your call to addSnapshotListener
:
db.collection("Pessoa").document(paciente.getProfissionalResponsavel())
.addSnapshotListener(MainActivity.this, new EventListener<DocumentSnapshot>() {
You’ll need to update MainActivity.this
to match your code.
By passing in the activity, Firestore can clean up the listeners automatically when the activity is stopped.
Yet another alternative is to use get()
to get those nested documented, which just reads the document once. Since it only reads once, there is no listener to clean up.
Answer:
use registration.remove();
for Stop listening to changes
Query query = db.collection("cities");
ListenerRegistration registration = query.addSnapshotListener(
new EventListener<QuerySnapshot>() {
// ...
});
// ...
// Stop listening to changes
registration.remove();
see more about this : https://firebase.google.com/docs/firestore/query-data/listen#detach_a_listener
Answer:
If you’re using MVVM architecture specifically the ViewModel and LiveData architecture classes, then it’s not a good idea to pass an activity via addSnapshotListener() method.
What you need to do is store the ListenerRegistration from the addSnapshotListener method and manually remove the listener on onInactive() method of LiveData class.
Answer:
Add these two method in your code, this will solve your problem.
@Override
public void onEvent(DocumentSnapshot documentSnapshot,
FirebaseFirestoreException e) {
if (e != null) {
Log.w(LOG_TAG, ":onEvent", e);
return;
}
}
and
@Override
protected void onStop() {
super.onStop();
if (registration!= null) {
registration.remove();
registration = null;
}
}
Answer:
ListenerRegistration is the Key
If you want to start and stop Realtime Updates from a FirebaseDatabase then you should register and unregister your EventListners with ListenerRegistration.
Full Code:
MyActivity extends AppCompatActivity implements EventListener<QuerySnapshot>{
private CollectionReference collectionRef; //<- You will get realtime updates on this
private ListenerRegistration registration;
public void registerListner(){
registration = collectionRef.addSnapshotListener(this);
}
public void unregisterListener(){
registration.remove(); //<-- This is the key
}
@Override
public void onEvent(@javax.annotation.Nullable QuerySnapshot queryDocumentSnapshots, @javax.annotation.Nullable FirebaseFirestoreException e) {
for(DocumentChange dc : queryDocumentSnapshots.getDocumentChanges()){
Log.d("Tag", dc.getType().toString()+" "+dc.getDocument().getData());
}
}
}
Tags: androidandroid, list, rest