Call Kotlin suspend function in Java class - java

Assume we have the following suspend function:
suspend fun doSomething(): List<MyClass> { ... }
If I want to call this function in one of my existing Java classes (which I'm not able to convert to Kotlin for now) and get its return value I have to provide a Continuation<? super List<MyClass>> as its parameter (Obviously).
My question is, How can I implement one. Specially its getContext getter.

First, add org.jetbrains.kotlinx:kotlinx-coroutines-jdk8 module to your dependencies. In your Kotlin file define the following async function that corresponds to Java style of writing async APIs:
fun doSomethingAsync(): CompletableFuture<List<MyClass>> =
GlobalScope.future { doSomething() }
Now use doSomethingAsync from Java in the same way as you are using other asynchronous APIs in the Java world.

If you dont want to use org.jetbrains.kotlinx:kotlinx-coroutines-jdk8, I have a new idea.
Write below code in your kotlin project.
#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())
}
}
}
I write it in my Coroutines class
Then you can call your suspend function like:
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() function is a suspend function.
suspend fun login(username: String, password: String): TokenResult
For your code, you can:
doSomething(getContinuation((result, throwable) -> {
//TODO
}));
Besides, you may want to run your callback code in different thread (e.g. Main thread), just use launch(Dispathers.Main) to wrap resumeWith()
Update: My friend has developed a plugin kotlin-jvm-blocking-bridge that can automatically generate blocking bridges for calling suspend functions from Java with minimal effort, also give it a try.

For coroutines 1.3.0 use this:
BuildersKt.launch(GlobalScope.INSTANCE,
Dispatchers.getMain(),//context to be ran on
CoroutineStart.DEFAULT,
(coroutineScope, continuation) -> suspendFunction(arguments)
);
For 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
}
}
);
My gradle file:
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 uses static classes for extension functions, launch is an extension function, so it is defined in BuildersKt. The first parameter is the target of the extension function, the rest are the parameters from the extension functions.

I created interface class based on #Kenvix answer to make it compatible with old Android SDK (lower than 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?)
}
usage
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
}));
}
}
now call suspend function from any java class by passing CoroutineCallback

Related

Kotlin: Type mismatch: inferred type is Unit but Void was expected

How can I rewrite in Kotlin a (Throwable) -> Unit into a (Throwable) -> Void?
The thing I need to achieve is make the following code compile:
fun myKotlinMethod(onError: (Throwable) -> Unit) { // Can not change here
val onErrorJavaCompatible: (Throwable) -> Void = { t -> onError.invoke(t) } // Compilation error
MyJavaLibrary.aMethod(onErrorJavaCompatible) // Can not change here
}
If you want to use a Kotlin function as a Java functional interface parameter, you need to convert it to that interface using SAM conversion, or you need to define an anonymous implementation of the interface (but that is verbose). Either way, Kotlin-Java interop will automatically switch between Unit/Void.
Assuming the interface in Java is named MyJavaCallback, here are two ways to do SAM conversion:
fun myKotlinMethod(onError: (Throwable) -> Unit) { // Can not change here
val onErrorJavaCompatible = MyJavaCallback { t -> onError(t) }
MyJavaLibrary.aMethod(onErrorJavaCompatible)
}
fun myKotlinMethod(onError: (Throwable) -> Unit) {
MyJavaLibrary.aMethod { t -> onError(t) }
}
Since you are directly passing through the code, you can prevent an unnecessary wrapper object around the Kotlin function by using inline:
inline fun myKotlinMethod(crossinline onError: (Throwable) -> Unit) {
MyJavaLibrary.aMethod { t -> onError(t) }
}
One more step you can take for simpler code. When passing a function as a function, you don't need to put it in a lambda and invoke it:
inline fun myKotlinMethod(crossinline onError: (Throwable) -> Unit) {
MyJavaLibrary.aMethod(onError)
}
Just to be complete, here's how you would do it the verbose way, assuming the function in the Java interface is named onSomeEvent:
inline fun myKotlinMethod(crossinline onError: (Throwable) -> Unit) {
val onErrorJavaCompatible = object: MyJavaCallback {
override fun onSomeEvent(t: Throwable) {
onError(t)
}
}
MyJavaLibrary.aMethod(onErrorJavaCompatible)
}

