在我的一项Android活动中,我需要对Firebase执行多个查询,以便最终向用户显示内容。
总之,我需要检查用户参考以检查他当前所处的课程步骤,然后我需要阅读课程的内容以加载它
我目前正在做的是我有两个嵌套的侦听器:
ref1.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
ref2.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
//do the work
}
});
}
});
当您需要顺序查询时,是否有更好的方法来执行此查询?
答案 0 :(得分:5)
就像Parse对Bolts所做的那样,Google还提供了一个实施JavaScript promises的任务框架。因此,您可以创建一系列任务,而不是嵌套侦听器。
如果所有任务都成功执行,结果将发送到addOnSuccessListener
。
如果在用例执行期间其中任何一个失败,则序列将被中止,异常将传递给addOnFailureListener
。
public Task<Course> execute() {
return Tasks.<Void>forResult(null)
.then(new GetUser())
.then(new GetCourse());
}
public void updateInBackground() {
Tasks.<Void>forResult(null)
.then(new GetUser())
.then(new GetCourse())
.addOnSuccessListener(this)
.addOnFailureListener(this);
}
@Override
public void onFailure(@NonNull Exception error) {
Log.e(TAG, error.getMessage());
}
@Override
public void onSuccess(Customer customer) {
// Do something with the result
}
假设您希望从Firebase下载两个User
和Course
类型的对象。
您需要使用Tasks API创建序列的第一个任务。您的选择是:
Tasks.forResult
TaskCompletionSource
,设置结果或异常值,然后返回任务。callable
创建任务。我更喜欢第一种选择,主要是因为代码易读性。如果您需要在自己的执行程序中运行任务,则应使用第一个或第二个选项。
现在让我们创建两个Continuation
任务,每个任务下载两个:
class GetUser implements Continuation<Void, Task<User>> {
@Override
public Task<User> then(Task<Void> task) {
final TaskCompletionSource<User> tcs = new TaskCompletionSource();
ref1.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onCancelled(DatabaseError error) {
tcs.setException(error.toException());
}
@Override
public void onDataChange(DataSnapshot snapshot) {
tcs.setResult(snapshot.getValue(User.class));
}
});
return tcs.getTask();
}
}
和
class GetCourse implements Continuation<User, Task<Course>> {
@Override
public Task<Course> then(Task<User> task) {
final User result = task.getResult();
final TaskCompletionSource<Course> tcs = new TaskCompletionSource();
ref2.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onCancelled(DatabaseError error) {
tcs.setException(error.toException());
}
@Override
public void onDataChange(DataSnapshot snapshot) {
tcs.setResult(snapshot.getValue(Course.class));
}
});
return tcs.getTask();
}
}
根据the documentation,调用getResult()
并允许RuntimeExecutionException传播以从已完成的Task传播失败。
RuntimeExecutionException
将被解包,以便continueWith(Continuation)
或continueWithTask(Continuation)
返回的任务失败并显示原始异常。
答案 1 :(得分:0)
根据Firebase博客:https://firebase.googleblog.com/2016/09/become-a-firebase-taskmaster-part-3_29.html
我们可以实现一系列异步任务,如下所示:
public Task<ClassReturnedByTask3> wrapAllTask() {
return Tasks.call(new Task1())
.continueWithTask(new Task2())
.continueWithTask(new Task3());
}
其中Task1至Task3定义为:
static class Task1 implements Callable<ClassReturnedByTask1> {
@Override
public ClassReturnedByTask1 call() throws Exception {
ClassReturnedByTask1 result = new ClassReturnedByTask1();
return result;
}
}
static class Task2 implements Continuation<ClassReturnedByTask1, Task<ClassReturnedByTask2>> {
@Override
public Task<ClassReturnedByTask2> then(Task<ClassReturnedByTask1> task) {
final TaskCompletionSource<ClassReturnedByTask2> tcs = new TaskCompletionSource();
ClassReturnedByTask1 resultFromTask1 = task.getResult();
ClassReturnedByTask2 result = new ClassReturnedByTask2();
tcs.setResult(result);
return tcs.getTask();
}
}
static class Task3 implements Continuation<ClassReturnedByTask2, Task<ClassReturnedByTask3>> {
@Override
public Task<ClassReturnedByTask3> then(Task<ClassReturnedByTask2> task) {
final TaskCompletionSource<ClassReturnedByTask3> tcs = new TaskCompletionSource();
ClassReturnedByTask2 resultFromTask2 = task.getResult();
ClassReturnedByTask3 result = new ClassReturnedByTask3();
tcs.setResult(result);
return tcs.getTask();
}
}
要执行wrapAllTask()函数,可以运行:
Task<ClassReturnedByTask3> tasks = wrapAllTask();
tasks.addOnSuccessListener(new OnSuccessListener<ClassReturnedByTask3>() {
@Override
public void onSuccess(ClassReturnedByTask3 resultFromTask3) {
// do something
}
});