Olivier Patry
03/19/2021, 2:03 PMvectorXmlResource
but it fails with a NPE, form openResourceStream
. I guess my problem comes from my Gradle configuration not packaging my assets in the final Jar file but I don't know how to fix that. Any clue?
desktop-app/src/main/kotlin
for the source code, desktop-app/src/main/resources
for the assets. I put an icons/
dir within resources/
which contains my Android Vector drawables and then I use vectorXmlResource("icons/ic_settings.xml")
.desktop-app/build.gradle.kts
import org.jetbrains.compose.compose
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm")
id("org.jetbrains.compose")
application
}
group = "org.acme"
version = "1.0.0"
dependencies {
implementation(compose.desktop.currentOs)
}
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
application {
mainClass.set("MainKt")
}
resources/
dir as an assets directory)Igor Demin
03/19/2021, 4:39 PMOlivier Patry
03/19/2021, 5:22 PMModifier.size(48.dp)
make the crash easier but even without that, I have random crashes.
If Iaunch it several times in sequence…Modifier.size(48.dp)
Igor Demin
03/19/2021, 6:13 PMThread.currentThread().contextClassLoader
Maybe something somewhere overrides it?
Try to call this before `vectorXmlResource`:
Thread.currentThread().contextClassLoader = ClassLoader.getSystemClassLoader()
(just to be sure that this is because of contextClassLoader
)Olivier Patry
03/19/2021, 6:30 PMIgor Demin
03/19/2021, 6:44 PMI'm surprised, Compose runtime is multithreaded?It is single threaded for now, but there are plans to make it multi-threaded.
this as a bug on Compose side or should I manage this on my sideI think we can replace
Thread.currentThread().contextClassLoader
by ClassLoader.getSystemClassLoader()
in Compose (we just need to be sure that everything will work as before).
You also can manage this on your side, if somewhere in your code contextClassLoader
is changed. Usually we need to override contextClassLoader
only for some part of the code and then revert it:
val contextClassLoader = Thread.currentThread().contextClassLoader
try {
Thread.currentThread().contextClassLoader = ...
...
} finally {
Thread.currentThread().contextClassLoader = contextClassLoader
}
Things get complicated if some third-party library changes it and forgets to revert.Olivier Patry
03/19/2021, 7:07 PMExecutors.newSingleThreadExecutor()
but all of this is wrapped using suspendCoroutine {}
In other circumstances, such background tasks invokes callback on their thread which I delegate to a view model class which itself updates a MutableStateFlow
with MainScope
coroutine scope
private val viewModelScope: CoroutineScope = MainScope()
private val _collections = MutableStateFlow<LibraryState>(LibraryState.Unloaded)
val collections: Flow<LibraryState>
get() = _collections
.... something called from background ....
viewModelScope.launch(context = Dispatchers.Main) {
_collections.value = LibraryState.Updated(collectionModels)
}
....
Then, on compose side
val state by libraryViewModel.collections.collectAsState(LibraryState.Unloaded)
So maybe this setup leads to odd behavior?Try catch is not supported around composable function invocations.I'll do it another way
collectAsState
recomposition comes from a native library.
I know, on Android, there are some oddities with class loaders and JNI for threads created from native side.
Maybe it's something linked to this too on desktop?Igor Demin
03/20/2021, 10:13 AMMaybe it's something linked to this too on desktop?Yes, threads created from native side have no
contextClassLoader
.
Do you control the code which is called from native side?
You can call Thread.currentThread().contextClassLoader = ClassLoader.getSystemClassLoader()
there, not in Composable function.Olivier Patry
03/20/2021, 10:21 PMicon
helper, I'll do the trick here for now.
There are to much code being called from native callbacks right now.
Thanks 👍