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

时间:2018-11-07 09:46:25

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

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

道:

@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变量的代码怎么可能没有崩溃

3 个答案:

答案 0 :(得分:4)

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

如果您将Java中的null传递给需要非null值的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接口,它是由Room生成的Java实现。 因此Kotlin编译器无法添加检查,因为它无法控制所有接口实现。否则,每次调用Kotlin类或接口后,都必须添加检查,因为它可以用Java实现,这对性能不利。

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

答案 1 :(得分:1)

据我了解,您生成的Dao类并未将返回值注释为Java代码中的@Nullable。

@Override
public User getById(long id) {

应该是

@Override
public @Nullable User getById(long id) {

因此您看不到警告

答案 2 :(得分:1)

您没有得到NullPointerException的原因很简单:Room是Java库而不是Kotlin,因此不知道您的User不应为null。 当与Java代码进行交互时,Kotlin引入了一些空检查来为您提供该异常,但是由于您的界面是用Kotlin编写的,因此它假定这不会出现问题,并且会跳过该检查。

我不是会议室专家,但是经过Google的快速搜索之后,我找不到强迫会议室检查空值的方法。我看到两种解决您的“问题”的方法:

  • 更改getById函数以返回User?
  • @Dao转换为Java接口,迫使Kotlin检查是否为空。