【问题标题】:fetching data from firebase and returning it to the main thread [duplicate]从firebase获取数据并将其返回到主线程[重复]
【发布时间】:2020-05-28 09:25:39
【问题描述】:

目前遇到我从 firebase 获取数据的问题。我知道这是因为 Firebase 是异步的,所以当我进行 firebase 调用时,它会在自己的线程上执行,并且调用它的当前线程会继续执行。我正在使用来自 firebase 的数据填充对象列表,然后返回该对象列表。问题是,列表总是返回 null,因为 firebase 代码的执行没有及时完成。

我创建了一些从 SQLite db 中获取的异步代码,效果很好,但这种方法似乎不适用于 firebase(我相信这是因为 firebases API 是异步的)这是我从 firebase 返回对象列表的方法.

/** Method to get activity data from firebase.
 * @param userInput the user query to select the data
 * @return a list of activity models based on the query
 * */
public List<ActivityModel> retrieveActivityData(String userInput) {
    Log.d(TAG, "retrieveActivityData: starts");
    List<ActivityModel> models = new ArrayList<ActivityModel>();
    // execute the query in firebase
    CollectionReference activfitCollection = db.collection("activity");
    activfitCollection.orderBy("isoTimestamp")
            .startAt(userInput)
            .endAt(DateHelper.getDayEndingDate(userInput))
            .get()
            .addOnCompleteListener(task -> {
                if (task.isSuccessful()) {
                    Log.d(TAG, "onComplete: Getting data successful!");
                    // check to see if it exists
                    if (!task.getResult().isEmpty()) {
                        for (DocumentSnapshot documentSnapshot : task.getResult().getDocuments()) {
                            Log.d(TAG, "retrieveActivityData: document = " + documentSnapshot.getId());
                            // cast the document to the activity model
                            Log.d(TAG, "retrieveActivityData: document data " + documentSnapshot.getData());
                            ActivityModel model = mapToActivityModel(documentSnapshot);
                            models.add(model);
                            Log.d(TAG, "retrieveActivityData: array size" + models.size());
                        }
                    }

                } else {
                    Log.e(TAG, "onComplete: Error getting documents: ", task.getException());
                }
            });
    Log.d(TAG, "retrieveActivityData: array size outside " + models.size());
    return models;
}

