使用 Kotlin 协程时 Room dao class 出错
Error with Room dao class when using Kotlin coroutines
我正在尝试通过 中描述的方法使用 kotlin 协程访问房间数据库,添加了插件和依赖项,并在 gradle 中启用了 kotlin 协程。
在gradle文件中:
kotlin {
experimental {
coroutines 'enable'
}
}
dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:0.21" ...}
所以我为dao class中的所有方法添加了suspend
关键字,像这样:
dao class
@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 class。这个 class 中生成的方法现在每个都有一个额外的这种类型的参数 Continuation
,如下所示:
自动生成 dao class
@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 class 并重建以重新生成它,仍然出现这些错误。我考虑不使用 lauch{}
方法,而是使用 suspend
关键字,因为代码中有很多地方可以查询数据库。
我该如何解决这个问题?
您不能对 DAO 使用 suspend
方法。
暂停在编译时处理的函数,编译器更改此函数的签名(不同 return 类型,状态机回调的附加参数)以使其成为非阻塞。
房间等待特定方法签名生成代码。因此,在 Room 不直接支持协程之前,您不能对 DAO 使用挂起功能。
目前,您有这样的解决方法:
- 如果DAO方法returns值,使用RxJava或LiveData获取它并
使用 coroutine adapter for RxJava 或为 LiveData 编写自己的
(不知道现有的)
- 将同步 DAO 方法调用包装到
具有自己的线程池的协程(因为这样的调用将被阻塞)。
但如果可能,总是首选选项 1,因为 Room 已经提供了非阻塞 API,只需使用协程适配器即可允许将此 API 与协程一起使用而无需回调
从 Room 2.1.0-alpha03
开始,DAO 方法现在可以是 suspend
函数。专门注释为@Insert、@Update 或@Delete 的 Dao 方法可以是挂起函数。注释为 @Query 的插入、更新和删除是 not yet supported although normal queries are. For further details see: Architecture Components Release Notes and Feature Request.
其实是可以的,
您需要使用:
implementation "androidx.room:room-coroutines:${versions.room}"
您可以按照本教程进行操作:https://medium.com/androiddevelopers/room-coroutines-422b786dc4c5
此外,对我有用的版本是:2.1.0-alpha04
所以,我的 Room deps 完全是:
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.3.0)来解决此问题,同时我当前的 Kotlin 版本是 1.5.10。
一般来说,如果你仍然有错误,我建议你为你的依赖使用最新的稳定版本。
我有同样的错误,后来我才知道我在我的 DAO class 方法中使用了 suspend 关键字:
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertCountry(country: Country) // here
转换成这个解决了我的问题:
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertCountry(country: Country)
在某些活动中,可能需要将 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 方法,这个 activity 就会崩溃。这意味着不可能摆脱协程或去除suspend方法。在这种情况下,如果您从 Dao 中删除挂起方法并将 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"
参数类型必须是用@Entity 注释的class 或它的collection/array。
kotlin.coroutines.Continuation 继续);
^
我正在尝试通过
在gradle文件中:
kotlin {
experimental {
coroutines 'enable'
}
}
dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:0.21" ...}
所以我为dao class中的所有方法添加了suspend
关键字,像这样:
dao class
@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 class。这个 class 中生成的方法现在每个都有一个额外的这种类型的参数 Continuation
,如下所示:
自动生成 dao class
@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 class 并重建以重新生成它,仍然出现这些错误。我考虑不使用 lauch{}
方法,而是使用 suspend
关键字,因为代码中有很多地方可以查询数据库。
我该如何解决这个问题?
您不能对 DAO 使用 suspend
方法。
暂停在编译时处理的函数,编译器更改此函数的签名(不同 return 类型,状态机回调的附加参数)以使其成为非阻塞。
房间等待特定方法签名生成代码。因此,在 Room 不直接支持协程之前,您不能对 DAO 使用挂起功能。
目前,您有这样的解决方法:
- 如果DAO方法returns值,使用RxJava或LiveData获取它并 使用 coroutine adapter for RxJava 或为 LiveData 编写自己的 (不知道现有的)
- 将同步 DAO 方法调用包装到 具有自己的线程池的协程(因为这样的调用将被阻塞)。
但如果可能,总是首选选项 1,因为 Room 已经提供了非阻塞 API,只需使用协程适配器即可允许将此 API 与协程一起使用而无需回调
从 Room 2.1.0-alpha03
开始,DAO 方法现在可以是 suspend
函数。专门注释为@Insert、@Update 或@Delete 的 Dao 方法可以是挂起函数。注释为 @Query 的插入、更新和删除是 not yet supported although normal queries are. For further details see: Architecture Components Release Notes and Feature Request.
其实是可以的,
您需要使用:
implementation "androidx.room:room-coroutines:${versions.room}"
您可以按照本教程进行操作:https://medium.com/androiddevelopers/room-coroutines-422b786dc4c5
此外,对我有用的版本是:2.1.0-alpha04 所以,我的 Room deps 完全是:
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.3.0)来解决此问题,同时我当前的 Kotlin 版本是 1.5.10。
一般来说,如果你仍然有错误,我建议你为你的依赖使用最新的稳定版本。
我有同样的错误,后来我才知道我在我的 DAO class 方法中使用了 suspend 关键字:
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertCountry(country: Country) // here
转换成这个解决了我的问题:
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertCountry(country: Country)
在某些活动中,可能需要将 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 方法,这个 activity 就会崩溃。这意味着不可能摆脱协程或去除suspend方法。在这种情况下,如果您从 Dao 中删除挂起方法并将 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"
参数类型必须是用@Entity 注释的class 或它的collection/array。 kotlin.coroutines.Continuation 继续); ^