Usare un futuro ascoltabile

Un ListenableFuture rappresenta il risultato di un calcolo asincrono: di calcolo che potrebbe aver già terminato o meno di produrre un risultato. È una tipo di Future che consente di registrare i callback da eseguire dopo che il calcolo o, se il calcolo è già stato completato, immediatamente.

ListenableFuture non fa parte del framework Android e viene invece fornito di Guava. Per ulteriori informazioni di questa classe, consulta la spiegazione di ListenableFuture.

Molte librerie Jetpack esistenti, ad esempio CameraX o i servizi sanitari hanno metodi asincroni dove il tipo restituito è ListenableFuture che rappresenta lo stato di l'esecuzione. In alcuni casi, potrebbe essere necessario implementare un metodo che restituisca un ListenableFuture, in modo da soddisfare i requisiti di TileService.

Librerie obbligatorie

Alla moda

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

Recupero del risultato di un ListenableFuture

Aggiunta di un callback

Utilizza la Futures.addCallback(...) helper per collegare i callback di esito positivo e negativo a 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()
);

Sospensione in Kotlin

Quando usi Kotlin, il modo più semplice per attendere il risultato di un ListenableFuture consiste nell'utilizzare await().

import kotlinx.coroutines.guava.await

...

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

Interoperabilità con RxJava

Un file RxJava Single può essere creato da un ListenableFuture registrando i callback all'interno di 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));

Creazione di un ListenableFuture in corso...

Creare un futuro immediato

Se l'API non è asincrona, ma devi eseguire il wrapping del risultato di un operazione in un ListenableFuture, puoi creare un ImmediateFuture. Questo può essere eseguita utilizzando 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);
    }
}

Uso di una coroutina

In Kotlin, una future{ ... } può essere utilizzato per convertire il risultato di una funzione di sospensione in un ListenableFuture.

import kotlinx.coroutines.guava.future

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

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

Conversione di un callback

Per convertire un'API basata su callback in un'API che utilizza ListenableFuture, utilizza CallbackToFutureAdapter Questa API è fornita dall'artefatto androidx.concurrent:concurrent-futures.

Per ulteriori informazioni, vedi androidx.concurrent.

Conversione da RxJava Single in corso...

Quando utilizzi RxJava, viene utilizzato un parametro Single può essere convertito in un elemento SettableFuture, che implementa 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;
}