简体   繁体   English

带有 Kotlin 协程的函数是否可以等待完成并返回 Java 类?

[英]Is it possible for a function with a Kotlin coroutine to wait for completion and return to a Java class?

I am working on a Java-based Android app.我正在开发基于 Java 的 Android 应用程序。 I want to start using Kotlin & coroutines for network-related work off the main thread, but I have run into an issue trying to figure out how to successfully handle a certain situation.我想开始在主线程之外使用 Kotlin 和协程进行与网络相关的工作,但我遇到了一个问题,试图弄清楚如何成功处理某种情况。

I have created a Kotlin file with a networking function which I plan to call in a Java class (a view model, which at this time needs to stay written in Java).我已经创建了一个带有网络功能的 Kotlin 文件,我计划在 Java 类(一个视图模型,目前需要用 Java 编写)中调用它。 The idea is that I want the networking function to modify and return a list back to the view model, and then allow the view model to proceed.这个想法是我希望网络功能修改并将列表返回给视图模型,然后允许视图模型继续进行。

fun performNetworking(
    data: MutableList<Data>
): MutableList<Data> {
    CoroutineScope(Dispatchers.IO).launch {
        data.forEach {
            // modify each element in the list
        }
    }
    return data
}

Currently, I am calling it from the Java view model as such:目前,我从 Java 视图模型中调用它,如下所示:

    public void modifyData(List<Data> data) {
        List<Data> modifiedData = NetworkingKt.performNetworking(data);
        performMoreThings(modifiedData);
    }

With this implementation, performMoreThings() triggers as if none of the Data in the list was modified.使用此实现, performMoreThings()会触发,就好像列表中的任何数据都没有被修改一样。 Through debugging, I discovered that before the coroutine scope can do anything, the conclusion of performMoreThings() is reached with the unmodified Data list.通过调试,我发现在协程作用域可以做任何事情之前, performMoreThings()的结论是用未修改的Data列表。

Therefore, I am wondering if there is a way to have the code wait for the coroutine scope's work to complete before returning the Data list to the Java view model (without locking up the primary thread and preventing the user from interacting with the app)?因此,我想知道是否有办法让代码在将数据列表返回到 Java 视图模型之前等待协程范围的工作完成(不锁定主线程并阻止用户与应用程序交互)? Or am I misunderstanding the abilities, purposes, and implementations of coroutines and this is not possible?还是我误解了协程的能力、目的和实现,这是不可能的? Would I have to pass in a reference to the view model and have it call a continuation method once the coroutine is complete, much as I would do with AsyncTask's in its onPostExecute() ?我是否必须传入对视图模型的引用,并在协程完成后让它调用延续方法,就像我在onPostExecute()使用 AsyncTask 所做的那样?

No, this is not possible.不,这是不可能的。 Not because of limitations of coroutines, but the opposite - due to limitations of non-coroutine code.不是因为协程的限制,而是相反 - 由于非协程代码的限制。 Your modifyData() is a regular, not-suspendable method, so it can't anyhow wait without blocking the thread.您的modifyData()是一个常规的、不可modifyData()方法,因此它无论如何都不能在不阻塞线程的情况下等待。 Suspend functions of Kotlin can do this, but Java methods can't. Kotlin 的挂起函数可以做到这一点,但 Java 方法不能。

You need to either invoke modifyData() from the background thread, so blocking won't be a problem or redesign performNetworking() to use one of classic techniques for dealing with asynchronous tasks, ie receive a callback or return a future:您需要从后台线程调用modifyData() ,因此阻塞不会成为问题,或者重新设计performNetworking()以使用处理异步任务的经典技术之一,即接收回调或返回未来:

fun performNetworking(
    data: MutableList<Data>
): CompletableFuture<MutableList<Data>> {
    return CoroutineScope(Dispatchers.IO).future {
        data.forEach {
            // modify each element in the list
        }
        data
    }
}
public void modifyData(List<Data> data) {
    NetworkingKt.performNetworking(data)
            .thenAccept(this::performMoreThings);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM