Korzystanie z elementu ListenableFuture

Pole ListenableFuture jest wynikiem obliczeń asynchronicznych, czyli obliczeń, które mogły, ale nie muszą, nie zostały jeszcze zakończone. Jest to typ Future, który umożliwia rejestrowanie wywołań zwrotnych, które są wykonywane po zakończeniu obliczeń lub od razu, gdy przetwarzanie już się zakończyło.

ListenableFuture nie jest częścią platformy Androida. Zamiast niego jest dostarczany przez Guava. Więcej informacji o implementacji tej klasy znajdziesz w tym artykule.

Wiele istniejących bibliotek Jetpack, takich jak CameraX i Health Services, ma metody asynchroniczne, w których zwracany typ to ListenableFuture, który reprezentuje stan wykonania. W niektórych przypadkach może być konieczne wdrożenie metody, która zwraca wartość ListenableFuture, np. aby spełnić wymagania TileService.

Wymagane biblioteki

Odlotowy

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

Pobieram wynik: ListenableFuture

Dodawanie wywołania zwrotnego

Użyj Futures.addCallback(...) metody pomocniczej, aby dołączyć udane i nieudane wywołania zwrotne do 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()
);

Zawieszenie w Kotlin

W przypadku korzystania z Kotlin najprostszym sposobem oczekiwania na wynik elementu ListenableFuture jest użycie właściwości await().

import kotlinx.coroutines.guava.await

...

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

Interakcja z RxJava

Obiekt RxJava Single można utworzyć na podstawie ListenableFuture, rejestrując wywołania zwrotne w 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));

Tworzę ListenableFuture

Tworzenie najbliższej przyszłości

Jeśli interfejs API nie jest asynchroniczny, ale chcesz umieścić wynik zakończonej operacji w elemencie ListenableFuture, możesz utworzyć obiekt ImmediateFuture. Można to zrobić za pomocą metody fabrycznej 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);
    }
}

Korzystanie z współprogramowania

W Kotlin obiekt future{ ... } może służyć do konwertowania wyniku funkcji zawieszania na ListenableFuture.

import kotlinx.coroutines.guava.future

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

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

Konwersja wywołania zwrotnego

Aby przekonwertować interfejs API oparty na wywołaniach zwrotnych na taki, który korzysta z ListenableFuture, użyj CallbackToFutureAdapter. Ten interfejs API jest dostarczany przez artefakt androidx.concurrent:concurrent-futures.

Więcej informacji znajdziesz na stronie androidx.concurrent.

Konwersja z formatu RxJava Single

Korzystając z RxJava, Single można przekonwertować na plik SettableFuture z implementacją 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;
}