Home > Mobile >  Is it possible for a function with a Kotlin coroutine to wait for completion and return to a Java cl
Is it possible for a function with a Kotlin coroutine to wait for completion and return to a Java cl

Time:11-04

I am working on a Java-based Android app. 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.

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). 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:

    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. Through debugging, I discovered that before the coroutine scope can do anything, the conclusion of performMoreThings() is reached with the unmodified Data list.

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)? 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()?

CodePudding user response:

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. Suspend functions of Kotlin can do this, but Java methods can't.

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, i.e. receive a callback or return a future:

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);
}
  • Related