6

我刚刚开始研究 Room、Coroutines 和 Flow,并且遇到了一些奇怪的事情:我所期望的空流实际上有一个 null 项。

我的设置如下,T对我的实际实体具有通用性。

interface TDao {

    @Query("SELECT * FROM Table WHERE date=:date")
    fun getT(date: String): Flow<T>
}
@Singleton
class TRepository @Inject constructor(
    private val apiService: TApiService,
    private val Tdao: TDao
) {

    suspend fun getTFor(date: String): Flow<T> =
        Tdao
            .getT(date)
            .map {
                if (it == null) {
                    returnTFromDatabase()
                } else {
                    it
                }
            }

现在,当数据库中没有任何Tfordate时,我希望它返回一个空流,其中没有任何项目。相反,它有一个null元素,它永远不会发生,因为T它不能为空。

我为它写了这个测试:

@RunWith(AndroidJUnit4::class)
class TDatabaseTest {

    private lateinit var db: TDatabase
    private lateinit var underTest: TDao

    @Before
    fun setUp() {
        val context = InstrumentationRegistry.getInstrumentation().context
        db = Room.inMemoryDatabaseBuilder(context, TDatabase::class.java).build()
        underTest = db.TDao()
    }

    @After
    fun tearDown() {
        db.close()
    }

    @Test
    fun givenEmptyDatabase_thenHasNoItems() {
        runBlocking {
            val list = underTest.getT("1999").take(1).toList()
            assertEquals(1, list.size)
        }
    }
}

...它通过了,因为再次null返回了一件物品。

我错过了什么?这里有什么问题,因为我无法弄清楚。为什么我在具有不可为空元素的流中得到一个空元素?

4

2 回答 2

13

Room 是一个用 Java 编写的数据库,这就是它忽略 Kotlin 可选的原因。我建议声明总是查询返回类型,或者在你的情况下,Flow<T?>类型是可选的。如果您不想在流程中使用 null 类型,则可以使用filterNotNull()如下函数:

Tdao.getT(date).filterNotNull()
于 2020-03-07T10:13:41.503 回答
7

Room 如何处理可空性取决于您如何定义查询函数的返回类型。文档说:

  • 返回类型为Flow<T>时,查询空表会引发空指针异常
  • 当返回类型为Flow<T?>时,查询一个空表会发出一个null值。
  • 当返回类型为Flow<List<T>>时,查询一个空表会发出一个空列表

上面的代码段讨论了空表,但我假设相同的行为适用于任何不返回行的查询。

资料来源:关于查询的房间文档

于 2020-09-16T20:28:01.440 回答