Firebase Android:如何顺序读取不同的引用

Esc*_*ar5 1 android firebase firebase-realtime-database

在我的一项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
             }
         }); 
    }
}); 
Run Code Online (Sandbox Code Playgroud)

当您顺序需要它们时,是否有更好的方法来执行此查询?

JP *_*ura 5

TL; DR

就像ParseBolts所做的一样,Google还提供了一个实现JavaScript承诺的任务框架。因此,您可以创建一系列任务,而不是嵌套侦听器。

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
}
Run Code Online (Sandbox Code Playgroud)

描述

假设您希望从Firebase 下载类型为User和的两个对象Course

您需要使用Tasks API创建序列中的第一个任务。您的选择是:

我更喜欢第一种选择,主要是因为代码易读。如果需要在自己的执行程序中运行任务,则应使用第一个或第二个选项。

现在让我们创建两个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();
    }

}
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)

根据文档,调用getResult()并允许RuntimeExecutionException传播以传播已完成Task的失败。

RuntimeExecutionException会解开使得任务返回通过continueWith(Continuation)continueWithTask(Continuation)失败,原始异常。