How to call Kotlin suspending coroutine function from Java 7
Solution 1
You have several options depending on your environment.
- If you are using
RxJava2
in the project, the modulekotlinx-coroutines-rx2
has utility functions to convert back and forth between coroutines and Rx datatypes.
Example
suspend fun sayHello(): String {
delay(1000)
return "Hi there"
}
fun sayHelloSingle(): Single<String> = GlobalScope.rxSingle { sayHello() }
- Otherwise, you could add a new
Continuation
class that matches the definition of the old one and is also useful in the Java side.
Example (Kotlin side)
abstract class Continuation<in T> : kotlin.coroutines.Continuation<T> {
abstract fun resume(value: T)
abstract fun resumeWithException(exception: Throwable)
override fun resumeWith(result: Result<T>) = result.fold(::resume, ::resumeWithException)
}
Example (Java side)
sayHello(new Continuation<String>() {
@Override
public CoroutineContext getContext() {
return EmptyCoroutineContext.INSTANCE;
}
@Override
public void resume(String value) {
doSomethingWithResult(value);
}
@Override
public void resumeWithException(@NotNull Throwable throwable) {
doSomethingWithError(throwable);
}
});
Solution 2
You can use BuildersKt. That is already included in the implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0"
BuildersKt.launch(
GlobalScope.INSTANCE,
(CoroutineContext) Dispatchers.getMain(),
CoroutineStart.DEFAULT,
(Function2<CoroutineScope, Continuation<? super Unit>, Unit>) (coroutineScope, continuation) -> {
// your code here
return Unit.INSTANCE;
}
);
michalbrz
I do Android programming by day and every other programming at night. Suprisingly, I also care about code quality.
Updated on June 07, 2022Comments
-
michalbrz almost 2 years
I'm trying to call Kotlin function from Java 7. I'm using coroutines and this called function is suspending, for example:
suspend fun suspendingFunction(): Boolean { return async { longRunningFunction() }.await() } suspend fun longRunningFunction() : Boolean { delay(400) return true }
I was using coroutines in version 0.25.3 and I could emulate simple Java callback style by passing
Continuation<U>
instance as an argument to suspending function, e.g.CoroutinesKt.suspendingFunction(new Continuation<Boolean>() { @Override public CoroutineContext getContext() { return EmptyCoroutineContext.INSTANCE; } @Override public void resume(Boolean value) { doSomethingWithResult(value); } @Override public void resumeWithException(@NotNull Throwable throwable) { handleException(throwable); } });
However, after updating to fully stable 1.0.1 release, I think it's no longer possible. Let's say updated version of suspending function looks like that:
suspend fun suspendingFunction(): Boolean { return GlobalScope.async { longRunningFunction() }.await() }
Continuation<U>
now usesResult
class, which seems to be unusable from Java (which makes sense as it is inline class). I was trying to use some subclass ofContinuation
from coroutines but they are all internal or private.I know that usually it is advised to transform coroutine to
CompletableFuture
, but I'm on Android, which means Java 7 only. SimpleFuture
on the other hand is too dumb as I don't want to check periodically if function is finished - I just want to be called when it is finished. And I would really like to avoid adding new libraries or many additional classes/methods.Is there any simple way to call suspending function directly from Java 7?
As Kotlin tries to be very interoperable with Java I would imagine there would be some easy way to do that, but I'm yet to find it.
-
michalbrz over 5 yearsThanks! While I don't use RxJava, handling
Result
class on Kotlin side is very good idea. And one additional class is small price to pay. -
Ricard about 5 yearsGreat response. Rx is good and clean approach to handle suspend calls inside java classes
-
casolorz over 4 yearsIf I'm calling this from a Java
Activity
should I still be usingreturn EmptyCoroutineContext.INSTANCE;
? or is there a betterContext
to use? -
Marko Topolnik over 4 yearsThis answer is now outdated, the
Continuation
interface has changed and now has a single methodresumeWith
that takes an inline class on the Kotlin side, it can represent either success or failure but you can't distinguish them because you have no access to the private classes. -
Nathan Schwermann about 4 years@MarkoTopolnik the continuation will come up as an Object that is non null but actually it can be null and will be you Object, in this example a String.
-
Marko Topolnik about 4 years@NathanSchwermann If the suspendable function throws an exception, the continuation is resumed with
kotlin.Result$Failure
, which is aninternal class
. -
tim4dev almost 4 yearsGreat! It worked
kotlin-stdlib-jdk7
,kotlinx-coroutines-android:1.3.6
-
tim4dev almost 4 yearsFor RxJava you can simply call
rxSingle { sayHello() }
-
shtas about 2 yearshow do I switch dispatcher context inside the result block (your code here)? I need to read the data from the db on the background thread but afterwards display it to the user (android uI).