如何分离firestore监听器

时间:2017-10-15 15:48:11

标签: android google-cloud-firestore

我是FireStore的新手。我创建了一个ListenerRegistration来更新我的Recycler View。我知道我的实现可能并不完美,但每次我的活动被破坏时,我的应用程序都会在此监听器内的行上引发错误。我不知道为什么,但mt registration.remove()在destroy之前或者finish()活动之后都没有工作。有人可以帮忙吗?

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;
            }

我的onDestroy方法:

@Override
protected void onDestroy() {
    super.onDestroy();
    registration.remove();
}

如果我删除了这个:

if(FirebaseAuth.getInstance().getCurrentUser()!=null)
                        FirebaseAuth.getInstance().signOut();

我的问题消失了。但如果我不这样做,我会收到以下错误:

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)

5 个答案:

答案 0 :(得分:13)

当您use addSnapshotListener you attach a listener被要求进行任何更改时。显然,在活动被破坏之前你必须detach those listeners。另一种方法是add the activity to your call to addSnapshotListener

 db.collection("Pessoa").document(paciente.getProfissionalResponsavel())
   .addSnapshotListener(MainActivity.this, new EventListener<DocumentSnapshot>() {

您需要更新MainActivity.this以匹配您的代码。

通过传入活动,Firestore可以在活动停止时自动清理侦听器。

另一种替代方法是使用get()来获取那些嵌套的文档,它只读取文档一次。因为它只读一次,所以没有听众清理。

答案 1 :(得分:3)

使用registration.remove();停止收听更改

Query query = db.collection("cities");
ListenerRegistration registration = query.addSnapshotListener(
        new EventListener<QuerySnapshot>() {
            // ...
        });

// ...

// Stop listening to changes
registration.remove();

详细了解此内容:https://firebase.google.com/docs/firestore/query-data/listen#detach_a_listener

答案 2 :(得分:1)

如果您正在使用MVVM架构,特别是ViewModel和LiveData架构类,那么通过addSnapshotListener()方法传递活动不是一个好主意。

您需要做的是从addSnapshotListener方法存储ListenerRegistration并手动删除LiveData类的onInactive()方法上的侦听器。

答案 3 :(得分:0)

在您的代码中添加这两个方法,这将解决您的问题。

@Override
public void onEvent(DocumentSnapshot documentSnapshot, 
FirebaseFirestoreException e) {
    if (e != null) {
        Log.w(LOG_TAG, ":onEvent", e);
        return;
    }
}

@Override
protected void onStop() {
    super.onStop();

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

答案 4 :(得分:0)

ListenerRegistration是关键

如果您要从FirebaseDatabase启动和停止实时更新,则应使用ListenerRegistration注册和注销EventListners。

  

完整代码:

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());

          }
      }

}