调用Java类中的Kotlin挂起函数

bfrts1fy  于 2023-02-02  发布在  Java
关注(0)|答案(4)|浏览(361)

假设我们有以下suspend函数:

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

如果我想在我现有的Java类中调用这个函数(目前我还不能将其转换为Kotlin)并获得它的返回值,我必须提供一个Continuation<? super List<MyClass>>作为它的参数(显然)。
我的问题是,如何实现一个,特别是它的getContext getter。

nwnhqdif

nwnhqdif1#

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

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

现在使用来自Java的doSomethingAsync,方法与使用Java世界中的其他异步API相同。

agyaoht7

agyaoht72#

如果你不想用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())
            }
        }
    }

我在Coroutines类中编写了它
然后您可以调用suspend函数,如下所示:

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) Package resumeWith()即可
更新:我的朋友开发了一个插件kotlin-jvm-blocking-bridge,它可以自动生成阻塞桥,用于从Java调用挂起函数,而且非常简单,也给予尝试一下。

wgmfuz8q

wgmfuz8q3#

对于协程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中定义,第一个参数是扩展函数的目标,其余的都是来自扩展函数的参数。

c9qzyr3d

c9qzyr3d4#

我创建了基于@Kenvix答案的接口类,使其与旧的Android SDK兼容(低于API 24)

interface CoroutineCallback<RESULT> {

companion object {

    @JvmOverloads
    fun <R> call(
        callback: CoroutineCallback<R>,
        dispatcher: CoroutineDispatcher = Dispatchers.Default
    ): Continuation<R> {
        return object : Continuation<R> {
            override val context: CoroutineContext
                get() = dispatcher

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

 fun onComplete(result: RESULT?, error: Throwable?)
}

用法

class kotlinClass {
  suspend doSomething(foo, bar) : FooBar {}
}

class javaClass {
  void doSomething(){
   kotlinClassObject.doSomething("foo", "bar", CoroutineCallback.Companion.call((fooBar, error) -> { 
     //do something with result or error
   }));
  }
}

现在通过传递CoroutineCallback从任何java类调用suspend函数

相关问题