在 Java class 中调用 Kotlin 挂起函数

Call Kotlin suspend function in Java class

假设我们有以下挂起函数:

suspend fun doSomething(): List<MyClass> { ... }

如果我想在我现有的 Java 类 之一(我现在无法转换为 Kotlin)中调用此函数并获取其 return 值我必须提供一个 Continuation<? super List<MyClass>> 作为它的参数(显然)。

我的问题是,我怎样才能实现一个。特别是它的 getContext getter.

首先,将 org.jetbrains.kotlinx:kotlinx-coroutines-jdk8 模块添加到您的依赖项中。在您的 Kotlin 文件中,定义以下对应于 Java 异步 API 编写风格的异步函数:

fun doSomethingAsync(): CompletableFuture<List<MyClass>> =
    GlobalScope.future { doSomething() }

现在使用 Java 中的 doSomethingAsync 就像您在 Java 世界中使用其他异步 API 一样。

对于协程 1.3.0 使用这个:

BuildersKt.launch(GlobalScope.INSTANCE,
                Dispatchers.getMain(),//context to be ran on
                CoroutineStart.DEFAULT,
                (coroutineScope, continuation) -> suspendFunction(arguments)
        );

对于 java < 8:

BuildersKt.launch(
        GlobalScope.INSTANCE,
        Dispatchers.getMain(),//context to be ran on
        CoroutineStart.DEFAULT,
        new Function2<CoroutineScope, Continuation<? super Unit>, Unit/*or your return type here*/>() {
            @Override
            public Unit/*or your return type here*/ invoke(CoroutineScope coroutineScope, Continuation<? super Unit> continuation) {
                //do what you want
                return Unit.INSTANCE; //or something with the defined type
            }
        }
);

我的 gradle 文件:

implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.50"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0"

Kotlin对扩展函数使用静态类,launch是一个扩展函数,所以定义在BuildersKt中。第一个参数是扩展函数的目标,其余是扩展函数的参数。

如果你不想用org.jetbrains.kotlinx:kotlinx-coroutines-jdk8,我有个新主意

在您的 kotlin 项目中编写以下代码。

    @JvmOverloads
    fun <R> getContinuation(onFinished: BiConsumer<R?, Throwable?>, dispatcher: CoroutineDispatcher = Dispatchers.Default): Continuation<R> {
        return object : Continuation<R> {
            override val context: CoroutineContext
                get() = dispatcher

            override fun resumeWith(result: Result<R>) {
                onFinished.accept(result.getOrNull(), result.exceptionOrNull())
            }
        }
    }

我写在我的Coroutinesclass

然后你可以这样调用你的挂起函数:

            Coroutines coroutines = new Coroutines();
            UserUtils.INSTANCE.login("user", "pass", coroutines.getContinuation(
                    (tokenResult, throwable) -> {
                        System.out.println("Coroutines finished");
                        System.out.println("Result: " + tokenResult);
                        System.out.println("Exception: " + throwable);
                    }
            ));

login() 函数是一个挂起函数。
suspend fun login(username: String, password: String): TokenResult

对于您的代码,您可以:

doSomething(getContinuation((result, throwable) -> { 
       //TODO
}));

此外,你可能想运行你的回调代码在不同的线程(例如主线程),只需使用launch(Dispathers.Main)包裹resumeWith()