了解coroutineScope

时间:2020-06-27 10:01:47

标签: android scope android-context coroutine kotlin-coroutines

假设在VM内使用viewModelScope启动了一个新协程,并在通用存储库类内调用了一个非暂停函数

UserViewModel

viewModelScope.launch(context = Dispatchers.IO) {

                _user.value?.id?.let { id ->
                    val dataSaved = userRepository.setUserData(id, newUser)

                }

}

UserRepository

fun setUserData(id: String, data: User): Boolean {
        return try {
            val saveTask = db.collection(COLLECTION).document(id).set(data)
            Tasks.await(saveTask)
            true
        } catch (e: Throwable) {
            false
        }
}
  1. 启动setUserData的范围和上下文是什么?
  2. 如果我在suspend函数之前添加了setUserData键盘,则await的{​​{1}}方法将生成警告Tasks。为什么?
  3. 此实现有什么区别?
Inappropriate blocking method call
  1. suspend fun setUserData(id: String, data: User): Boolean { return coroutineScope { return@coroutineScope try { val saveTask = db.collection(COLLECTION).document(id).set(data) Tasks.await(saveTask) true } catch (e: Throwable) { e.printStackTrace() Log.e(TAG, "${e.message}") false } } } 是否可以保证在呼叫者的相同范围和上下文中启动coroutineScope

1 个答案:

答案 0 :(得分:0)

启动setUserData的范围和上下文是什么?

viewModelScope.launch(context = Dispatchers.IO)来看,上下文看起来像CoroutineScope(SupervisorJob() + Dispatchers.IO)

如果我在suspend函数之前添加了setUserData键盘,则await的{​​{1}}方法将生成警告Tasks。为什么?

除非在调度程序中支持,否则在挂起函数中阻塞线程(使用Inappropriate blocking method call)是不好的做法。即Tasks.await

IntelliJ / Android Studio不够聪明(而且可能不够聪明),无法准确确定您是否在不应该这样做的时候进行阻止。因此,这可以被认为是一个错误,但是可以在Dispatchers.IO之外调用setUserData,因此IntelliJ有一个要点。

此实现有什么区别?

真的不多。只是有一些额外的开销是不值得的。

作为旁注,Dispatchers.IO不会像coroutineScope那样更改直接coroutineContext,但会更改已启动协程的继承上下文。

withContext是否可以保证在呼叫者的相同范围和上下文中启动coroutineScope

您已经获得此保证。您不需要setUserData即可实现。

您可能想要的是这个。

coroutineScope

然后,调用方不必担心要使用哪个调度程序或上下文。

您应该使用的是这个。

suspend fun setUserData(id: String, data: User): Boolean {
    val saveTask = db.collection(COLLECTION).document(id).set(data)
    return withContext(Dispatchers.IO) {
        try {
            Tasks.await(saveTask)
            true
        } catch (e: Throwable) {
            e.printStackTrace()
            Log.e(TAG, "${e.message}")
            false
        }
    }
}

通过这种方式,您无需唤醒suspend fun setUserData(id: String, data: User): Boolean { val saveTask = db.collection(COLLECTION).document(id).set(data) return try { saveTask.await() // From `kotlinx-coroutines-play-services` true } catch (e: Throwable) { e.printStackTrace() Log.e(TAG, "${e.message}") false } } 并阻止更多线程。

供参考,https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-play-services/kotlinx.coroutines.tasks/com.google.android.gms.tasks.-task/await.html