A partir da versão 9.0.0 do Google Play Services, é possível usar uma API Task
e uma
Número de métodos que retornam Task
ou as subclasses dela. Task
é uma API que
representa chamadas de método assíncronas, semelhante a PendingResult
nas
do Google Play Services.
Como processar resultados de tarefas
Um método comum que retorna um Task
é FirebaseAuth.signInAnonymously()
.
Ela retorna um Task<AuthResult>
, o que significa que a tarefa retornará
um objeto AuthResult
quando ele é bem-sucedido:
Task<AuthResult> task = FirebaseAuth.getInstance().signInAnonymously();
Para receber uma notificação quando a tarefa for concluída, anexe um OnSuccessListener
:
task.addOnSuccessListener(new OnSuccessListener<AuthResult>() { @Override public void onSuccess(AuthResult authResult) { // Task completed successfully // ... } });
Para receber uma notificação quando a tarefa falhar, anexe um OnFailureListener
:
task.addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
Para lidar com sucessos e falhas no mesmo listener, anexe um
OnCompleteListener
:
task.addOnCompleteListener(new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { if (task.isSuccessful()) { // Task completed successfully AuthResult result = task.getResult(); } else { // Task failed with an exception Exception exception = task.getException(); } } });
Linha de execução
Os listeners anexados a uma linha de execução são executados na linha de execução principal (interface) do aplicativo
por padrão. Ao anexar um listener, você também pode especificar um Executor
que seja
usada para programar listeners.
// Create a new ThreadPoolExecutor with 2 threads for each processor on the // device and a 60 second keep-alive time. int numCores = Runtime.getRuntime().availableProcessors(); ThreadPoolExecutor executor = new ThreadPoolExecutor(numCores * 2, numCores *2, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); task.addOnCompleteListener(executor, new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { // ... } });
Listeners com escopo de atividade
Se você estiver ouvindo resultados de tarefas em uma Activity
, recomendamos adicionar
listeners com escopo de atividade à tarefa. Esses listeners são removidos durante
o método onStop
da sua atividade para que os listeners não sejam chamados;
quando a atividade não estiver mais visível.
Activity activity = MainActivity.this; task.addOnCompleteListener(activity, new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { // ... } });
Encadeamento
Se você usa várias APIs que retornam Task
, é possível encadeá-las
usando uma continuação. Isso ajuda a evitar callbacks profundamente aninhados e consolida
tratamento de erros para cadeias de tarefas.
Por exemplo, o método doSomething
retorna um Task<String>
, mas exige
um AuthResult
, que vamos receber de forma assíncrona de uma tarefa:
public Task<String> doSomething(AuthResult authResult) { // ... }
Usando o método Task.continueWithTask
, podemos encadear estas duas tarefas:
Task<AuthResult> signInTask = FirebaseAuth.getInstance().signInAnonymously(); signInTask.continueWithTask(new Continuation<AuthResult, Task<String>>() { @Override public Task<String> then(@NonNull Task<AuthResult> task) throws Exception { // Take the result from the first task and start the second one AuthResult result = task.getResult(); return doSomething(result); } }).addOnSuccessListener(new OnSuccessListener<String>() { @Override public void onSuccess(String s) { // Chain of tasks completed successfully, got result from last task. // ... } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // One of the tasks in the chain failed with an exception. // ... } });
Bloqueio
Caso seu programa já esteja sendo executado em uma linha de execução em segundo plano, é possível bloquear uma tarefa para obter o resultado de forma síncrona e evitar callbacks:
try { // Block on a task and get the result synchronously. This is generally done // when executing a task inside a separately managed background thread. Doing this // on the main (UI) thread can cause your application to become unresponsive. AuthResult authResult = Tasks.await(task); } catch (ExecutionException e) { // The Task failed, this is the same exception you'd get in a non-blocking // failure handler. // ... } catch (InterruptedException e) { // An interrupt occurred while waiting for the task to complete. // ... }
Também é possível especificar um tempo limite ao bloquear uma tarefa para que seu aplicativo não trava:
try { // Block on the task for a maximum of 500 milliseconds, otherwise time out. AuthResult authResult = Tasks.await(task, 500, TimeUnit.MILLISECONDS); } catch (ExecutionException e) { // ... } catch (InterruptedException e) { // ... } catch (TimeoutException e) { // Task timed out before it could complete. // ... }
Interoperabilidade
Um Task
se alinha conceitualmente a várias abordagens conhecidas do Android para gerenciar
código assíncrono, e um Task
pode ser convertido diretamente em outro
primitivos, incluindo as corrotinas ListenableFuture
e Kotlin, que são
recomendado pelo AndroidX.
Confira um exemplo usando um Task
:
// ... simpleTask.addOnCompleteListener(this) { completedTask -> textView.text = completedTask.result }
Corrotina do Kotlin
Uso
Adicione a dependência abaixo ao projeto e use o código abaixo para converter
de um Task
.
Gradle (nível do módulo build.gradle
, geralmente app/build.gradle
)
// Source: https://github.com/Kotlin/kotlinx.coroutines/tree/master/integration/kotlinx-coroutines-play-services implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.7.3'
Snippet
import kotlinx.coroutines.tasks.await // ... textView.text = simpleTask.await() }
Guava ListenableFuture
Adicione a dependência abaixo ao projeto e use o código abaixo para converter
de um Task
.
Gradle (nível do módulo build.gradle
, geralmente app/build.gradle
)
implementation "androidx.concurrent:concurrent-futures:1.2.0"
Snippet
import com.google.common.util.concurrent.ListenableFuture // ... /** Convert Task to ListenableFuture. */ fun <T> taskToListenableFuture(task: Task<T>): ListenableFuture<T> { return CallbackToFutureAdapter.getFuture { completer -> task.addOnCompleteListener { completedTask -> if (completedTask.isCanceled) { completer.setCancelled() } else if (completedTask.isSuccessful) { completer.set(completedTask.result) } else { val e = completedTask.exception if (e != null) { completer.setException(e) } else { throw IllegalStateException() } } } } } // ... this.listenableFuture = taskToListenableFuture(simpleTask) this.listenableFuture?.addListener( Runnable { textView.text = listenableFuture?.get() }, ContextCompat.getMainExecutor(this) )
RxJava2 observável
Adicione a dependência a seguir, além da biblioteca assíncrona relativa de
opção, para seu projeto e use o código abaixo para converter de um Task
.
Gradle (nível do módulo build.gradle
, geralmente app/build.gradle
)
// Source: https://github.com/ashdavies/rx-tasks implementation 'io.ashdavies.rx.rxtasks:rx-tasks:2.2.0'
Snippet
import io.ashdavies.rx.rxtasks.toSingle import java.util.concurrent.TimeUnit // ... simpleTask.toSingle(this).subscribe { result -> textView.text = result }