ListenableFuture представляет собой результат асинхронного вычисления, которое может быть завершено или нет. Это тип Future, который позволяет регистрировать обратные вызовы, выполняемые после завершения вычислений или сразу, если вычисления уже завершены.
ListenableFuture не входит в платформу Android, а предоставляется Guava. Подробную информацию о реализации этого класса можно найти в статье ListenableFuture explained (Общие сведения о ListenableFuture).
Многие существующие библиотеки Jetpack, такие как CameraX или сервисы наблюдения за здоровьем, имеют асинхронные методы, в которых тип возвращаемого значения – ListenableFuture, представляющий статус выполнения. В некоторых случаях может потребоваться реализовать метод, который возвращает ListenableFuture, например чтобы выполнить требования TileService.
Необходимые библиотеки
Классный
dependencies { implementation "com.google.guava:guava:31.0.1-android" // To use CallbackToFutureAdapter implementation "androidx.concurrent:concurrent-futures:1.3.0" // Kotlin implementation "org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.6.0" }
Котлин
dependencies { implementation("com.google.guava:guava:31.0.1-android") // To use CallbackToFutureAdapter implementation("androidx.concurrent:concurrent-futures:1.3.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
Объект Single RxJava можно создать из ListenableFuture, зарегистрировав обратные вызовы в 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));
Создание 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{ ... }, чтобы преобразовать результат функции suspend в ListenableFuture.
import kotlinx.coroutines.guava.future suspend fun getResultAsync(): QueryResult { ... } fun getResultFuture(): ListenableFuture<QueryResult> { return coroutineScope.future{ getResultAsync() } }
Преобразование обратного вызова
Чтобы преобразовать API на основе обратного вызова в API, использующий ListenableFuture, используйте CallbackToFutureAdapter.
Этот API предоставляется артефактом androidx.concurrent:concurrent-futures.
Подробную информацию можно найти на странице androidx.concurrent.
Переход с RxJava Single
При использовании RxJava объект Single можно преобразовать в SettableFuture, который реализует 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; }