Vai*_*gal 6 sqlite android kotlin android-room
最初,我直接访问了一个 viewModel 函数,该函数为我正在运行的查询启动了一个 viewModel 作用域协程。那有同样的错误。
然后,我将 viewModel 函数更改为挂起函数,并从片段中的协程调用它。那也没用。
因此,我使得该函数在协程内调用,然后在 viewModel 范围内运行另一个协程。这给出了相同的结果。
我认为在片段创建期间调用它可能负载太大。所以我尝试使用按钮 onclick 侦听器调用 viewModel 函数。再次坠毁。
我在数据库检查器中运行了相同的查询,它运行良好。所以,查询也不是问题。
在下面的屏幕截图中,我包含了有关该问题的所有必要细节。只需关注突出显示的内容即可。从传递列表片段(左上角选项卡)开始。从那里,调用右上角选项卡中的 viewModel 函数。从那里开始,DAO 就在它的正下方。然后是它下面的数据类。
viewModel 函数 -
fun resetAllAccess(){
viewModelScope.launch {
passwordDao.resetAccessForAll()
}
}
Run Code Online (Sandbox Code Playgroud)
DAO 功能 -
@Query("UPDATE password_data SET access = 0 WHERE access = 1")
fun resetAccessForAll()
Run Code Online (Sandbox Code Playgroud)
数据库的数据类 -
@Entity(tableName = "password_data")
data class PasswordData(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
@ColumnInfo(name = "service_name") var serviceName: String,
@ColumnInfo(name = "service_password") var servicePassword: String,
@ColumnInfo(name = "is_an_application") var isAnApplication: Boolean = false,
@ColumnInfo(name = "use_finger_print") var useFingerPrint: Boolean = true,
@ColumnInfo(name = "access") var access: Boolean = false
)
Run Code Online (Sandbox Code Playgroud)
从片段发出的呼叫 -
CoroutineScope(Dispatchers.IO).launch { viewModel.resetAllAccess() }
Run Code Online (Sandbox Code Playgroud)
Vai*_*gal 21
我替换了这个功能 -
fun resetAllAccess(){
viewModelScope.launch {
passwordDao.resetAccessForAll()
}
}
Run Code Online (Sandbox Code Playgroud)
-和
fun resetAllAccess(){
CoroutineScope(Dispatchers.IO).launch {
passwordDao.resetAccessForAll()
}
}
Run Code Online (Sandbox Code Playgroud)
所以现在,它不再在主线程上运行。
这是因为您正在使用viewModelScope. 很多人不知道这一点,但viewModelScope实际上是硬编码为使用主线程而不是另一个线程。
您可以在Google 官方文档中找到此信息:
注意:ViewModel 类的 viewModelScope 属性被硬编码到 Dispatchers.Main。在测试中使用 Dispatchers.setMain 和 TestCoroutineDispatcher 来替换它,如 Android 中的 Easy coroutines: viewModelScope 博客文章中所述。
因此,您可能想要将协程范围传递到视图模型类构造函数(首选方式)或直接在视图模型中创建一个。那么你应该用它来启动协程。
另一种常用的做法是创建一个包含视图模型和自定义范围(通过视图模型构造函数传递)的范围。
例如:
class ViewModelClass(customCoroutineScope: CoroutineScope): ViewModel {
private val backgroundScope: CoroutineContext = customCoroutineScope.coroutineContext + viewModelScope.coroutineContext
fun resetAllAccess(){
backgroundScope.launch {
passwordDao.resetAccessForAll()
}
}
}
Run Code Online (Sandbox Code Playgroud)
您还可以在此处找到有关viewModelScope幕后工作原理的更多信息。
还有另一种选择,但我根本不建议这样做,原因很明显,那就是允许 Room 通过使用Room 构建器中的allowMainThreadQueries在主线程中运行查询。
| 归档时间: |
|
| 查看次数: |
12018 次 |
| 最近记录: |