Sử dụng ListenableFuture

ListenableFuture thể hiện kết quả của một phép tính không đồng bộ: phép tính có thể chưa hoàn tất hoặc chưa hoàn tất kết quả. Đó là loại Future cho phép bạn đăng ký lệnh gọi lại được thực thi sau khi tính toán hoặc nếu phép tính đã hoàn tất ngay lập tức.

ListenableFuture không thuộc khung Android mà được cung cấp thay vào đó của Guava. Để biết thêm thông tin về Việc triển khai lớp này, hãy xem ListenableFuture giải thích.

Nhiều thư viện Jetpack hiện có như CameraX hoặc Dịch vụ sức khoẻ có các phương thức không đồng bộ trong đó loại dữ liệu trả về là ListenableFuture, đại diện cho trạng thái của quá trình thực thi. Trong một số trường hợp, bạn có thể cần phải triển khai một phương thức trả về ListenableFuture, chẳng hạn như để đáp ứng các yêu cầu của TileService.

Thư viện bắt buộc

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

Nhận kết quả của ListenableFuture

Thêm lệnh gọi lại

Sử dụng Futures.addCallback(...) phương thức trợ giúp để đính kèm các lệnh gọi lại thành công và không thành công vào 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()
);

Tạm ngưng trong Kotlin

Khi sử dụng Kotlin, cách dễ nhất để chờ kết quả của ListenableFuture là sử dụng await().

import kotlinx.coroutines.guava.await

...

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

Khả năng tương tác với RxJava

RxJava Single có thể được tạo qua ListenableFuture bằng cách đăng ký các lệnh gọi lại bên trong một 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));

Đang tạo một ListenableFuture

Tạo tương lai tức thì

Nếu API của bạn không đồng bộ, nhưng bạn cần gói kết quả của một vào ListenableFuture, bạn có thể tạo ImmediateFuture. Chiến dịch này có thể thực hiện bằng cách sử dụng Futures.immediateFuture(...) phương thức ban đầu.

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

Sử dụng coroutine

Trong Kotlin, future{ ... } có thể được dùng để chuyển đổi kết quả của hàm tạm ngưng thành ListenableFuture.

import kotlinx.coroutines.guava.future

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

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

Chuyển đổi lệnh gọi lại

Để chuyển đổi API dựa trên lệnh gọi lại thành API sử dụng ListenableFuture, hãy sử dụng CallbackToFutureAdapter. API này do cấu phần phần mềm androidx.concurrent:concurrent-futures cung cấp.

Hãy xem androidx.concurrent để biết thêm thông tin.

Đang chuyển đổi từ RxJava Single

Khi sử dụng RxJava, Single có thể được chuyển đổi thành SettableFuture, triển khai 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;
}