ListenableFuture nutzen

Ein ListenableFuture stellt das Ergebnis einer asynchronen Berechnung dar: eine Berechnung, die möglicherweise noch kein Ergebnis erzielt hat. Es handelt sich um einen Typ von Future, mit dem Sie Callbacks registrieren können, die ausgeführt werden sollen, sobald die Berechnung abgeschlossen ist oder die Berechnung bereits abgeschlossen ist.

ListenableFuture ist nicht Teil des Android-Frameworks und wird stattdessen von Guava bereitgestellt. Weitere Informationen zur Implementierung dieser Klasse finden Sie in der Erläuterung zu ListenableFuture.

Viele vorhandene Jetpack-Bibliotheken wie CameraX oder Health Services haben asynchrone Methoden. Der Rückgabetyp ist dabei ListenableFuture, der den Status der Ausführung angibt. In einigen Fällen musst du eine Methode implementieren, die ein ListenableFuture zurückgibt, z. B. um die Anforderungen von TileService zu erfüllen.

Erforderliche Bibliotheken

Groovig

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")
}

Ergebnis von ListenableFuture abrufen

Callback hinzufügen

Verwenden Sie die Hilfsmethode Futures.addCallback(...), um Erfolgs- und Fehler-Callbacks an eine ListenableFuture anzuhängen.

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()
);

Aussetzen in Kotlin

Bei Verwendung von Kotlin ist es am einfachsten, auf das Ergebnis einer ListenableFuture zu warten, indem du await() verwendest.

import kotlinx.coroutines.guava.await

...

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

Interoperabilität mit RxJava

Ein RxJava-Single kann aus einer ListenableFuture erstellt werden. Dazu werden Callbacks in einem SingleEmitter registriert.

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 wird erstellt

Eine unmittelbare Zukunft schaffen

Wenn Ihre API nicht asynchron ist, Sie aber das Ergebnis eines abgeschlossenen Vorgangs in eine ListenableFuture verpacken müssen, können Sie eine ImmediateFuture erstellen. Dazu kann die Factory-Methode Futures.immediateFuture(...) verwendet werden.

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

Koroutine verwenden

In Kotlin kann ein future{ ... } verwendet werden, um das Ergebnis einer Anhaltenfunktion in eine ListenableFuture umzuwandeln.

import kotlinx.coroutines.guava.future

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

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

Callback konvertieren

Verwenden Sie CallbackToFutureAdapter, um eine Callback-basierte API in eine API umzuwandeln, die ListenableFuture verwendet. Diese API wird vom Artefakt androidx.concurrent:concurrent-futures bereitgestellt.

Weitere Informationen finden Sie unter androidx.gleichzeitig.

Konvertierung von RxJava Single wird durchgeführt

Bei Verwendung von RxJava kann ein Single in einen SettableFuture konvertiert werden, der ListenableFuture implementiert.

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;
}