Converting Java To Kotlin: Type mismatch. Required: MenuSlidingTabStrip.OnTabSelectedListener? Found: (Nothing, Nothing) → Boolean

I am converting an Android app that was originally written in Java to Kotlin.
I am struggling to understand the following error message:
Type mismatch.
Required:
MenuSlidingTabStrip.OnTabSelectedListener?
Found:
(Nothing, Nothing) → Boolean
Here is the fragment of code where the error is being signalled (and it was working perfectly fine before the conversion):
private var tabs: MenuSlidingTabStrip? = null //The Kotlinized class
tabs!!.setOnTabSelectedListner{ tab, category -> /*Type mismatch...*/
listView!!.post {
...
}
}
The issue arose after converting this Java code (found in MenuSlidingTabStrip) :
public void setOnTabSelectedListner(OnTabSelectedListener listener) {
this.listener = listener;
}
public interface OnTabSelectedListener {
public void OnTabSelected(View tab, MenuCategory category);
}
To Kotlin
fun setOnTabSelectedListner(listener: OnTabSelectedListener?) {
this.listener = listener
}
interface OnTabSelectedListener {
fun onTabSelected(tab: View?, category: MenuCategory?)
}
Can you see the issue? Do you need more code?
I'd suggest you to use the natively supported lambdas as:
// make `this.listener` look like lambda signature as well
fun setOnTabSelectedListner(listener: (tab: View?, category: MenuCategory?) -> Unit) {
this.listener = listener
}
tabs!!.setOnTabSelectedListner { tab, category ->
// ...
}
If you still wanna use the SAM conversion with the manually defined interface, then mark the interface with the fun keyword as described in Kotlin 1.4-M1 Release changelog (will only work with Kotlin 1.4):
fun interface OnTabSelectedListener {
fun onTabSelected(tab: View?, category: MenuCategory?)
}
// call that method like this:
tabs!!.setOnTabSelectedListner(OnTabSelectedListener { tab, category ->
// ...
})
If you've not switched to Kotlin-1.4 (which is still in beta state), you have to manually instantiate the anonymous object if you are not willing to use the natively provided lambda syntax:
tabs!!.setOnTabSelectedListner(object : OnTabSelectedListener {
override fun onTabSelected(tab: View?, category: MenuCategory?) {
// ...
}
})

Continuation<? super String> cannot be applied to () [duplicate]

Assume we have the following suspend function:
suspend fun doSomething(): List<MyClass> { ... }
If I want to call this function in one of my existing Java classes (which I'm not able to convert to Kotlin for now) and get its return value I have to provide a Continuation<? super List<MyClass>> as its parameter (Obviously).
My question is, How can I implement one. Specially its getContext getter.
First, add org.jetbrains.kotlinx:kotlinx-coroutines-jdk8 module to your dependencies. In your Kotlin file define the following async function that corresponds to Java style of writing async APIs:
fun doSomethingAsync(): CompletableFuture<List<MyClass>> =
GlobalScope.future { doSomething() }
Now use doSomethingAsync from Java in the same way as you are using other asynchronous APIs in the Java world.
If you dont want to use org.jetbrains.kotlinx:kotlinx-coroutines-jdk8, I have a new idea.
Write below code in your kotlin project.
#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())
}
}
}
I write it in my Coroutines class
Then you can call your suspend function like:
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() function is a suspend function.
suspend fun login(username: String, password: String): TokenResult
For your code, you can:
doSomething(getContinuation((result, throwable) -> {
//TODO
}));
Besides, you may want to run your callback code in different thread (e.g. Main thread), just use launch(Dispathers.Main) to wrap resumeWith()
Update: My friend has developed a plugin kotlin-jvm-blocking-bridge that can automatically generate blocking bridges for calling suspend functions from Java with minimal effort, also give it a try.
For coroutines 1.3.0 use this:
BuildersKt.launch(GlobalScope.INSTANCE,
Dispatchers.getMain(),//context to be ran on
CoroutineStart.DEFAULT,
(coroutineScope, continuation) -> suspendFunction(arguments)
);
For 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
}
}
);
My gradle file:
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 uses static classes for extension functions, launch is an extension function, so it is defined in BuildersKt. The first parameter is the target of the extension function, the rest are the parameters from the extension functions.
I created interface class based on #Kenvix answer to make it compatible with old Android SDK (lower than 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?)
}
usage
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
}));
}
}
now call suspend function from any java class by passing CoroutineCallback

