如何分离 firestore 侦听器
How to detach firestore listener
我是 FireStore 新手。我创建了一个 ListenerRegistration 来更新我的 Recycler View。我知道我的实现可能并不完美,但每次我的 activity 被销毁时,我的应用程序都会在此 Listener 内的行上抛出错误。我不知道为什么,但是 mt registration.remove() 在 destroy 之前或 finish() activity 之后不工作。有人可以帮忙吗?
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();
我的问题解决了。但如果我不这样做,我会收到以下错误:
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.onEvent(HomeActivity.java:200)
at santauti.app.Activities.Home.HomeActivity.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)
当你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>() {
您需要更新 MainActivity.this
以匹配您的代码。
通过传入 activity,Firestore 可以在 activity 停止时自动清理监听器。
另一种选择是使用 get()
来获取那些嵌套的文档,它只读取文档一次。由于它只读取一次,所以没有监听器需要清理。
在您的代码中添加这两个方法,这将解决您的问题。
@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;
}
}
如果您使用的是 MVVM 架构,特别是 ViewModel 和 LiveData 架构 classes,那么通过 addSnapshotListener() 方法传递 activity 并不是一个好主意。
您需要做的是从 addSnapshotListener 方法存储 ListenerRegistration 并在 LiveData 的 onInactive() 方法上手动删除监听器 class.
使用 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
ListenerRegistration 是关键
如果您想从 FirebaseDatabase 启动和停止实时更新,那么您应该使用 ListenerRegistration.
注册和取消注册您的 EventListners
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());
}
}
}
我是 FireStore 新手。我创建了一个 ListenerRegistration 来更新我的 Recycler View。我知道我的实现可能并不完美,但每次我的 activity 被销毁时,我的应用程序都会在此 Listener 内的行上抛出错误。我不知道为什么,但是 mt registration.remove() 在 destroy 之前或 finish() activity 之后不工作。有人可以帮忙吗?
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();
我的问题解决了。但如果我不这样做,我会收到以下错误:
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.onEvent(HomeActivity.java:200) at santauti.app.Activities.Home.HomeActivity.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)
当你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>() {
您需要更新 MainActivity.this
以匹配您的代码。
通过传入 activity,Firestore 可以在 activity 停止时自动清理监听器。
另一种选择是使用 get()
来获取那些嵌套的文档,它只读取文档一次。由于它只读取一次,所以没有监听器需要清理。
在您的代码中添加这两个方法,这将解决您的问题。
@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;
}
}
如果您使用的是 MVVM 架构,特别是 ViewModel 和 LiveData 架构 classes,那么通过 addSnapshotListener() 方法传递 activity 并不是一个好主意。
您需要做的是从 addSnapshotListener 方法存储 ListenerRegistration 并在 LiveData 的 onInactive() 方法上手动删除监听器 class.
使用 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
ListenerRegistration 是关键
如果您想从 FirebaseDatabase 启动和停止实时更新,那么您应该使用 ListenerRegistration.
注册和取消注册您的 EventListnersFull 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());
}
}
}