我已经从File > New > New Module > Java or Kotlin Library向我的项目添加了一个新模块.我将语言设置为Kotlin,将DSL设置为Kotlin DSL.然而,我的build.gradle列出的项目是plugins中的java-library.这是我的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")
}

我应该如何着手将它打造成一座Kotlin 图书馆?


一些背景:我并不真的需要做出这样的改变.但是,最近,我开始在我详尽的when条声明中看到enum条警告,声明如下:

在Java中,枚举参数可以为空,但如果不包含空分支,则为穷举

由于此枚举是在新模块中声明的(在使用Kotlin语法的Kotlin文件中),我认为我当前的项目假定此模块是一个Java项目,因此出现了警告.


这个问题的答案也可能帮助我解决LiveData将来自另一个模块的变量视为空的问题,即使在判断是否为空之后也是如此.

val result = response.data // CallResult is a class in another module
if (result == null) {
    errors.emit(generalErrorOf(response.message))
    return@launch
}

_someLiveData.value = result!!

More info here

推荐答案

您可以更新build.gradle文件以将模块正确配置为Kotlin库,方法是替换id("java-library") with id("org.jetbrains.kotlin.jvm") version "<kotlin_version>",并包括Kotlin标准库和任何其他特定于Kotlin的依赖项:

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.


关于LiveData lint警告,try 修改您的ViewModel以处理可为空的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被声明为SingleLiveEvent<MediaContent?>以接受可为空的值.这一更改要求在观察到_cropRequiredLiveData的代码部分中处理为空性.

或者:如果将content赋值给_cropRequiredLiveData时确定content非空,则在if条件中勾选content != null后可以为use !!:

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 any enum using LiveData (which is a java class), and not because the enum class was declared in another module.

因此,当观察LiveData个枚举时,"Java Enum Nullability"问题浮出水面,这确实是一个Java类.这可能是因为Kotlin和Java处理空性的方式不同,以及Kotlin与Java代码交互的方式.

在Java中,所有非基元类型都可以为空,包括枚举.当Kotlin与Java类型交互时,为it often treats them as nullable以维护Java的可空性契约.这可能就是为什么在将LiveData与枚举一起使用时,您会看到与枚举为空性相关的警告.

为了解决这个问题,在观察枚举到LiveData时,显式判断null值,即使这在Kotlin中似乎是不必要的.这种方法确保了在处理来自Java类的潜在空值时的安全性.

myEnumLiveData.observe(this, Observer { enumValue ->
    if (enumValue != null) {
        // Handle non-null enum case
    } else {
        // Handle null case, even if it is unexpected in Kotlin
    }
})

另一种可能的方法是:为LiveData创建一个强制非空值的定制包装器.这可以帮助弥合Kotlin的非空类型和LiveData的基于Java的空性之间的差距.

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) })
    }
}

使用此包装器观察枚举,隐式过滤掉空值.

或者,在处理可能为空的LiveData值时,也可以使用Kotlin的safe calls (?.)Elvis operator (?:).

myEnumLiveData.observe(this, Observer { enumValue ->
    val safeEnumValue = enumValue ?: return@Observer // Handle or return on null
    // Use safeEnumValue which is guaranteed non-null here
})

Android相关问答推荐

Jetpack Compose中的导航找不到NavHost类的名称为:startDestination";的参数

Kotlin Android VS Kotlin多平台

SmsMessage如何在Kotlin库中工作?

在 kotlin 上向适配器添加绑定视图功能

为什么第二个代码可以安全地在 map 中进行网络调用,因为它已被缓存?

retrofit2.HttpException: HTTP 401

如何在每次显示可组合项时执行代码(并且只执行一次)

在 MVVM Jetpack Compose 上添加依赖项时出现重复类错误

Jetpack Compose with Paging 3 发出太多网络请求

列语义在列中的第一个元素之后读取

React Native Android 应用程序在调试模式下运行良好,但当我们发布 apk 时,它会生成旧版本的应用程序

安卓模拟器打不开

compose 导航参数字符串包含花括号?

找不到(包名称).在以下位置搜索:

将应用更改为暗模式后 Android MainActivity 数据泄漏

如何将设备屏幕位置转换为发送事件位置?

插入查询室 OnConflictStrategy.REPLACE

android 13 版本是否会影响 android 12 目标应用程序

Android Jetpack Compose - 找不到 R.drawable?

Android WebView 没有在第一次页面完成时从本地存储读取数据?