Issue
I have added a new module to my project from File > New > New Module > Java or Kotlin Library. I set language as Kotlin and DSL as Kotlin DSL. However, my build.gradle
lists project as java-library
in plugins
. Here's my build.gradle:
plugins {
id("java-library")
id("org.jetbrains.kotlin.jvm")
// kotlin("jvm") // this is something I wanted to try
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
}
How should I go about making it a Kotlin library?
Some context: I didn't really need to make this change. But, recently, I have started seeing enum
warnings in my exhaustive when
statements stating following:
Enum argument can be null in Java, but exhaustive when contains no null branch
Since this enum is declared in new module (in a kotlin file using kotlin syntax), I think my current project is assuming that this module is a java-project and hence, the warning.
An answer, to this question, might also help me solve the issue with my LiveData treating variables from another module as null even after checking for nullability.
val result = response.data // CallResult is a class in another module
if (result == null) {
errors.emit(generalErrorOf(response.message))
return@launch
}
_someLiveData.value = result!!
Solution
You could update your build.gradle
file to properly configure your module as a Kotlin library, by replacing id("java-library")
with id("org.jetbrains.kotlin.jvm") version "<kotlin_version>"
, and including Kotlin standard library and any other Kotlin-specific dependencies:
plugins {
id("org.jetbrains.kotlin.jvm") version "<kotlin_version>"
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
}
kotlin {
sourceSets {
main {
kotlin.srcDirs("src/main/kotlin")
}
test {
kotlin.srcDirs("src/test/kotlin")
}
}
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
There is an optional kotlin
block to set source directories. The java
block is for compatibility settings.
Sync your Gradle files after making these changes.
Regarding the LiveData lint warning, try and Modify your ViewModel
to handle nullable MediaContent
:
private val _cropRequiredLiveData = SingleLiveEvent<MediaContent?>()
fun crop(): LiveData<MediaContent?> = _cropRequiredLiveData
private fun onDownloadComplete(content: MediaContent?) {
if (request.isCropEnabled && content != null) {
_cropRequiredLiveData.value = content
}
//
}
_cropRequiredLiveData
is declared as SingleLiveEvent<MediaContent?>
to accept nullable values. That change requires handling nullability in parts of your code where _cropRequiredLiveData
is observed.
Or: if you are confident that content
is non-null when assigning it to _cropRequiredLiveData
, you can use !!
after checking content != null
in the if
condition:
private fun onDownloadComplete(content: MediaContent?) {
if (request.isCropEnabled && content != null) {
_cropRequiredLiveData.value = content!!
}
//
}
Although, I updated the projects as you said, it didn't help me resolve both the issues.
But, to be fair, I found out that "Java Enum Nullability
" issue only happens when I observe anyenum
usingLiveData
(which is a java class), and not because theenum
class was declared in another module.
So the "Java Enum Nullability" issue surfaces when observing enums through LiveData
, which is indeed a Java class. That could be because of the way Kotlin and Java handle nullability differently, and how Kotlin interacts with Java code.
In Java, all non-primitive types can be null, including enums. When Kotlin interacts with Java types, it often treats them as nullable to maintain Java's nullability contract. That is likely why you are seeing warnings related to enum nullability when using LiveData
with enums.
To address this, when observing enums through LiveData
, explicitly check for null values even if it seems unnecessary in Kotlin. That approach ensures safety when dealing with potential nulls from Java classes.
myEnumLiveData.observe(this, Observer { enumValue ->
if (enumValue != null) {
// Handle non-null enum case
} else {
// Handle null case, even if it is unexpected in Kotlin
}
})
Another possible approach: create a custom wrapper for LiveData
that enforces non-null values. That can help bridge the gap between Kotlin's non-null types and LiveData's Java-based nullability.
class NonNullLiveData<T : Any>(private val liveData: LiveData<T?>) : LiveData<T>() {
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
liveData.observe(owner, Observer { it?.let(observer::onChanged) })
}
}
Use this wrapper to observe your enums, filtering out null values implicitly.
Or, you can also use Kotlin's safe calls (?.
) and the Elvis operator (?:
) when dealing with potentially nullable LiveData values.
myEnumLiveData.observe(this, Observer { enumValue ->
val safeEnumValue = enumValue ?: return@Observer // Handle or return on null
// Use safeEnumValue which is guaranteed non-null here
})
Answered By - VonC
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.