我正在从firestore检索医院数据。我想保持检索到的数据对整个片段是全局的,但Map在从addOnSuccessListner((中出来后将返回null。
我已经在CreateView((中声明了Map
static Map<String, Map<String, String>> hospitals ;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_home, container, false);
hospitals = new HashMap<>();
.......
.....
return root;
}
下面是我检索HospitalData的代码。
private void readHospitalData() {
CollectionReference collectionReference = fStore.collection("hospital Details");
collectionReference.get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
for(QueryDocumentSnapshot queryDocumentSnapshot: queryDocumentSnapshots){
Map<String, String> map = new HashMap<>();
map.put("h_name", queryDocumentSnapshot.getString("h_name"));
map.put("h_email", queryDocumentSnapshot.getString("h_email"));
map.put("h_phone", queryDocumentSnapshot.getString("h_phone"));
map.put("h_road", queryDocumentSnapshot.getString("h_road"));
map.put("h_area", queryDocumentSnapshot.getString("h_area"));
map.put("h_city", queryDocumentSnapshot.getString("h_city"));
map.put("h_state", queryDocumentSnapshot.getString("h_state"));
map.put("h_pincode", queryDocumentSnapshot.getString("h_pincode"));
hospitals.put(queryDocumentSnapshot.getId(), map);
}
Log.d("MAP-->" , hospitals.toString()); // display the Map
}
});
Log.d("MAP-->" , hospitals.toString()); // but here it will display null
}
Firebase API调用处理读写数据是完全异步的。这意味着调用总是立即返回,而不会阻塞代码等待结果。结果会在晚些时候出来,只要他们准备好了。
这就是为什么你在这里得到空
CollectionReference collectionReference = fStore.collection("hospital Details");
collectionReference.get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
public void onSuccess(DocumentSnapshot snapshot) {
// handle the document snapshot here
}
});
task.addOnFailureListener(new OnFailureListener() {
public void onFailure(Exception e) {
// handle any errors here
}
});
Log.d("MAP-->" , hospitals.toString());
企业消费者API这种行为的原因:->为什么要让API的消费者经历使用异步API的额外麻烦?难道我们不能只使用更简单的同步API吗?好吧,Firebase可以为移动应用程序提供同步API,但我们会继承两个问题中的一个,这两个问题都比编写额外的代码更糟糕。
1.在应用程序的主线程上调用同步函数可能会无限期冻结应用程序,这是一种糟糕的用户体验。在安卓系统上,它还可以通过应用程序未响应(ANR(对话框进行软崩溃。
- 为了避免用异步方法阻塞主线程,我们必须管理自己的线程才能正确调用这些API。这是更多的代码,可能很难正确处理。即使是专业的工程师也面临着正确线程行为的挑战
思考异步
Firebase API对应用程序主线程的性能非常敏感。这意味着任何需要处理磁盘或网络上数据的Firebase API都是以异步方式实现的。函数将立即返回,因此您可以在主线程上调用它们,而不必担心性能问题。您所要做的就是使用文档和示例中建立的模式来实现回调。
对于这个问题,有一个解决方案,您必须使用Kotlin Flow进行同步调用,请访问此链接:https://developer.android.com/kotlin/flow#callback
我使用回调解决了这个问题
我创建了HospitalData.class并从那里的firebase检索数据。通过使用回调接口,我读取片段中的数据
HospitalData.class
public class HospitalData {
FirebaseFirestore fStore = FirebaseFirestore.getInstance();
Map<String, Map<String, String>> hospitals = new HashMap<>();
HospitalCallback hospitalCallback;
HospitalData(){
// empty constructor
}
public void setHospitalCallback(HospitalCallback hospitalCallback) {
this.hospitalCallback = hospitalCallback;
}
void getHospitalData(){
CollectionReference collectionReference = fStore.collection("hospital Details");
collectionReference.get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
for(QueryDocumentSnapshot queryDocumentSnapshot: queryDocumentSnapshots){
Map<String, String> map = new HashMap<>();
map.put("h_name", queryDocumentSnapshot.getString("h_name"));
map.put("h_email", queryDocumentSnapshot.getString("h_email"));
map.put("h_phone", queryDocumentSnapshot.getString("h_phone"));
map.put("h_road", queryDocumentSnapshot.getString("h_road"));
map.put("h_area", queryDocumentSnapshot.getString("h_area"));
map.put("h_city", queryDocumentSnapshot.getString("h_city"));
map.put("h_state", queryDocumentSnapshot.getString("h_state"));
map.put("h_pincode", queryDocumentSnapshot.getString("h_pincode"));
hospitals.put(queryDocumentSnapshot.getId(), map);
}
hospitalCallback.DisplayHospitalData(hospitals);
}
});
}
interface HospitalCallback{
public void DisplayHospitalData(Map<String, Map<String, String>> map);
}
}
在我的家Fragment.class
public class HomeFragment extends Fragment implements HospitalCallback{
static Map<String, Map<String, String>> hospitals ;
HospitalData hospitalData;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_home, container, false);
hospitals = new HashMap<>();
hospitalData = new HospitalData();
hospitalData.getHospitalData();
hospitalData.setHospitalCallback(this);
return root;
}
@Override
public void DisplayHospitalData(Map<String, Map<String, String>> map) {
Log.d("HOSPITAL DATA-->", map.toString());
}
}