ListenableFuture 사용

ListenableFuture는 비동기 계산의 결과를 나타냅니다. 비동기 계산은 아직 결과 생성을 완료했을 수도 있고 완료하지 않았을 수도 있습니다. 이는 Future의 한 유형으로, 계산이 완료되거나 계산이 이미 완료된 경우 즉시 실행될 콜백을 등록할 수 있습니다.

ListenableFuture는 Android 프레임워크의 일부가 아니며 Guava에서 제공됩니다. 이 클래스의 구현에 관한 자세한 내용은 ListenableFuture 설명을 참고하세요.

CameraX 또는 건강 관리 서비스와 같은 많은 기존 Jetpack 라이브러리에는 반환 유형이 실행 상태를 나타내는 ListenableFuture인 비동기 메서드가 있습니다. 경우에 따라 TileService의 요구사항을 충족하기 위해 ListenableFuture를 반환하는 메서드를 구현해야 할 수도 있습니다.

필수 라이브러리

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

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와의 상호 운용성

RxJava SingleSingleEmitter 내에 콜백을 등록하여 ListenableFuture에서 생성할 수 있습니다.

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{ ... }를 사용하여 정지 함수의 결과를 ListenableFuture로 변환할 수 있습니다.

import kotlinx.coroutines.guava.future

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

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

콜백 변환

콜백 기반 API를 ListenableFuture를 사용하는 API로 변환하려면 CallbackToFutureAdapter를 사용합니다. 이 API는 androidx.concurrent:concurrent-futures 아티팩트에서 제공합니다.

자세한 내용은 androidx.concurrent를 참고하세요.

RxJava에서 변환 Single

RxJava를 사용하는 경우 SingleListenableFuture를 구현하는 SettableFuture로 변환할 수 있습니다.

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