JavaFX + Kotlin coroutine without android OS, is it possible? - kotlin

I have a runnable jar that has a UI made with javafx fxml and the class code in kotlin with some database operations done with spring jpa.
Everything works great, except that I would like to not block the main thread while doing the work. Coming from C# I saw that in kotlin you can use coroutine like async await.
import javafx.fxml.FXML
import javafx.scene.control.Button
import kotlinx.coroutines.*
class appGui{
#FXML
private var buttonExecute: Button? = null
#FXML
fun buttonExecuteClick() {
buttonExecute!!.isDisable = true
CoroutineScope(Dispatchers.Main).launch {
withContext(Dispatchers.IO){
work()
}
buttonExecute!!.isDisable = false
}
}
private suspend fun work() {
println("corotine starting...")
delay(5000);
//springMain.applyChanges()
println("corotine finished...")
}
}
So I have added the coroutine call, but I got an exception Module with the Main dispatcher is missing. Add dependency providing the Main dispatcher
Looking at this exception, I found that you have to import the coroutines-android instead of the core, so I change my pom to it
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-android</artifactId>
<version>1.4.2</version>
</dependency>
which cause other exception ClassNotFoundException: android.os.Looper
Now I'm confused, is the coroutine intended to be used in android app? I'm running a jar on windows. Or do I need to go back to runnable task and do things like it was done in swing?

Thank to mipa (comment) for the tip.
just change the pom to import the javafx instead android.
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-coroutines-javafx</artifactId>
<version>1.4.2</version>
</dependency>
simple and easy.
There is 3 main imports in the doc right now https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md
kotlinx-coroutines-android -- Dispatchers.Main context for Android applications.
kotlinx-coroutines-javafx -- Dispatchers.JavaFx context for JavaFX UI
applications.
kotlinx-coroutines-swing -- Dispatchers.Swing context for Swing UI applications.
I just need to use the right one

Related

Why launching my coroutine fails to find a class kotlin.Random?

