当前遇到一个问题,我正在从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;
}
由于数据是异步加载的,因此您不能返回数据,您应该在retrieveActivityData方法中传递callback(Interface),并使用接口的回调来加载数据,请检查下面的代码
@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);
}
Option-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
这样
您可以在Firebase操作完成后使用回调函数获取结果。retrieveActivityData(userInput).observe(this, new Observer<List<ActivityModel>>() { @Override public void onChanged(List<ActivityModel> activityModels) { //you can use list here } });
Option-2:
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
}
});
您猜对了!该查询是异步的,因此retrieveActivityData()
不应返回List<ActivityModel>
,否则它将始终为null。一旦将List
编译到onComplete()
中,您就必须使用事件总线来触发事件,或者使用LiveData
进行观察。