À partir de la version 9.0.0 des services Google Play, vous pouvez utiliser une API Task
et un certain nombre de méthodes qui renvoient Task
ou ses sous-classes. Task
est une API qui représente les appels de méthode asynchrones, semblable à PendingResult
dans les versions précédentes des services Google Play.
Gérer les résultats des tâches
FirebaseAuth.signInAnonymously()
est une méthode courante qui renvoie un Task
.
Elle renvoie Task<AuthResult>
, ce qui signifie que la tâche renvoie un objet AuthResult
en cas de réussite:
Task<AuthResult> task = FirebaseAuth.getInstance().signInAnonymously();
Pour recevoir une notification lorsque la tâche aboutit, joignez OnSuccessListener
:
task.addOnSuccessListener(new OnSuccessListener<AuthResult>() { @Override public void onSuccess(AuthResult authResult) { // Task completed successfully // ... } });
Pour être averti en cas d'échec de la tâche, joignez OnFailureListener
:
task.addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
Pour gérer la réussite et l'échec dans le même écouteur, associez un 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(); } } });
Exécution de threads
Les écouteurs associés à un thread sont exécutés par défaut sur le thread principal de l'application (UI). Lorsque vous associez un écouteur, vous pouvez également spécifier un Executor
utilisé pour planifier des écouteurs.
// 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) { // ... } });
Écouteurs de portée activité
Si vous écoutez les résultats d'une tâche dans une Activity
, vous pouvez ajouter des écouteurs de portée activité à la tâche. Ces écouteurs sont supprimés lors de la méthode onStop
de votre activité, afin qu'ils ne soient pas appelés lorsque l'activité n'est plus visible.
Activity activity = MainActivity.this; task.addOnCompleteListener(activity, new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { // ... } });
Chaîne
Si vous utilisez plusieurs API qui renvoient Task
, vous pouvez les enchaîner à l'aide d'une continuation. Cela permet d'éviter les rappels profondément imbriqués et de consolider la gestion des erreurs pour les chaînes de tâches.
Par exemple, la méthode doSomething
renvoie un objet Task<String>
, mais nécessite un élément AuthResult
, que nous obtiendrons de manière asynchrone à partir d'une tâche:
public Task<String> doSomething(AuthResult authResult) { // ... }
La méthode Task.continueWithTask
nous permet d'enchaîner ces deux tâches:
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. // ... } });
Vidéo bloquée
Si votre programme s'exécute déjà dans un thread en arrière-plan, vous pouvez bloquer une tâche pour obtenir le résultat de manière synchrone et éviter les rappels:
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. // ... }
Vous pouvez également spécifier un délai avant expiration lors du blocage d'une tâche afin que votre application ne se bloque pas:
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. // ... }
Interopérabilité
Un Task
s'aligne conceptuellement sur plusieurs approches Android courantes de gestion du code asynchrone, et un Task
peut être facilement converti en d'autres primitives, y compris les coroutines ListenableFuture
et Kotlin, recommandées par AndroidX.
Voici un exemple utilisant un Task
:
// ... simpleTask.addOnCompleteListener(this) { completedTask -> textView.text = completedTask.result }
Coroutine Kotlin
Utilisation
Ajoutez la dépendance suivante à votre projet et utilisez le code ci-dessous pour effectuer la conversion à partir d'un Task
.
Gradle (build.gradle
au niveau du module, généralement 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.4.1'
Snippet
import kotlinx.coroutines.tasks.await // ... textView.text = simpleTask.await() }
Guava ListenableFuture
Ajoutez la dépendance suivante à votre projet et utilisez le code ci-dessous pour effectuer la conversion à partir d'un Task
.
Gradle (build.gradle
au niveau du module, généralement app/build.gradle
)
implementation "androidx.concurrent:concurrent-futures:1.1.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 Observable
Ajoutez la dépendance suivante à votre projet, en plus de la bibliothèque asynchrone relative de votre choix, et utilisez le code ci-dessous pour effectuer la conversion à partir d'un Task
.
Gradle (build.gradle
au niveau du module, généralement 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 }