在Java类中调用Kotlin暂停函数

mrt*_*ndi 12 java kotlin kotlin-coroutines

假设我们有以下挂起功能:

suspend fun doSomething(): List<MyClass> { ... }
Run Code Online (Sandbox Code Playgroud)

如果我想在我现有的一个Java类中调用此函数(我现在无法将其转换为Kotlin)并获得其返回值,我必须提供一个Continuation<? super List<MyClass>>参数(显然).

我的问题是,我该如何实施一个.特别是它的getContext吸气剂.

Rom*_*rov 21

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

fun doSomethingAsync(): CompletableFuture<List<MyClass>> =
    GlobalScope.future { doSomething() }
Run Code Online (Sandbox Code Playgroud)

现在使用doSomethingAsyncJava的方式与在Java世界中使用其他异步API的方式相同.

  • 注意:这需要 API 级别 24 或更高版本。 (12认同)
  • 不适用于 Android 6.0。错误:java.lang.NoClassDefFoundError:解析失败:Ljava/util/concurrent/CompletableFuture; (4认同)
  • 只是供新手Gradle用户(像我一样)使用的FYI-您需要将版本添加到依赖项,例如:`implementation“ org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.0.1”` (3认同)
  • 您可以将其表示为任何其他未来类型并在 Java 代码中使用。我们内置了对转换为 CompletableFuture、ListenableFuture、Rx Single、Reactor Mono 的支持。您也可以自己编写。 (2认同)
  • 使用 Dispatchers.Main 通常是从 java 调用时需要的: fun doSomethingAsync(): CompletableFuture&lt;List&lt;MyClass&gt;&gt; = GlobalScope.future(Dispatchers.Main) { doSomething() } (2认同)

Dra*_*eru 8

对于协程 1.3.0 使用这个:

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

对于 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
            }
        }
);
Run Code Online (Sandbox Code Playgroud)

我的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"
Run Code Online (Sandbox Code Playgroud)

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

  • `// 做你想做的事` - 你不能在这里做你想做的事,因为你必须提供一个期望以被调用函数的返回类型恢复的延续,但你没有这样的延续,你的答案没有显示如何从 Java 构建它。从“launch”获得的延续只是完成延续,即当整个协程完成时使用“Unit”调用的延续。 (5认同)

Ken*_*ure 8

如果你不想使用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())
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

我写在我的Coroutines课上

然后你可以调用你的挂起函数,如:

            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);
                    }
            ));
Run Code Online (Sandbox Code Playgroud)

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

对于您的代码,您可以:

doSomething(getContinuation((result, throwable) -> { 
       //TODO
}));
Run Code Online (Sandbox Code Playgroud)

  • 就像 Roman 的答案一样,这也需要 API 24 或更高版本 (3认同)