I have a problem after Java to Kotlin conversion with the error in Android Studio, Cannot infer a type for this parameter

As I converted this method in Java:
private void enqueueDownloads() {
final List<Request> requests = Data.getFetchRequestWithGroupId(GROUP_ID);
fetch.enqueue(requests, updatedRequests -> {
}, error -> Timber.d("DownloadListActivity Error: %1$s", error.toString()));
}
It led to this method which has a lot of errors:
private fun enqueueDownloads() {
val requests = Data.getFetchRequestWithGroupId(GROUP_ID)
fetch.enqueue(requests, { updatedRequests ->
}, { error -> Timber.d("DownloadListActivity Error: %1\$s", error.toString()) })
}
This method in Kotlin has a lot of errors at the method fetch.enqueue where the value updatedRequestsand error it says Cannot infer a type for this parameter.
So I hit hover on the method and hit Ctrl+B and the method declaration in the library is:
fun enqueue(requests: List<Request>, func: Func<List<Request>>? = null, func2: Func<Error>? = null): Fetch
/** Pause a queued or downloading download.
* #param ids ids of downloads to be paused.
* #param func Callback the paused downloads will be returned on. Note. Only downloads that
* were paused will be returned in the result list.
* #param func2 Callback that is called when attempting to pause downloads fail. An error is returned.
* #throws FetchException if this instance of Fetch has been closed.
* #return Instance
* */
The problem has something to do with CallBack based on the method documentation but I can not get it to work! How can I make it fully Kotlin and call it in Kotlin?.
The library is Fetch2 and written in Kotlin. Also I can not see whole code for the methods in the library.
TLDR: the shortes syntax in your specific case is:
fetch.enqueue(requests, Func { updatedRequests ->
}, Func { error -> Timber.d("DownloadListActivity Error: %1\$s", error) })
The issue here is that you are calling function written in Kotlin. You can't use the short lambda syntax here, since Kotlin will not turn lambdas automatically into the right interface in that case.
"Kotlin has proper function types, automatic conversion of functions into implementations of Kotlin interfaces is unnecessary and therefore unsupported." (source)
Usually to implement (Kotlin) interfaces anonymously in Kotlin you'll have to use the full-blown object Syntax:
interface KFunc<T> { fun call(result: T) }
val func = object : KFunc<String> {
override fun call(result: String) {
println(result)
}
}
However Func is an interface defined in Java so Kotlin offers an automatic conversion utility and you can write
val func: Func<String> = Func {
result -> println(result)
}
This is because there is an automatically generated method for every Java interface. In this case below code is generated
fun <T> Func(function: (result: T) -> Unit): Func<T> {
return object : Func<T> {
override fun call(result: T) {
function(result) // call the function
}
}
}
If the method that takes the Func was also written in Java that's where you can even leave out the Func {} part. E.g. given
public class JavaClass {
public static void doWithFunc(Func<String> func) {
func.call("Hello");
}
}
you could write
JavaClass.doWithFunc { result -> println(result) }
However given
object KotlinClass {
#JvmStatic
fun doWithFunc(func: Func<String>) {
func.call("Hello")
}
}
you must write at least
KotlinClass.doWithFunc(Func { result -> println(result) })
On the other hand from Java(8+) you can use lambdas in both cases
JavaClass.doWithFunc(string -> System.out.println(string));
KotlinClass.doWithFunc(string -> System.out.println(string));
It's a little confusing. At the moment, APIs written in Kotlin that are meant for Kotlin consumption shouldn't use functional interfaces but actual function parameters, i.e. for the enqueue function which is
fun enqueue(requests: List<Request>, func: Func<List<Request>>? = null, func2: Func<Error>? = null): Fetch
they would ideally also offer
fun enqueue(requests: List<Request>, func: ((List<Request>) -> Unit)? = null, func2: ((Error) -> Unit)? = null): Fetch
which would allow you to call it like expected in Kotlin
fixedFetch.enqueue(requests, { println(it) }, { Timber.w(it) })
The downside is that this gives a fairly odd looking method for Java users of the library since Kotlin uses it's Function1 interface to represent function parameters. You'll also have to return Unit.INSTANCE since that's actually a type in Kotlin.
Fetch enqueue(List<? extends Request>, Function1<? super List<? extends Request>, Unit>, Function1<? super Error, Unit>)

