使用Kotlin协程时,Room dao类出现错误

14

我正在尝试使用Kotlin协程通过这里描述的方法访问Room数据库,我已添加插件和依赖项,并在gradle中启用了Kotlin协程。

gradle文件中:

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

所以我为dao类中的所有方法添加了 suspend 关键字,例如:

dao类

@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: 错误: 删除方法必须返回void或返回int(被删除的行数)。 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: 错误: 查询方法参数应该是可以转换为数据库列的类型,或者是一个包含这种类型的List / Array。您可以考虑为此添加类型适配器。 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关键字,因为代码中有许多地方需要查询数据库。

我该如何解决这个问题?

10个回答

26
你不能在DAO中使用suspend方法。suspend函数在编译时处理,编译器会更改该函数的签名(不同的返回类型,用于状态机回调的额外参数),使其成为非阻塞函数。
Room等待特定的方法签名生成代码。因此,在Room不直接支持协程之前,您不能在DAO中使用suspend函数。
目前,您可以采用以下解决方法:
  1. 如果DAO方法返回值,请使用RxJava或LiveData获取它,并使用RxJava的协程适配器或为LiveData编写自己的适配器(不知道是否存在现有适配器)。
  2. 将同步DAO方法调用包装到协程中的自有线程池中(因为这样的调用将是阻塞的)。
但始终优先选择选项1(如果可能的话),因为Room已经提供了非阻塞API,只需使用协程适配器即可允许使用此API与协程而无需回调。
截至Room 2.1.0-alpha03版本,DAO方法现在可以是suspend函数。具体注释为@Insert、@Update或@Delete的Dao方法可以是suspend函数。尽管正常查询已支持,但标记为@Query的插入、更新和删除尚不支持。有关详细信息,请参见:架构组件发行说明功能请求

你在使用 Room 2.1.0-alpha3/4 的 ViewModel/Repository 中是否使用任何协程“模式”? - Jan Veselý
有时候,小细节就是答案。 - Samir
你已经有了答案,但是有人编辑了你的答案,所以它看起来不正确。实际上,我看到了alpha,所以继续前进,我需要更稳定的东西。 - danny117

12

实际上是有可能的,

你需要使用:

implementation "androidx.room:room-coroutines:${versions.room}"

你可以跟随这个教程:https://medium.com/androiddevelopers/room-coroutines-422b786dc4c5

另外,对我而言可行的版本是:2.1.0-alpha04, 所以,我的 Room 依赖项完全是:

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"

我之前用的是2.2.6版本,但它无法正常工作。更新到2.3.0版本后问题得到了解决。 - M. Reza Nasirloo

9

我通过将我的Room版本更改为最新稳定版(截至撰写本文时,为2.3.0),解决了这个问题,同时我的当前Kotlin版本是1.5.10。

通常,如果您仍然有错误,请使用最新的稳定版本作为依赖项。


6

我遇到了同样的错误,后来发现我在DAO类的方法中使用了suspend关键字:

@Insert(onConflict = OnConflictStrategy.REPLACE)

suspend fun insertCountry(country: Country) // here

将其转换为以下内容解决了我的问题:

@Insert(onConflict = OnConflictStrategy.REPLACE)

fun insertCountry(country: Country)

1
这实际上看起来像是一个答案,而不是那种费力的版本控制。只能有一个挂起,我希望它比DAO接口更远的上游。 - danny117

2

将房间版本更改为最新稳定版本。

val room_version = "2.5.0" 对我有效。

我的错误与 Dao 和 Entity 类有关。


0
在我的情况下,我尝试了降级 Kotlin 版本。
在 build.gradle 中加入 classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0'。
这对我起作用了。

0

我通过将Room升级到最新的稳定版本来解决了这个问题。


这并没有回答问题。虽然你可能遇到了相同的问题,但是OP遇到问题是因为在DAO中使用了suspended函数。解决问题的答案在这里。您可以参考它。 - Abhishek Dutt

0
在某些活动中,可能需要将 Room DB 代码的行包装在协程中,如下所示的代码。(因为没有协程会崩溃。)
// 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方法,那么此活动将崩溃。这意味着无法摆脱协程或删除suspend方法。在这种情况下,如果您从Dao中删除suspend方法并将活动的协程更改为以下内容,则可以正常工作。
// 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"


-1
在我的情况下,我只是将Room升级到最新的稳定版本。 [def room_version = "X.X.X"] 我建议您使用最新的稳定版本。

-1

参数的类型必须是一个带有@Entity注解的类或其集合/数组。 kotlin.coroutines.Continuation<? super kotlin.Unit> continuation); ^


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接