【问题标题】:withContext(Dispatchers.IO) how to use for roomwithContext(Dispatchers.IO) 如何使用房间
【发布时间】:2021-03-30 06:01:13
【问题描述】:

在我们的应用程序中有很多查询,现在我们正在使用 ROOM,我想确认在我们这样使用之前使用 Coroutine 的正确方法是什么

在道

  @Query("SELECT * FROM VISITS")
    suspend fun getAllVisits(): List<Visits>

我们正在变成这样

fun getAll(visit: Visits?) = runBlocking {
        Log.i(TAG, "addOrUpdateRecord")
        try {

val list = ArrayList<Visits>()
                list.addAll(async {
                    visitsDao.getAllVisits()
                }.await())

}

但是在一些文章中我读到运行阻塞仅用于测试而不是生产请指导我正确的方式谢谢

【问题讨论】:

标签: android kotlin android-room kotlin-coroutines


【解决方案1】:

如果您需要一个协程范围来启动一个协程,您可以根据需要使用lifecycleScopeviewModelScope

在 Activity 内部:

fun myMethod() {
    lifecycleScope.launch {
        val list = visitsDao.getAllVisits()
        //Do something with list here
            ...
    }
}

片段内部:

fun myMethod() {
    viewLifecycleOwner.lifecycleScope.launch {
        val list = visitsDao.getAllVisits()
        //Do something with list here
            ...
    }
}

在 ViewModel 中:

fun myMethod() {
    viewModelScope.launch {
        val list = visitsDao.getAllVisits()
        //Do something with list here
        ...
    }
}

在普通班级内:

class MyPresenter: CoroutineScope {
    private val myJob = Job()
    override val coroutineContext: CoroutineContext
        get() = Dispatchers.Default + myJob
    
    ...

    fun myMethod() {
        launch {
            val list = visitsDao.getAllVisits()
            //Do something with list here
            ...
        }
    }
    
    ...

    //Call clear when required
    fun clear() {
        this.myJob.cancel()
    }
}

【讨论】:

  • 我们的设计模式是MVP,我还能用这个方法吗?
  • @bakhtiyarhussain 你可以像这样在你的 Presenter 中实现CoroutineScopeclass MyPresenter: CoroutineScope by MainScope(){ ... }。根据您的需要使用正确的 Dispatcher 或自行构建其 CoroutineContext 而无需委托。请注意正确取消其范围。
  • 如果我像您在 tableHelperClass 中的 Presenter 中那样实现 CoroutineScope 并在运行我的查询时使用 launch(Dispatchers.IO) 是一种好习惯吗?
  • @bakhtiyarhussain 如果您将 suspend 关键字添加到您的 DAO 方法,您不必担心发出调用的调度程序。 Room 将在后台线程上执行查询。
  • 所以我只需要使用启动?这是我提到的正确方法吗?
【解决方案2】:

你可以使用这样的东西

GlobalScope.launch { 
            withContext(Dispatchers.IO){
                // your query
            }
        }

【讨论】:

  • 基于@Chirag Rayani 的回答,如果您使用的是viewModel,则可以使用viewModelScope.launch{ withContext(dispatchers.IO)} 并将其与livedata.postValue() 结合使用
  • 如果您使用 viewModelScope 并假设您正在更新 db 中的单行,并且在更新行之前切换到另一个活动,那么您可能会遇到异常或数据可能不会在 db 中更新。所以我认为最好使用 GlobalScope @Yehezkiel L
  • 当 viewModel 附加到活动或片段生命周期时,它仍然可以 cmiiw
  • GlobalScope 不是一个好习惯,即使我们关闭应用程序,GlobalScope 也不会自动终止,这就是我不使用它的原因
【解决方案3】:

在视图模型中:

viewmodelScope.launch(Dispatchers.IO){
  visitsDao.getAllVisits()
}

或者另一个挂起函数

suspend fun addAll() {
    visitsDao.getAllVisits().run{
     ArrayList<Visits>().addAll(this)

   }
}

甚至更多,只需使用流,您可以使用 livedata builder/map/asLiveData 等。

【讨论】:

  • 是的,我已经看到了。这是我的结果,不推荐运行阻塞。检查link。 " 调用 runBlocking 的主线程会阻塞,直到 runBlocking 中的协程完成。"如果您没有 ViewModel,只需使用 MainScope(),当视图被销毁时,它可能会被取消。您可以创建自己的,只需使用 SupervisorJob() + Dispatchers.Main
  • 顺便说一句,在 Google 创建 viewModelScope 和生命周期范围之前,我习惯使用 MainScope。检查kotlinx.coroutines/-main-scope
猜你喜欢
  • 2023-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多