【问题标题】:Migrating from RxJava2 to Kotlin Coroutines从 RxJava2 迁移到 Kotlin 协程
【发布时间】:2019-11-28 10:41:59
【问题描述】:

我正在尝试将我的代码从 RxJava2 迁移到 Coroutines。但我不确定如何实现。

例如,这是我将代码插入房间数据库的旧代码:

fun insert(note: Note) = Single.fromCallable {
        dao.insert(note)
    }.subscribeIn({ id ->
        note.id = id
        if (note.bitmap != null) update(note)
    }

注意:这段代码在一个名为DataHelper的对象中,它包含了所有的方法和Dao对象。

这是道召:

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(note: Note): Long

尝试用协程调用替换该代码尚不清楚,因为我无法从主线程调用挂起函数。

fun insert(note: Note) {
        val id = withContext(Dispatchers.IO) {
            dao.insert(note)
        }
        note.id = id
        if (note.bitmap != null) update(note)
    }

dao.insert() 现在是 Dao 中的挂起函数。

insert(Note) 函数设为挂起函数意味着我必须使用 Dispatcher 从任何地方(例如,片段)调用它。这要么意味着每个片段或活动中必须有一个 Dispatcher,要么意味着暂停整个调用线。

使用 Coroutines 运行后台线程的正确方法是什么?

【问题讨论】:

  • 如果您不想在每个 activity/fragment 中创建 CoroutineContext,然后使用 GlobalScope 在 insert 方法中调用您的函数,尽管这样做不是最佳实践做。

标签: android kotlin rx-java2 kotlin-coroutines


【解决方案1】:

您可以在 Room Dao 中使用暂停功能:

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(note: Note): Long

无论何时你想访问/调用这个 Dao 方法,你都需要CoroutineScope 来做到这一点。

方法一使用GlobalScope:

GlobalScope.launch(Dispatchers.IO) {
    dao.insert(note)
    withContext(Dispatchers.Main){
     // main thread calls here, e.g. updating view, showing toast, etc
    }
}

方法二创建CoroutineScope

val job = SupervisorJob()
val scope = CoroutineScope(Dispatchers.IO + job)

scope.launch {
    dao.insert(note)
    withContext(Dispatchers.Main){
     // main thread calls here, e.g. updating view, showing toast, etc
    }
}

注意:当您的实例(例如 Activity/Fragment)被销毁时,您 可以致电:job.cancel() 取消您的协程作业。

方法3:你可以用CoroutineScope扩展你的类:

class MainActivity : AppCompatActivity(), CoroutineScope {
    override val coroutineContext: CoroutineContext = Dispatchers.IO + SupervisorJob()

    ....

    fun onSomeAction() {
        launch {
            dao.insert(note)
            withContext(Dispatchers.Main) {
                // main thread actions
            }
        }
    }
}

如果您使用ViewModel 来调用dao 方法,那么您可以使用viewModelScope 扩展:

viewModelScope.launch(Dispatchers.IO) {
    dao.insert(note)
    withContext(Dispatchers.Main){
     // main thread calls here, e.g. updating view, showing toast, etc
    }
}

与其他选项不同,当调用ViewModelonCleared() 方法时,viewModelScope 将被自动取消。

要使用此选项,您需要将此依赖项包含在您的 app 级别 build.gradle 文件中:

implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-alpha01"

【讨论】:

【解决方案2】:

在你的例子中,有趣的插入应该是一个挂起函数:

suspend fun insert(note: Note) {
        withContext(Dispatchers.IO) {
            dao.insert(note)
        }
        //note.id = id
        //if (note.bitmap != null) update(note)
    }

然后从您的 ViewModel 中使用 viewModelScope:

viewModelScope.launch {
            noteRepository.createNote(note)
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-27
    • 1970-01-01
    • 1970-01-01
    • 2018-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多