【问题讨论】:

    标签: java android firebase google-cloud-firestore


    【解决方案1】:

    选项 - 1:您可以使用LiveData 来实现此目的。操作完成后将值发布到 LiveData 并观察您的活动或片段中的内容

    MutableLiveData<List<ActivityModel>> listMutableLiveData = new MutableLiveData<>();
    
    public MutableLiveData<List<ActivityModel>> retrieveActivityData(String userInput) {
    
        List<ActivityModel> models = new ArrayList<ActivityModel>();
    
        ....
            if (task.isSuccessful()) {
                for (DocumentSnapshot documentSnapshot : task.getResult().getDocuments()) {
                    ....
                    models.add(model);
                }
    
                //Post value to live data from here
                listMutableLiveData.postValue(models);
            }
    
        ....
    
        return listMutableLiveData;
    }
    

    然后像这样observe

    retrieveActivityData(userInput).observe(this, new Observer<List<ActivityModel>>() {
        @Override
        public void onChanged(List<ActivityModel> activityModels) {
            //you can use list here
        }
    });
    

    选项 - 2:您可以在firebase操作完成时使用回调函数获取结果。

    • 为回调创建interface
    interface FirebaseResultListener {
        void onComplete(List<ActivityModel> activityModels);
    }
    
    • 配置您的 retrieveActivityData 以处理此回调
    public void retrieveActivityData(String userInput, FirebaseResultListener callback) {
    
        List<ActivityModel> models = new ArrayList<ActivityModel>();
    
        ....
        if (task.isSuccessful()) {
            for (DocumentSnapshot documentSnapshot : task.getResult().getDocuments()) {
                    ....
                models.add(model);
            }
    
            //Invoke callback with result from here
            callback.onComplete(models);
        }
    
        ....
    }
    
    • 在您的活动或片段中实现此接口
    retrieveActivityData(userInput, new FirebaseResultListener() {
        @Override
        public void onComplete(List<ActivityModel> activityModels) {
            //you can use list here
        }
    });
    

    【讨论】:

    • 太棒了,感谢您的反馈和回复。最初,我使用 AsyncTask 在单独的线程上执行此方法。我创建了自己的自定义回调方法,该方法应该从 firebase 返回对象列表。但我会检查这些解决方案,看看哪些最适合!
    • 问题,如果我不想使用片段/活动中的数据怎么办?例如,我不会使用从 firebase 获取的数据来更新 UI。我只想将从firebase获取的数据存储在内存中并确保它等待该数据加载到内存中,我应该让该特定类实现回调接口还是必须是实现回调接口的活动或片段?
    • 您可以从任何地方使用回调方法。如果这对您有帮助,请接受答案
    • @FanonX,请接受未来用户的答案,以便他们发现它有帮助
    【解决方案2】:

    由于数据是异步加载的,无法返回数据,需要在retrieveActivityData方法中传入callback(Interface),并使用interface的callback来加载数据,查看以下代码

      @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main2);
    
            MyFirebaseCallback myFirebaseCallback = new MyFirebaseCallback() {
                @Override
                public void dataLoaded(List<ActivityModel> activityModels) {
                    //set the data in recycler view
                }
            };
    
            retrieveActivityData("myInput",myFirebaseCallback);
        }
    
        public void retrieveActivityData(String userInput, final MyFirebaseCallback callback) {
            Log.d(TAG, "retrieveActivityData: starts");
            // execute the query in firebase
            CollectionReference activfitCollection = db.collection("activity");
            activfitCollection.orderBy("isoTimestamp")
                    .startAt(userInput)
                    .endAt(DateHelper.getDayEndingDate(userInput))
                    .get()
                    .addOnCompleteListener(task -> {
                        if (task.isSuccessful()) {
                            List<ActivityModel> models = new ArrayList<ActivityModel>();
                            Log.d(TAG, "onComplete: Getting data successful!");
                            // check to see if it exists
                            if (!task.getResult().isEmpty()) {
                                for (DocumentSnapshot documentSnapshot : task.getResult().getDocuments()) {
                                    Log.d(TAG, "retrieveActivityData: document = " + documentSnapshot.getId());
                                    // cast the document to the activity model
                                    Log.d(TAG, "retrieveActivityData: document data " + documentSnapshot.getData());
                                    ActivityModel model = mapToActivityModel(documentSnapshot);
                                    models.add(model);
                                    Log.d(TAG, "retrieveActivityData: array size" + models.size());
                                }
                            }
    
                            callback.dataLoaded(models);
    
                        } else {
                            Log.e(TAG, "onComplete: Error getting documents: ", task.getException());
                        }
                    });
            Log.d(TAG, "retrieveActivityData: array size outside " + models.size());
        }
    
        interface MyFirebaseCallback{
            void dataLoaded(List<ActivityModel> activityModels);
        }
    

    【讨论】:

    • 太棒了,非常感谢您的反馈,就我而言,最好的方法似乎是回调方法。
    【解决方案3】:

    你猜对了!该查询是异步的,因此retrieveActivityData() 不应返回List&lt;ActivityModel&gt;,否则它将始终为空。一旦您的ListonComplete() 中编译,您就必须使用事件总线来触发事件,或者使用LiveData 并观察它。

    LiveData

    ViewModel

    EventBus

    【讨论】:

      猜你喜欢
      • 2021-06-21
      • 1970-01-01
      • 2021-06-21
      • 1970-01-01
      • 2017-04-21
      • 2020-08-19
      • 1970-01-01
      • 1970-01-01
      • 2012-04-08
      相关资源
      最近更新 更多