I am trying to use the accept answer here. Call Kotlin suspend function in Java class , innerReadStepsByTimeRange this one is never called but debug was able to stop at the readStepsByTimeRange.
My Kotlin class (the one that is called from java)
class StepReaderUtils {
companion object {
#OptIn(DelicateCoroutinesApi::class)
fun readStepsByTimeRange(
healthConnectClient: HealthConnectClient,
startTime: Instant,
endTime: Instant
) : CompletableFuture<Long> = GlobalScope.future {
innerReadStepsByTimeRange(healthConnectClient, startTime, endTime)
}
private suspend fun innerReadStepsByTimeRange (
healthConnectClient: HealthConnectClient,
startTime: Instant,
endTime: Instant
) : Long {
var totalStepsCount = 0L
val response =
healthConnectClient.readRecords(
ReadRecordsRequest(
StepsRecord::class,
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
)
for (stepRecord in response.records) {
totalStepsCount += stepRecord.count;
}
return totalStepsCount
}
}
}
My java caller method
CompletableFuture<Long> totalStepsCountCF = StepReaderUtils.Companion.readStepsByTimeRange(
healthConnectClient, startDate, endDate);
return totalStepsCountCF.get();
My Gradle module build
implementation 'org.jetbrains.kotlin:kotlin-stdlib:1.8.0'
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0'
implementation "androidx.health.connect:connect-client:1.0.0-alpha08"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.6.4"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
What am i doing wrong?
Related
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 DateUtil.kt file which contains.
fun getFirstDayOfTheWeek(): String {
val firstDay: LocalDate = LocalDate.now(ZoneId.of(DateConstants.IST_ZONE_ID))
.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
return firstDay.toString()
}
How can i test this? There is no class and just functions. Using spring boot,
#ExtendWith(SpringExtension.class) works at a class level.
Should i still create a DateUtilTest class for it , or is there a way to test without creating a class?
#ExtendWith(SpringExtension::class)
class DateUtilsTest {
#Test
fun getFirstDayOfTheWeekTest() {
}
}
Also, Can someone help with how this function can be tested? Should i mock the LocalDate library?
You don't need SpringExtension to test simple non-spring code. All you need a simple test in a class.
Couple of things to consider while designing such function. LocalDate.now() makes the function impure. Instead this Date should come as a parameter to the function, so it is easier to test. With Kotlin, you can initialize with default value, so the signature does not change for function callers.
fun getFirstDayOfTheWeek(date: LocalDate = LocalDate.now()): String {
val firstDay: LocalDate = date.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
return firstDay.toString()
}
class DateUtilKt {
#Test
fun testFirstDayOfTheWeek() {
val day = getFirstDayOfTheWeek(LocalDate.of(2020, 5,22))
assertEquals("2020-05-18", day)
}
}
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'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`
}
I'am coming from java and I have little difficulties to learn the patterns.
I have the first protocol
protocol Interval
{
}
And the second:
protocol Event
{
associatedtype IntervalType: Interval
var interval: IntervalType
func doSomething(param: IntervalType )
}
How can i make an array with the type Event?
I took a look at the type-erase and the solution that it gives it to create a struct like this one:
public struct AnyEvent<intervalType: Interval>: Event {...}
But it only gives me the possibility to create an array with any event type and only one type of Interval, I want to make an array with any kind of Events that could contain any kind of Intervals, something like: [AnyEvent] or [AnyEvent<Interval>]
I also want to ask if there is a possibility to make Event extend Equatable and define it in the type-erase.
Edit:
Hoping someone is good at both swift and java, and can provide a translated pattern for this:
A simple common interval interface:
interface ReadableInterval {...}
Two types that confirms the readable interval:
class Interval implements ReadableInterval {...}
class MutableInterval implements: ReadableInterval {...}
A common events interface:
interface ReadablEvent
{
ReadableInterval getInterval();
}
Two types of events that could have different intervals, with the specialized return type of the methods:
class Event implements: ReadablEvent
{
private Interval interval = new Interval();
Interval getInterval()
{
return interval;
}
}
class MutableEvent implements: ReadablEvent
{
private MutableInterval interval = new MutableInterval();
MutableInterval getInterval()
{
return interval;
}
}
and then i want to have a list or array with the both Event and MutableEvent like:
ArrayList<ReadableEvent>
or
ReadableEvent[]
As you know in Swift you cannot declare an array of a protocols with an associated type (please read this for more details)
However you can declare a new protocol like this
protocol AnyEvent {
var interval: Interval { get }
func doSomething(param: Interval )
}
Your 3 protocols should now look like this
protocol Interval {
}
protocol AnyEvent {
var interval: Interval { get }
func doSomething(param: Interval )
}
protocol Event: AnyEvent {
associatedtype IntervalType: Interval
var interval: IntervalType { get }
func doSomething(param: IntervalType )
}
Usage
To use these protocols we need some structs (or classes) that conform to them
struct TimeInterval: Interval { }
struct TapEvent: AnyEvent {
var interval: Interval = TimeInterval()
func doSomething(param: Interval) {
print("It's a tap")
}
}
struct GestureEvent: AnyEvent {
var interval: Interval = TimeInterval()
func doSomething(param: Interval) {
print("It's a gesture")
}
}
Now we can
var events = [AnyEvent]()
events.append(TapEvent())
events.append(GestureEvent())
for event in events {
event.doSomething(TimeInterval())
}
It's a tap
It's a gesture
I also want to ask if there is a possibility to make Event extend Equatable and define it in the type-erase
Yes you just need to add the declaration
protocol Event: AnyEvent, Equatable {
associatedtype IntervalType: Interval
var interval: IntervalType { get }
func doSomething(param: IntervalType )
}
Now you are forcing every struct o class conform to Event to be Equatable.