Android Room 将 Null 作为 Non-Null 类型返回

标签 android kotlin crash android-room kotlin-null-safety

我有 Dao 来返回简单的对象。如果对象不存在,Room 返回 null,但 Android 应用程序没有崩溃。此外,如果我将该值分配给非空变量,则应用程序不会崩溃。

道:

@Query("SELECT * FROM users WHERE id LIKE :id LIMIT 1")
abstract fun getById(id: Long): User

不崩溃的代码:

doAsync {
    val user: User = userDao.getById(999)   // user 999 not exist, userDao returns null
    uiThread {
        if (user == null) {
            Timber.d("user is $user")   // "user is null" in log
        } else {
            Timber.d("user is ${user.email}")
        }
    }
}

我有两个问题:

  1. Room 怎么可能将 Null 值作为 Non-Null 变量返回?
  2. 将 null 赋给 Non-Null 变量的代码怎么可能没有崩溃

最佳答案

这都是关于 Kotlin 如何处理 Java 代码边界上的空值。

如果您将 null 从 Java 传递给需要非空值的 Kotlin 方法,您将获得异常。这是通过调用 Kotlin 编译器在方法开头添加的 Intrinsics.checkNotNull 函数来实现的。

例如:

fun hello(who: String): Unit {
    println ("Hello $who")
}

成为

public final void hello(@NotNull String who) {
    Intrinsics.checkParameterIsNotNull(who, "who");
    String var2 = "Hello " + who;
    System.out.println(var2);
}

当您从 Kotlin 调用 Java 方法时添加了类似的检查。

但在你的情况下,你有 Kotlin 接口(interface),它是由 Room 生成的 Java 实现。 所以 Kotlin 编译器无法添加检查,因为它无法控制接口(interface)的所有实现。否则它必须在每次调用 Kotlin 类或接口(interface)后添加检查,因为它可以用 Java 实现,这对性能不利。

UPD:在 Room bugtracker https://issuetracker.google.com/issues/112323132 发现了类似的问题. Googler 说这是有意为之的行为,如果您编写了可以返回空值的查询,那么您有责任在 dao 接口(interface)中将其标记为可为空。

关于Android Room 将 Null 作为 Non-Null 类型返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53186937/

相关文章:

java - 如何区分字节数组和字符串

android - Kotlin 属性 : "Type parameter of a property must be used in its receiver type"

ios - 设置值 :forKey crash with _sigtramp

java - Android 应用程序在模拟器中启动时崩溃

android - AnimationDrawable.isRunning() 总是返回 true

android - 如何避免数组列表中的并发修改异常

android - 存储单元和 Espresso 测试的资源

java - 如何在android中创建圆角surfaceview

json - 在Kotlin中使用GSON解析JSON

python进程退出或崩溃毫无线索