Utiliser un ListenableFuture

Un objet ListenableFuture représente le résultat d'un calcul asynchrone: une des calculs qui peuvent ou non avoir fini de produire un résultat encore. Il s'agit d'un Type de Future qui vous permet d'enregistrer des rappels à exécuter une fois le calcul effectué ou si le calcul est déjà terminé, immédiatement.

ListenableFuture ne fait pas partie du framework Android et est fourni à la place de Guava. Pour en savoir plus sur la implémentation de cette classe, consultez la section ListenableFuture expliqué.

De nombreuses bibliothèques Jetpack existantes, telles que CameraX ou Services Santé utilisent des méthodes asynchrones où le type renvoyé est ListenableFuture, qui représente l'état l'exécution. Dans certains cas, vous devrez peut-être implémenter une méthode qui renvoie un ListenableFuture, par exemple pour répondre aux exigences de TileService.

<ph type="x-smartling-placeholder">

Bibliothèques requises

Groovy

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

    // To use CallbackToFutureAdapter
    implementation "androidx.concurrent:concurrent-futures:1.2.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.2.0")

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

Obtenir le résultat d'une ListenableFuture

Ajouter un rappel

Utilisez le Futures.addCallback(...) d'assistance permettant d'associer des rappels de réussite et d'échec à un 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()
);

Suspension en Kotlin

Lorsque vous utilisez Kotlin, le moyen le plus simple d'attendre le résultat d'un objet ListenableFuture consiste à utiliser await().

import kotlinx.coroutines.guava.await

...

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

Interopérabilité avec RxJava

Un Single RxJava peuvent être créées à partir d'un ListenableFuture en enregistrant des rappels dans un SingleEmitter

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

Créer un ListenableFuture

Créer un avenir immédiat

Si votre API n'est pas asynchrone, mais que vous devez encapsuler le résultat d'une dans un ListenableFuture, vous pouvez créer un ImmediateFuture. Ce peut être effectué à l'aide de la méthode Futures.immediateFuture(...) méthode par défaut.

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

Utiliser une coroutine

En langage Kotlin, un future{ ... } permet de convertir le résultat d'une fonction de suspension en ListenableFuture.

import kotlinx.coroutines.guava.future

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

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

Convertir un rappel

Pour convertir une API basée sur le rappel en une API qui utilise ListenableFuture, exécutez la commande suivante : CallbackToFutureAdapter Cette API est fournie par l'artefact androidx.concurrent:concurrent-futures.

Pour en savoir plus, consultez androidx.concurrent.

Conversion à partir de RxJava Single

Lorsque vous utilisez RxJava, un Single peut être convertie en SettableFuture, qui implémente ListenableFuture.

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