从 RxJava2 迁移到 Kotlin 协程

Migrating from RxJava2 to Kotlin Coroutines

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

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

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

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

这是 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,要么 activity,或者暂停整个调用行。

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

在你的例子中,fun insert 应该是一个挂起函数:

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)
        }

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

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

无论什么时候你想access/call这个Dao方法,你都需要CoroutineScope去做。

方法 1 使用 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
    }
}

Note: When your instance (e.g. Activity/Fragment) is destroyed, you can call: job.cancel() to cancel your coroutine jobs.

方法 3:您可以使用 CoroutineScope:

扩展您的 class
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
    }
}

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

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

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