【问题标题】:Global variable is returning null in android studio [duplicate]全局变量在android studio中返回null [重复]
【发布时间】:2021-07-28 09:51:03
【问题描述】:

我正在从 Firestore 中检索医院数据。我想将检索到的数据保持为整个片段的全局,但是从 addOnSuccessListner() 出来后 Map 将返回 null。

我已经在 onCreateView() 中声明了 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

}

【问题讨论】:

  • 它不应该为空,除非你在 onCreateView 之前调用 readHospitalData 。它将为空 collectionReference.get() 是一个异步调用,因此您只需将 Logs 放入 onSuccess 中。
  • 您也可以查看 this

标签: java android firebase google-cloud-firestore global-variables


【解决方案1】:

处理读取和写入数据的 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());

Firebase 消费者 API 出现这种行为的原因: -> 为什么要让 API 的使用者经历使用异步 API 的额外麻烦?我们不能只使用更简单的同步 API 吗?好吧,Firebase 可以为移动应用程序提供同步 API,但是我们会继承两个问题之一,这两个问题都比编写这些额外的代码更糟糕。

1.在应用的主线程上调用同步函数可能会无限期地冻结应用,这是一种糟糕的用户体验。在 Android 上,它还可能出现应用程序无响应 (ANR) 对话框软崩溃。

  1. 为避免使用异步方法阻塞主线程,我们必须管理自己的线程才能正确调用这些 API。这甚至是更多的代码,而且很难正确处理。即使是专业工程师也面临着正确线程行为的挑战。

考虑异步!

Firebase API 对应用主线程的性能很敏感。这意味着任何需要处理磁盘或网络上的数据的 Firebase API 都是以异步方式实现的。这些函数将立即返回,因此您可以在主线程上调用它们而不必担心性能。您所要做的就是使用文档和示例中建立的模式实现回调。

这个问题有一个解决方案,你必须使用 Kotlin-Flow 进行同步调用,通过这个链接:https://developer.android.com/kotlin/flow#callback

【讨论】:

    【解决方案2】:

    我通过使用 Callback

    解决了这个问题

    我创建了 HospitalData.class 并从那里的 firebase 检索数据。通过使用 Callback 接口,我读取了 Fragment

    中的数据

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

    在我的 HomeFragment.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());
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2015-11-27
      • 2014-01-21
      • 1970-01-01
      • 2015-07-24
      • 1970-01-01
      • 1970-01-01
      • 2014-04-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多