Skip to content
Advertisement

How to call Kotlin suspending coroutine function from Java 7

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 uses Result class, which seems to be unusable from Java (which makes sense as it is inline class). I was trying to use some subclass of Continuation 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. Simple Future 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.

Advertisement

Answer

You have several options depending on your environment.

  1. If you are using RxJava2 in the project, the module kotlinx-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() }

  1. 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);
    }
});

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement