Tasks API

Task API 是在 Google Play 服务中处理异步操作的标准方式。它提供了一种强大且灵活的方式来管理异步调用,取代了旧的 PendingResult 模式。借助 Task,您可以链接多个调用、处理复杂流程,并编写清晰的成功和失败处理程序。

处理任务结果

Google Play 服务和 Firebase 中的许多 API 都会返回一个 Task 对象来表示异步操作。例如,FirebaseAuth.signInAnonymously() 会返回一个 Task<AuthResult>,表示登录操作的结果。Task<AuthResult> 表示当任务成功完成时,它将返回一个 AuthResult 对象。

您可以通过附加监听器来处理 Task 的结果,这些监听器会响应成功完成、失败或两者兼而有之:

Task<AuthResult> task = FirebaseAuth.getInstance().signInAnonymously();

如需处理成功完成的任务,请附加 OnSuccessListener

task.addOnSuccessListener(new OnSuccessListener<AuthResult>() {     @Override     public void onSuccess(AuthResult authResult) {         // Task completed successfully         // ...     } });

如需处理失败的任务,请附加 OnFailureListener

task.addOnFailureListener(new OnFailureListener() {     @Override     public void onFailure(@NonNull Exception e) {         // Task failed with an exception         // ...     } });

如需在同一监听器中同时处理成功和失败情况,请附加 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();         }     } });

管理线程

默认情况下,附加到 Task 的监听器在应用主 (UI) 线程上运行。这意味着,您应避免在监听器中执行长时间运行的操作。如果您需要执行长时间运行的操作,可以指定用于在后台线程上调度监听器的 Executor

// 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) {         // ...     } });

使用 activity 范围的监听器

当您需要在 Activity 中处理任务结果时,请务必管理监听器的生命周期,以防止在 Activity 不再可见时调用它们。为此,您可以使用 activity 范围的监听器。当调用 ActivityonStop 方法时,这些监听器会自动移除,这样在 Activity 停止后,它们就不会再执行。

Activity activity = MainActivity.this; task.addOnCompleteListener(activity, new OnCompleteListener<AuthResult>() {     @Override     public void onComplete(@NonNull Task<AuthResult> task) {         // ...     } });

链接任务

如果您在一项复杂函数中使用一组返回 Task 对象的 API,可以使用延续将它们链接在一起。这有助于避免深度嵌套的回调,并整合多个链式任务的错误处理。

例如,假设您有一个返回 Task<String> 的方法 doSomething,但它需要 AuthResult 作为参数。您可以从另一个 Task 异步获取此 AuthResult

public Task<String> doSomething(AuthResult authResult) {     // ... }

使用 Task.continueWithTask 方法,您可以将这两项任务串联起来:

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.         // ...     } });

屏蔽任务

如果您的程序已在后台线程中执行,则可以阻塞当前线程并等待任务完成,而不是使用回调:

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.     // ... }

您还可以在阻塞任务时指定超时时间,以防止应用因任务完成时间过长而无限期卡住:

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.     // ... }

互操作性

Task 旨在与其他常见的 Android 异步编程模式搭配使用。它可以转换为其他原语(如 ListenableFuture)和 Kotlin 协程(AndroidX 推荐使用),从而让您能够使用最适合您需求的方法。

下面是一个使用 Task 的示例:

// ... simpleTask.addOnCompleteListener(this) {   completedTask -> textView.text = completedTask.result }

Kotlin 协程

如需将 Kotlin 协程与 Task 一起使用,请将以下依赖项添加到您的项目中,然后使用相应代码段从 Task 进行转换。

Gradle(模块级 build.gradle,通常为 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

如需将 Guava ListenableFutureTask 搭配使用,请将以下依赖项添加到您的项目中,然后使用相应代码段从 Task 进行转换。

Gradle(模块级 build.gradle,通常为 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 Observable

除了选择的相关异步库之外,还应将以下依赖项添加到您的项目中,然后使用代码段从 Task 进行转换。

Gradle(模块级 build.gradle,通常为 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 }

后续步骤