Menggunakan ListenableFuture

ListenableFuture mewakili hasil komputasi asinkron: komputasi yang mungkin belum atau belum selesai memberikan hasil. Ini adalah jenis Future yang memungkinkan Anda mendaftarkan callback untuk dijalankan setelah komputasi selesai, atau jika komputasi sudah selesai, secara langsung.

ListenableFuture bukan bagian dari framework Android dan disediakan oleh Guava. Untuk informasi selengkapnya tentang implementasi class ini, lihat ListenableFuture dijelaskan.

Banyak library Jetpack yang ada seperti CameraX atau Fitur Kesehatan memiliki metode asinkron dengan jenis nilai yang ditampilkan adalah ListenableFuture yang mewakili status eksekusi. Dalam beberapa kasus, Anda mungkin perlu mengimplementasikan metode yang menampilkan ListenableFuture, misalnya untuk memenuhi persyaratan TileService.

Library yang diperlukan

Groovy

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

Mendapatkan hasil ListenableFuture

Menambahkan callback

Gunakan metode bantuan Futures.addCallback(...) untuk melampirkan callback berhasil dan gagal ke 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()
);

Penangguhan di Kotlin

Saat menggunakan Kotlin, cara termudah untuk menunggu hasil ListenableFuture adalah dengan menggunakan await().

import kotlinx.coroutines.guava.await

...

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

Interop dengan RxJava

Single RxJava dapat dibuat dari ListenableFuture dengan mendaftarkan callback di dalam 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));

Membuat ListenableFuture

Menciptakan masa depan dalam waktu dekat

Jika API Anda tidak asinkron, tetapi Anda perlu menggabungkan hasil operasi yang telah selesai ke ListenableFuture, Anda dapat membuat ImmediateFuture. Hal ini dapat dilakukan menggunakan metode factory 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);
    }
}

Menggunakan coroutine

Di Kotlin, future{ ... } dapat digunakan untuk mengonversi hasil fungsi penangguhan menjadi ListenableFuture.

import kotlinx.coroutines.guava.future

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

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

Mengonversi callback

Untuk mengonversi API berbasis callback menjadi API yang menggunakan ListenableFuture, gunakan CallbackToFutureAdapter. API ini disediakan oleh artefak androidx.concurrent:concurrent-futures.

Lihat androidx.concurrent untuk informasi selengkapnya.

Mengonversi dari RxJava Single

Saat menggunakan RxJava, Single dapat dikonversi menjadi SettableFuture, yang mengimplementasikan 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;
}