使用 ListenableFuture

ListenableFuture 代表非同步運算的結果,亦即不一定會完成產生結果的運算。這是 Future 的類型,可讓您註冊在計算完成或計算已完成時,要執行的回呼。

ListenableFuture 並非 Android 架構的一部分,而是由 Guava 提供。如要進一步瞭解此類別的實作,請參閱 ListenableFuture 說明

許多現有的 Jetpack 程式庫 (例如 CameraX健康照護服務) 都有非同步方法,其中傳回類型為 ListenableFuture,代表執行作業的狀態。在某些情況下,您可能需要實作傳回 ListenableFuture 的方法 (例如滿足 TileService 的要求)。

必要程式庫

Groovy

dependencies {
    implementation "com.google.guava:guava:31.0.1-android"

    // To use CallbackToFutureAdapter
    implementation "androidx.concurrent:concurrent-futures:1.1.0"

    // Kotlin
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.6.0"
}

Kotlin

dependencies {
    implementation("com.google.guava:guava:31.0.1-android")

    // To use CallbackToFutureAdapter
    implementation("androidx.concurrent:concurrent-futures:1.1.0")

    // Kotlin
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.6.0")
}

取得 ListenableFuture 的結果

新增回呼

使用 Futures.addCallback(...) 輔助方法,將成功和失敗回呼附加至 ListenableFuture

Kotlin

val future: ListenableFuture<QueryResult> = ...
Futures.addCallback(
    future,
    object : FutureCallback<QueryResult> {
        override fun onSuccess(result: QueryResult) {
            // handle success
        }

        override fun onFailure(t: Throwable) {
            // handle failure
        }
    },
    // causes the callbacks to be executed on the main (UI) thread
    context.mainExecutor
)

Java

ListenableFuture<QueryResult> future = ...
Futures.addCallback(
    future,
    new FutureCallback<QueryResult>() {
        public void onSuccess(QueryResult result) {
            // handle success
        }

        public void onFailure(@NonNull Throwable thrown) {
            // handle failure
        }
    },
    // causes the callbacks to be executed on the main (UI) thread
    context.getMainExecutor()
);

在 Kotlin 中暫停

使用 Kotlin 時,如要等待 ListenableFuture 的結果,最簡單的方法就是使用 await()

import kotlinx.coroutines.guava.await

...

val future: ListenableFuture<QueryResult> = ...
val queryResult = future.await() // suspends awaiting success

與 RxJava 的互通性

透過在 SingleEmitter 中註冊回呼,即可透過 ListenableFuture 建立 RxJava Single

Kotlin

val future: ListenableFuture<QueryResult> = ...
val single = Single.create<QueryResult> {
    Futures.addCallback(future, object : FutureCallback<QueryResult> {
        override fun onSuccess(result: QueryResult) {
            it.onSuccess(result)
        }

        override fun onFailure(t: Throwable) {
            it.onError(t)
        }
    }, executor)
}

Java

ListenableFuture<QueryResult> future = ...
Single<QueryResult> single = Single.create(
        e -> Futures.addCallback(future, new FutureCallback<QueryResult>() {
            @Override
            public void onSuccess(QueryResult result) {
                e.onSuccess(result);
            }

            @Override
            public void onFailure(@NonNull Throwable thrown) {
                e.onError(thrown);
            }
        }, executor));

建立 ListenableFuture

創造立竿見影的未來

如果您的 API 並非非同步,但您需要將已完成作業的結果納入 ListenableFuture,則可建立 ImmediateFuture。您可以使用 Futures.immediateFuture(...) 工廠方法進行這項操作。

Kotlin

fun getResult(): ListenableFuture<QueryResult> {
    try {
        val queryResult = getQueryResult()
        return Futures.immediateFuture(queryResult)
    } catch (e: Exception) {
        return Futures.immediateFailedFuture(e)
    }
}

Java

public ListenableFuture<QueryResult> getResult() {
    try {
        QueryResult queryResult = getQueryResult();
        return Futures.immediateFuture(queryResult);
    } catch (Exception e) {
        return Futures.immediateFailedFuture(e);
    }
}

使用協同程式

在 Kotlin 中,future{ ... } 可用來將暫停函式的結果轉換為 ListenableFuture

import kotlinx.coroutines.guava.future

suspend fun getResultAsync(): QueryResult { ... }

fun getResultFuture(): ListenableFuture<QueryResult> {
    return coroutineScope.future{
        getResultAsync()
    }
}

轉換回呼

如要將回呼式 API 轉換為使用 ListenableFuture 的 API,請使用 CallbackToFutureAdapter。這個 API 是由 androidx.concurrent:concurrent-futures 構件提供。

詳情請參閱 androidx.concurrent

從 RxJava Single 轉換

使用 RxJava 時,可將 Single 轉換為實作 ListenableFutureSettableFuture

Kotlin

fun getResult(): ListenableFuture<QueryResult> {
    val single: Single<QueryResult> = ...

    val future = SettableFuture.create<QueryResult>()
    single.subscribe(future::set, future::setException)
    return future
}

Java

public ListenableFuture<QueryResult> getResult() {
    Single<QueryResult> single = ...

    SettableFuture<QueryResult> future = SettableFuture.create();
    single.subscribe(future::set, future::setException);
    return future;
}