This worked for me in the past:
CoroutineScope(Dispatchers.IO).launch { ...
as well as this:
GlobalScope.launch { ...
I am trying to build a SpringBoot app with Kotlin 1.6.10. and these commands blow up as follows:
Could not initialize class kotlin.random.Random
kotlin/internal/jdk7/JDK7PlatformImplementations
this app definitely uses Java 11, so the reference to jdk7 is a surprise as well. Can someone explain what is going on?
Here are the dependencies
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core") {
version {
strictly("1.6.1")
}
}
TIA
Edit: we do not use Random at all, but we added code to invoke it, and it works.

Dealing with R8 + JvmStatic Annotation + Lambda in public API for Android Library written in Kotlin

First of all, please note that I'm not expecting why do you want to obfuscate library comments. This is a genuine problem I'm asking about.
I have been having an issue dealing with R8/obfuscation with an Android library written in Kotlin.
I've a public API method which is annotated with #JvmStatic and that method takes a Lambda as parameter.
For example, take a look at code below,
typealias MyLambdaCallback = (String, Map<String, Any>) -> Unit
#Keep
object MyApi {
private var callback: MyLambdaCallback? = null
#JvmStatic
fun setCallback(callback: MyLambdaCallback) {
this.callback = callback
}
}
I have added #Jvmstatic so that Java calling code can call the method statically rather than doing MyApi.INSTANCE.setCallback()
When I release the library without minification, everything is fine and calling code from both Java and Kotlin is written as expected.
But now I want to release the library while turning on minification.
That creates an issue.
Here is the error
java.lang.IncompatibleClassChangeError: The method 'void setCallback(kotlin.jvm.functions.Function2)' was expected to be of type virtual but instead was found to be of type static (declaration of 'com.demo.basic.Application' appears in /data/app/com.demo.basic-_0uJXPbtfs3UZ2Rp2h-RdQ==/base.apk!classes2.dex)
Am I making a mistake somewhere or this is expected as some kind of limitation ?
What did I Try ?
Removing #Jvmstatic resolves the issue but it created ugly Java calling code
Kept #Jvmstatic but removed Lambda converting Lambda into an interface with one method and everything is working fine. Unfortunately SAM for Kotlin classes is not there yet, so calling Kotlin code looks ugly.
This is tracked on the R8 issue tracker http://issuetracker.google.com/158393309 which has more details.
The short story is that this has been fixed in R8 version 2.1.35, which can be used by making the following changes to the top level build.gradle file:
repositories {
maven {
url 'https://storage.googleapis.com/r8-releases/raw'
}
}
dependencies {
classpath 'com.android.tools:r8:2.1.35' // Must be before the Gradle Plugin for Android.
classpath 'com.android.tools.build:gradle:X.Y.Z' // Your current AGP version.
}
R8 team has fixed this issue along with related issue b/158400283 in R8 version 2.1.42
Fix should already be available in Android Studio 4.1 beta or higher, but if you're using stable Android Studio 4.0 then add following to your top-level build.gradle file:
buildscript {
repositories {
maven {
url 'https://storage.googleapis.com/r8-releases/raw'
}
}
dependencies {
classpath 'com.android.tools:r8:2.1.42' // Must be before the Gradle Plugin for Android.
classpath 'com.android.tools.build:gradle:X.Y.Z' // Your current AGP version.
}
}

Check for dependencies update with kotlin-dsl

This question has already been asked before, however the solution is still unknown... Kotlin DSL build scripts dependency updates
With the new implementation of kotlin-dsl. Now the imports looks like this.
implementation Koin.core
implementation Koin.android
and the buildSrc.
object Versions{
const val koin = "2.0.1"
}
object Koin {
val core = "org.koin:koin-core:${Versions.koin}"
val android = "org.koin:koin-android:${Versions.koin}"
val scope = "org.koin:koin-androidx-scope:${Versions.koin}"
val viewModel = "org.koin:koin-androidx-viewmodel:${Versions.koin}"
val extension = "org.koin:koin-androidx-ext:${Versions.koin}"
val test = "org.koin:koin-test:${Versions.koin}"
}
in this case Koin is using a previous version, but i know that there's a new version https://github.com/InsertKoinIO/koin
anyone knows how to check if the dependencies has a newer version with kotlin-dsl?
I've tested this Gradle Dependencies Update Check Plugin on my Android/Kotlin DSL build (with a separate Versions class with versions definitions) and it works fine for me:
CheckDependencyUpdates Gradle Plugin
(I've also tested that it works with a traditional Groovy-DSL project)
To install the plugin (copied from linked page) add the following to your build.gradle.kts. Note that I've removed the version number from this as it will, unlike the page I've linked to, get out of date:
plugins {
id("name.remal.check-dependency-updates")
}
To run the update check (copied from gradle tasks) run the following:
gradle checkDependencyUpdates
You will see an output section similar to the following:
New dependency version: com.android.tools.build:aapt2: 3.6.1-6040484 -> 3.6.3-6040484
New dependency version: com.android.tools.lint:lint-gradle: 26.6.1 -> 26.6.3
I made this plugin. Dependency Updates Commenter.
Just apply plugin and add annotation to the dependency properties and execute commentDependencyUpdates task. This is the example:
object Junit {
const val junit = "junit:junit:4.12"
}
import io.github.zeroarst.dependencyupdatescommenter.CommentUpdates
object Junit {
// Available versions:
// 4.13-rc-2
// 4.13-rc-1
// 4.13-beta-3
// 4.13-beta-2
// 4.13-beta-1
#CommentUpdates
const val junit = "junit:junit:4.12"
}

Cucumber, Java8: find usage of step defined by lambda expression

Currently in our project's tests we switched from using annotated step definitions, e.g.:
public class Steps {
#Given("^Step name$")
void methodName() {
// do sth
}
}
to lambda expressions:
public class Steps implements En {
public Steps() {
Given("^Step name$", () ->
// do sth
);
}
}
When using Intellij Cucumber Java plugin it was easy to find the usage of some step, since it looked for usages of the annotated method (I presume).
Now however, we have to manually search for the regex passed as the argument.
My first question is: is there a neat way to do this with lambda expressions?
Moreover: when using Intellij's tool for version control and commiting files containing definitions of big numbers of steps, the code analysis tool goes on forever (I guess it is because of the constructor having to crank a lot of code).
So the second question is: since there is no possibility of the step library shrinking and step usage search is used very often wouldn't it be a good idea to switch back to Ye Olde Way i.e. using annotated methods?
Find usages for java-8 style step definitions do not yet work. One can vote and follow this request: IDEA-144648.
It is working here while using
IntelliJ IDEA 2018.1.5
'Cucumber for Java' plugin 181.5281.24
pom.xml
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<version.cucumber>3.0.2</version.cucumber>
<!-- following versions were also checked -->
<!--<version.cucumber>2.4.0</version.cucumber>-->
<!--<version.cucumber>2.3.1</version.cucumber>-->
</properties>
<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java8</artifactId>
<version>${version.cucumber}</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>${version.cucumber}</version>
<scope>test</scope>
</dependency>
</dependencies>
userdata.feature
Feature: demo for java8 glue classes
Scenario: user login on home page
Given user is on home page
When user navigate to login page
And user enters credentials to login
Then message displayed login successfully
glue/StepPojo.java
package glue;
import cucumber.api.PendingException;
import cucumber.api.java8.En;
public class StepPojo implements En {
public StepPojo() {
Given("^User is on Home Page$", () -> {
throw new PendingException();
});
When("^User Navigate to LogIn Page$", () -> {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
});
And("^User enters Credentials to LogIn$", () -> {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
});
Then("^Message displayed Login Successfully$", () -> {
// Write code here that turns the phrase above into concrete actions
throw new PendingException();
});
}
}
The class StepPojo.java was created by the Cucumber plugin by pressing ALT+ENTER while selecting a step in the feature file.
The feature file was shown before as
after the steps are defined as
[
when you hover with the mouse over a step while pressing down the CTRL key it looks as
when you click on a step while pressing down the CTRL key you jump to the respective method, e.g.
Given("^User is on Home Page$", () -> {
throw new PendingException();
});

What can I do to make the Headless JS service run in foreground in android?

I went through official documentation of the React Native Headless JS. In the caveats, It is mentioned that if the app will try to run the task in foreground, the app will crash.It is also mentioned that there is a way around this.Please suggest a way so that I can have heavy tasks done in an another thread other than the UI thread using Headless JS when the app is in the foreground.
It worked for me to use the HeadlessJsTaskService, even when started from a currently active Activity. Did you try it and it crashed?
Edit
I had a look at their implementation.
Your app will crash under the following conditions:
if (reactContext.getLifecycleState() == LifecycleState.RESUMED &&
!taskConfig.isAllowedInForeground()) { //crash }
(see ReactContext)
This means that you can configure the HeadlessJsTaskConfig within your HeadlessJsTaskService with a true for allowedInForeground.
E.g.
#Override
#Nullable
protected HeadlessJsTaskConfig getTaskConfig(Intent intent) {
Bundle extras = intent.getExtras();
WritableMap data = extras != null ? Arguments.fromBundle(extras) : null;
return new HeadlessJsTaskConfig(
"FeatureExecutor",
data,
5000,
true /* Don't crash when running in foreground */);
}
But in my test-case this step was not necessary, even when displaying a ReactRootView. I think the reason for that is, that the ReactRootView had its own ReactContext (which might not be a good idea).
For your implementation you should consider the following when using Headless JS:
allowedInForeground whether to allow this task to run while the app is in the foreground (i.e. there is a host in resumed mode for the current ReactContext). Only set this to true if you really need it. Note that tasks run in the same JS thread as UI code, so doing expensiveoperations would degrade user experience.
(see HeadlessJsTaskConfig.java)