了解协程作用域
Understanding coroutineScope
假设在 VM 中使用 viewModelScope
启动了一个新协程,并在通用存储库中调用了一个非挂起函数 class
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
}
}
- 启动
setUserData
的范围和背景是什么?
- 如果我在
setUserData
函数之前添加 suspend
键,Tasks
的 await
方法将生成一个警告说 Inappropriate blocking method call
。为什么?
- 这个实现有什么不同?
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
是否保证 setUserData
将在调用者的相同范围和上下文中启动?
What's the scope and context in which the setUserData
is launched?
从 viewModelScope.launch(context = Dispatchers.IO)
来看,上下文看起来是这样的 CoroutineScope(SupervisorJob() + Dispatchers.IO)
。
If I add the suspend
keywork ahead of the setUserData
function, the await
method of the Tasks
will generate a warning saying Inappropriate blocking method call
. Why?
在挂起函数中阻塞线程(使用 Tasks.await
)是不好的做法,除非调度程序支持这一点。即 Dispatchers.IO
.
IntelliJ/Android Studio 不够智能(而且可能不能),无法准确确定您是否在不该阻止的情况下进行阻止。所以这可以被认为是一个错误,但是 setUserData
可以在 Dispatchers.IO
之外调用,所以 IntelliJ 在这里有一点。
What's the difference with this implementation?
真的不多。它只是有一些不值得的额外开销。
附带说明一下,coroutineScope
不会像 withContext
那样更改直接 coroutineContext
,但它会更改已启动协程的继承上下文。
Is coroutineScope
a guarantee that setUserData
will be launched within the same scope and context of the caller?
您已经获得此保证。你不需要 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
}
}
这样您就不需要调用 Dispatchers.IO
和阻塞更多线程。
假设在 VM 中使用 viewModelScope
启动了一个新协程,并在通用存储库中调用了一个非挂起函数 class
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
}
}
- 启动
setUserData
的范围和背景是什么? - 如果我在
setUserData
函数之前添加suspend
键,Tasks
的await
方法将生成一个警告说Inappropriate blocking method call
。为什么? - 这个实现有什么不同?
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
是否保证setUserData
将在调用者的相同范围和上下文中启动?
What's the scope and context in which the
setUserData
is launched?
从 viewModelScope.launch(context = Dispatchers.IO)
来看,上下文看起来是这样的 CoroutineScope(SupervisorJob() + Dispatchers.IO)
。
If I add the
suspend
keywork ahead of thesetUserData
function, theawait
method of theTasks
will generate a warning sayingInappropriate blocking method call
. Why?
在挂起函数中阻塞线程(使用 Tasks.await
)是不好的做法,除非调度程序支持这一点。即 Dispatchers.IO
.
IntelliJ/Android Studio 不够智能(而且可能不能),无法准确确定您是否在不该阻止的情况下进行阻止。所以这可以被认为是一个错误,但是 setUserData
可以在 Dispatchers.IO
之外调用,所以 IntelliJ 在这里有一点。
What's the difference with this implementation?
真的不多。它只是有一些不值得的额外开销。
附带说明一下,coroutineScope
不会像 withContext
那样更改直接 coroutineContext
,但它会更改已启动协程的继承上下文。
Is
coroutineScope
a guarantee thatsetUserData
will be launched within the same scope and context of the caller?
您已经获得此保证。你不需要 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
}
}
这样您就不需要调用 Dispatchers.IO
和阻塞更多线程。