使用 Kotlin 协程时 Room dao 类出错

问题描述 投票:0回答:11

我正在尝试通过here描述的方法使用kotlin协程访问房间数据库,添加插件和依赖项,并在gradle中启用kotlin协程。

gradle 文件中:

    kotlin {
    experimental {
        coroutines 'enable'
    }
}
dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:0.21" ...}

所以我为 dao 类中的所有方法添加了

suspend
关键字,如下所示:

道类

@Query("select * from myevent")
suspend fun all(): List<MyEvent>

@Delete
suspend fun deleteEvent(event: MyEvent)
...

并构建,然后出现这些错误

错误

e: C:\Users\projectpath\app\build\tmp\kapt3\stubs\debug\com\robyn\myapp\data\source\local\EventsDao.java:39: error: Deletion methods must either return void or return int (the number of deleted rows).
    public abstract java.lang.Object deleteEventById(@org.jetbrains.annotations.NotNull()
                                     ^
e: C:\Users\projectpath\app\build\tmp\kapt3\stubs\debug\com\robyn\myapp\data\source\local\EventsDao.java:41: error: Query method parameters should either be a type that can be converted into a database column or a List / Array that contains such type. You can consider adding a Type Adapter for this.
    kotlin.coroutines.experimental.Continuation<? super kotlin.Unit> p1);

错误链接导航到自动生成的 dao 类。现在,此类中生成的每个方法都有一个此类型的附加参数

Continuation
,如下所示:

自动生成dao类

@org.jetbrains.annotations.Nullable()
@android.arch.persistence.room.Delete()
public abstract java.lang.Object deleteAllEvents(@org.jetbrains.annotations.NotNull() // error indicates at this line
java.util.List<com.robyn.myapp.data.MyEvent> events, @org.jetbrains.annotations.NotNull()
kotlin.coroutines.experimental.Continuation<? super kotlin.Unit> p1); // error indicates at this line
...

我尝试删除生成的 dao 类并重建以重新生成它,仍然出现这些错误。我考虑不使用

lauch{}
方法,而是使用
suspend
关键字,因为代码中有很多地方可以查询数据库。

我该如何解决这个问题?

android kotlin coroutine android-room
11个回答
27
投票

您不能对 DAO 使用

suspend
方法。 在编译时处理的挂起函数,编译器会更改该函数的签名(不同的返回类型,状态机回调的附加参数)以使其非阻塞。

Room 等待特定的方法签名来生成代码。因此,在 Room 不直接支持协程之前,您无法对 DAO 使用挂起功能。

目前,您有这样的解决方法:

  1. 如果DAO方法返回值,使用RxJava或LiveData获取它并 使用 RxJava 协程适配器或为 LiveData 编写自己的协程适配器 (不知道现有的)
  2. 将同步 DAO 方法调用包装到 具有自己的线程池的协程(因为这样的调用会阻塞)。
但如果可能的话,总是更喜欢选项 1,因为 Room 已经提供了非阻塞 API,只需使用协程适配器即可允许将此 API 与协程一起使用而无需回调

Room 2.1.0-alpha03

 开始,DAO 方法现在可以是 
suspend
 函数。特别注释为@Insert、@Update 或@Delete 的Dao 方法可以是挂起函数。尽管普通查询支持,但注释为 @Query 的插入、更新和删除
尚不支持。有关更多详细信息,请参阅:架构组件发行说明功能请求


12
投票
其实是可以的,

您需要使用:

implementation "androidx.room:room-coroutines:${versions.room}"
您可以按照本教程进行操作:

https://medium.com/androiddevelopers/room-coroutines-422b786dc4c5

此外,对我有用的版本是:2.1.0-alpha04 所以,我的房间部门完全是:

implementation "androidx.room:room-runtime:2.1.0-alpha04" implementation "androidx.room:room-coroutines:2.1.0-alpha04" kapt "androidx.room:room-compiler:2.1.0-alpha04"
    

9
投票
我通过将我的 Room 版本更改为最新的稳定版本(截至撰写本文时为 2.3.0)来修复此问题,同时我当前的 Kotlin 版本是 1.5.10。

一般来说,如果仍然有错误,我建议您对依赖项使用最新的稳定版本。


8
投票
我有同样的错误,后来我发现我在 DAO 类方法中使用了

suspend 关键字:

@Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertCountry(country: Country) // here
转换为这个解决了我的问题:

@Insert(onConflict = OnConflictStrategy.REPLACE) fun insertCountry(country: Country)
    

2
投票
将房间版本更改为最新的稳定版本。

val room_version = "2.5.0"

对我有用。

我的错误是关于 Dao 和 Entity 类。


0
投票
在某些活动中,可能需要将 Room DB 代码行包装在 COROUTINE 中,如下面的代码所示。 (因为没有 COROUTINE 它会崩溃。)

// at an Activity: CoroutineScope(Dispatchers.Main).launch { rcAdapter.helper = helper rcAdapter.listData.addAll(helper?.roomDao()?.getAll() ?: listOf()) } // at Dao: suspend fun getAll(): List<Room>
在这种情况下,如果 Dao 中没有使用 suspend 方法,这个 Activity 就会崩溃。这意味着不可能摆脱协程或删除 suspend 方法。在这种情况下,如果您从 Dao 中删除 suspend 方法并将 Activity 的协程更改为以下内容,则可以正常工作。

// at an Activity: lifecycleScope.launch(Dispatchers.IO) { rcAdapter.helper = helper rcAdapter.listData.addAll(helper?.roomMemoDao()?.getAll() ?: listOf()) } // at Dao: fun getAll(): List<Room>
参见。 kotlin_version = '1.6.0' 和 room_version = "2.3.0"


0
投票
我通过将 room 升级到最新的稳定版本解决了这个问题。


0
投票
就我而言,我尝试降级 kotlin 版本

build.gradle 中的类路径“org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0”

这对我有用


0
投票
就我而言:使用最新版本“2.6.1”升级房间是可行的。

配置:

def room_version = "2.6.1" implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-ktx:$room_version" kapt "androidx.room:room-compiler:$room_version"
    

-1
投票
参数的类型必须是@Entity注解的类或其集合/数组。 kotlin.coroutines.Continuation

延续); ^


-1
投票
就我而言, 我刚刚将 room 升级到最新的稳定版本。 [def room_version = "X.X.X"] 我建议你使用最后一个稳定的稳定版本

© www.soinside.com 2019 - 2024. All rights reserved.