Un ListenableFuture
representa el resultado de un procesamiento asíncrono: un cálculo que puede haber terminado o no de producir un resultado. Es un tipo de Future
que te permite registrar devoluciones de llamada para que se ejecuten una vez que se complete el procesamiento, o de inmediato si ya se completó.
ListenableFuture
no forma parte del framework de Android y, en su lugar, lo proporciona Guava. Para obtener más información sobre la implementación de esta clase, consulta la explicación de ListenableFuture.
Muchas bibliotecas de Jetpack existentes, como CameraX o Servicios de salud, tienen métodos asíncronos en los que el tipo de datos que se muestra es ListenableFuture
, que representa el estado de la ejecución. En algunos casos, es posible que debas implementar un método que muestre un ListenableFuture
, por ejemplo, para cumplir con los requisitos de TileService
.
Bibliotecas requeridas
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") }
Cómo obtener el resultado de un ListenableFuture
Cómo agregar una devolución de llamada
Usa el método auxiliar Futures.addCallback(...)
para adjuntar devoluciones de llamada de éxito y fracaso 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() );
Suspensión en Kotlin
Cuando usas Kotlin, la forma más fácil de esperar el resultado de un ListenableFuture es usar await()
.
import kotlinx.coroutines.guava.await ... val future: ListenableFuture<QueryResult> = ... val queryResult = future.await() // suspends awaiting success
Interoperabilidad con RxJava
Se puede crear un Single
RxJava a partir de un ListenableFuture
registrando devoluciones de llamada dentro de 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));
Cómo crear un ListenableFuture
Creación de un futuro inmediato
Si tu API no es asíncrona, pero necesitas unir el resultado de una operación completada en un ListenableFuture
, puedes crear un ImmediateFuture
. Esto se puede hacer con el método de fábrica 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); } }
Cómo usar una corrutina
En Kotlin, se puede usar un objeto future{ ... }
para convertir el resultado de una función de suspensión en un elemento ListenableFuture
.
import kotlinx.coroutines.guava.future suspend fun getResultAsync(): QueryResult { ... } fun getResultFuture(): ListenableFuture<QueryResult> { return coroutineScope.future{ getResultAsync() } }
Convierte una devolución de llamada
Para convertir una API basada en devolución de llamada en una que use ListenableFuture
, usa CallbackToFutureAdapter
.
El artefacto androidx.concurrent:concurrent-futures
proporciona esta API.
Consulta androidx.concurrent para obtener más información.
Realiza la conversión de RxJava Single
Cuando se usa RxJava, un Single
se puede convertir en un SettableFuture
, que 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; }