How to restrict function invocation to a particular thread/executor

I'm currently designing database for a mobile application. Recently I found very useful function to access database in background:
private val IO_EXECUTOR = Executors.newSingleThreadExecutor()
fun ioThread(f : () -> Unit) {
IO_EXECUTOR.execute(f)
}
Besides that I figured out that don't need synchronization code as the database will be accessed only in one thread (i.e the thread used by SingleThreadExecutor).
The only issue is that the following methods have to be restricted to be invoked only through ioThread function (or using IO_EXECUTOR).
abstract class MyDatabase : RoomDatabase() {
companion object {
fun init(context: Context) { ... }
fun getInstance() { ... }
}
Is it possible to achieve this in Kotlin/Java?
UPDATE: for now I have this implementation but think there should be better ones
// App.kt file
private val IO_EXECUTOR = Executors.newSingleThreadExecutor()
private var IO_THREAD_ID: Long = -1L
private fun getIOThreadId(): Long {
if (IO_THREAD_ID == -1L)
IO_THREAD_ID = IO_EXECUTOR.submit(Callable<Long> { Thread.currentThread().id }).get()
return IO_THREAD_ID
}
fun notInIOThread() = Thread.currentThread().id != getIOThreadId()
fun ioThread(f : () -> Unit) {
IO_EXECUTOR.execute(f)
}
and then use notInIOThread() in init() and getInstance() functions
If you absolutely need to make sure that the code is running on the correct thread, you could make use of a custom thread and then checking Thread.currentThread() for the interface.
private interface MarkedIOThread // Marker interface
private val IO_EXECUTOR = Executors.newSingleThreadExecutor { r ->
return object : Thread(r), MarkedIOThread
}
fun notInIOThread(): Boolean = Thread.currentThread() !is MarkedIOThread
Yes, you can use android annotations`s Worker Thread annotation.
When you annotate a method or class with #WorkerThread, android will give you lint errors if you call it from the UI thread.
You can read more about the #WorkerThread here: https://developer.android.com/reference/android/support/annotation/WorkerThread
And more about android annotations here: https://developer.android.com/studio/write/annotations
I would suggest that you should check room library: https://developer.android.com/topic/libraries/architecture/room
It is very powerful, if you don't have any specific reason to create a database library, room is your best bet.
I assume you want the functions to be called only inside ioThread code block, otherwise there'd be a type error. First make them member functions of a class with user-code-inaccessible constructor so others cannot call it directly:
class MyDslClass internal constructor() {
fun init(context: Context) { ... }
fun getInstance() { ... }
}
And ioThread should be:
fun ioThread(f : MyDslClass.() -> Unit) {
val dsl = MyDslClass()
IO_EXECUTOR.execute { dsl.f() }
}
Then you can restrict calls to those functions only inside ioThread block.
fun main(args: Array<String>) {
ioThread {
getInstance() // Ok
}
// cannot call `getInstance` since I cannot construct a `MyDslClass`
}

Categories