Firebase Android: How To Read From Different References Sequentially
Solution 1:
TL;DR
Just like Parse did with Bolts, Google also provided a task framework that implement JavaScript promises. So, instead of nesting listeners, you can create a sequence of tasks.
The result will be sent to addOnSuccessListener
if all tasks execute successfully.
If any of them fail during the use case execution, the sequence will be aborted and the exception is passed to addOnFailureListener
.
publicTask<Course> execute() {
returnTasks.<Void>forResult(null)
.then(newGetUser())
.then(newGetCourse());
}
publicvoidupdateInBackground() {
Tasks.<Void>forResult(null)
.then(newGetUser())
.then(newGetCourse())
.addOnSuccessListener(this)
.addOnFailureListener(this);
}
@OverridepublicvoidonFailure(@NonNull Exception error) {
Log.e(TAG, error.getMessage());
}
@OverridepublicvoidonSuccess(Customer customer) {
// Do something with the result
}
Description
Suppose you wish to download two object of type User
and Course
from Firebase.
You need to create the first task of your sequence using the Tasks API. Your options are:
- Create a successful task using
Tasks.forResult
- Create a
TaskCompletionSource
, set the result or exception values, then return a task. - Create a task from a
callable
.
I prefer the first option mostly due code legibility. If you you need run the tasks in your own executor, you should use the first or second option.
Now let's create two Continuation
tasks two download each one:
classGetUserimplementsContinuation<Void, Task<User>> {
@OverridepublicTask<User> then(Task<Void> task) {
final TaskCompletionSource<User> tcs = newTaskCompletionSource();
ref1.addListenerForSingleValueEvent(newValueEventListener() {
@OverridepublicvoidonCancelled(DatabaseError error) {
tcs.setException(error.toException());
}
@OverridepublicvoidonDataChange(DataSnapshot snapshot) {
tcs.setResult(snapshot.getValue(User.class));
}
});
return tcs.getTask();
}
}
and
classGetCourseimplementsContinuation<User, Task<Course>> {
@Overridepublic Task<Course> then(Task<User> task) {
finalUserresult= task.getResult();
final TaskCompletionSource<Course> tcs = newTaskCompletionSource();
ref2.addListenerForSingleValueEvent(newValueEventListener() {
@OverridepublicvoidonCancelled(DatabaseError error) {
tcs.setException(error.toException());
}
@OverridepublicvoidonDataChange(DataSnapshot snapshot) {
tcs.setResult(snapshot.getValue(Course.class));
}
});
return tcs.getTask();
}
}
According the documentation, call getResult()
and allow the RuntimeExecutionException to propagate to propagate failure from the completed Task.
The RuntimeExecutionException
will be unwrapped such that the Task returned by continueWith(Continuation)
or continueWithTask(Continuation)
fails with the original exception.
Solution 2:
According to the Firebase blog: https://firebase.googleblog.com/2016/09/become-a-firebase-taskmaster-part-3_29.html
We could implement a chain of asynchronous task as the following:
public Task<ClassReturnedByTask3> wrapAllTask() {
return Tasks.call(new Task1())
.continueWithTask(new Task2())
.continueWithTask(new Task3());
}
Where Task1 through Task3 are defined as:
staticclassTask1implementsCallable<ClassReturnedByTask1> {
@Overridepublic ClassReturnedByTask1 call()throws Exception {
ClassReturnedByTask1result=newClassReturnedByTask1();
return result;
}
}
staticclassTask2implementsContinuation<ClassReturnedByTask1, Task<ClassReturnedByTask2>> {
@Overridepublic Task<ClassReturnedByTask2> then(Task<ClassReturnedByTask1> task) {
final TaskCompletionSource<ClassReturnedByTask2> tcs = newTaskCompletionSource();
ClassReturnedByTask1resultFromTask1= task.getResult();
ClassReturnedByTask2result=newClassReturnedByTask2();
tcs.setResult(result);
return tcs.getTask();
}
}
staticclassTask3implementsContinuation<ClassReturnedByTask2, Task<ClassReturnedByTask3>> {
@Overridepublic Task<ClassReturnedByTask3> then(Task<ClassReturnedByTask2> task) {
final TaskCompletionSource<ClassReturnedByTask3> tcs = newTaskCompletionSource();
ClassReturnedByTask2resultFromTask2= task.getResult();
ClassReturnedByTask3result=newClassReturnedByTask3();
tcs.setResult(result);
return tcs.getTask();
}
}
To execute the wrapAllTask() function, you can run:
Task<ClassReturnedByTask3> tasks = wrapAllTask();
tasks.addOnSuccessListener(newOnSuccessListener<ClassReturnedByTask3>() {
@OverridepublicvoidonSuccess(ClassReturnedByTask3 resultFromTask3) {
// do something
}
});
Post a Comment for "Firebase Android: How To Read From Different References Sequentially"