viewModelScope.launch 不会阻塞 main UI 吗?
Will not viewModelScope.launch block main UI?
代码A使用了viewModelScope.launch{ ... }
的协程,我想不会阻塞main UI吧?
新增内容:
致 Tenfour04:谢谢!
我显示函数soundDb()
,soundDb()
是挂起函数,但可能需要运行长时间!您认为该应用程序是否会导致“应用程序无响应”错误?
代码A
class HandleMeter: ViewModel() {
var myInfo = mutableStateOf("Hello")
var a = 1
fun calCurrentAsyn() {
viewModelScope.launch {
var b = 0.0
for (i in 1..5) {
b = b + soundDb()
delay(100)
}
b = b / 5.0
myInfo.value = b.toString() + " OK Asyn " + a++.toString()
}
}
}
suspend fun soundDb(): Double {
var k=0.0
for (i in 1..500000000){
k=k+i
}
return k
}
第二个添加的内容:
致Tenfour04:非常感谢!
Code B和Code C哪个更好,或者它们是一样的?
代码B
class HandleMeter: ViewModel() {
var myInfo = mutableStateOf("Hello")
var a = 1
fun calCurrentAsyn() {
viewModelScope.launch (Dispatchers.Default){
var b = 0.0
for (i in 1..5) {
b = b + soundDb()
delay(100)
}
b = b / 5.0
myInfo.value = b.toString() + " OK Asyn " + a++.toString()
}
}
}
suspend fun soundDb(): Double {
var k=0.0
for (i in 1..500000000){
k=k+i
}
return k
}
代码C
class HandleMeter: ViewModel() {
var myInfo = mutableStateOf("Hello")
var a = 1
fun calCurrentAsyn() {
viewModelScope.launch {
var b = 0.0
for (i in 1..5) {
b = b + soundDb()
delay(100)
}
b = b / 5.0
myInfo.value = b.toString() + " OK Asyn " + a++.toString()
}
}
}
suspend fun soundDb(): Double = withContext(Dispatchers.Default) {
var k=0.0
for (i in 1..500000000){
k=k+i
}
return@withContext k //I fixed it
}
从 viewModelScope
启动的协程默认在主调度器上运行。只要您不在其中调用任何阻塞函数,它就不会阻塞主线程。如果需要调用阻塞函数,可以将其包裹在withContext
中,并指定一个非Dispatchers.Main
.
的Dispatcher
我在您的代码中看到的唯一可疑之处是 soundDb()
。如果那是一个阻塞函数,那么这个协程将阻塞主线程。
函数可以属于三个类别之一。
- 常规non-blocking
- 常规屏蔽
- 暂停(non-blocking)
可以创建一个阻塞的挂起函数,但按照惯例这是被禁止的,因为它会造成混淆并且违背了拥有挂起函数的目的。如果编译器能够检测到挂起函数中的阻塞函数调用,它会发出警告。并非所有阻塞函数都可以被编译器检测到。
编辑
增加 5 亿次不会花费足够的时间来导致 ANR 错误,但它可能会导致 UI 出现明显的卡顿。当你做类似 long-running 计算的事情时,它可以被认为是阻塞的,所以这将是一个无效的挂起函数。您可以通过将阻塞工作包装在 withContext
中来修复它,以便它使用可以处理阻塞工作的 Dispatcher。现在挂起函数是 non-blocking(按照惯例应该始终是你编写挂起函数的方式)所以从任何协程调用都是安全的,不管协程当前使用的是什么调度程序。
suspend fun soundDb(): Double = withContext(Dispatchers.Default) {
var k=0.0
for (i in 1..500000000){
k=k+i
}
k
}
代码A使用了viewModelScope.launch{ ... }
的协程,我想不会阻塞main UI吧?
新增内容:
致 Tenfour04:谢谢!
我显示函数soundDb()
,soundDb()
是挂起函数,但可能需要运行长时间!您认为该应用程序是否会导致“应用程序无响应”错误?
代码A
class HandleMeter: ViewModel() {
var myInfo = mutableStateOf("Hello")
var a = 1
fun calCurrentAsyn() {
viewModelScope.launch {
var b = 0.0
for (i in 1..5) {
b = b + soundDb()
delay(100)
}
b = b / 5.0
myInfo.value = b.toString() + " OK Asyn " + a++.toString()
}
}
}
suspend fun soundDb(): Double {
var k=0.0
for (i in 1..500000000){
k=k+i
}
return k
}
第二个添加的内容:
致Tenfour04:非常感谢!
Code B和Code C哪个更好,或者它们是一样的?
代码B
class HandleMeter: ViewModel() {
var myInfo = mutableStateOf("Hello")
var a = 1
fun calCurrentAsyn() {
viewModelScope.launch (Dispatchers.Default){
var b = 0.0
for (i in 1..5) {
b = b + soundDb()
delay(100)
}
b = b / 5.0
myInfo.value = b.toString() + " OK Asyn " + a++.toString()
}
}
}
suspend fun soundDb(): Double {
var k=0.0
for (i in 1..500000000){
k=k+i
}
return k
}
代码C
class HandleMeter: ViewModel() {
var myInfo = mutableStateOf("Hello")
var a = 1
fun calCurrentAsyn() {
viewModelScope.launch {
var b = 0.0
for (i in 1..5) {
b = b + soundDb()
delay(100)
}
b = b / 5.0
myInfo.value = b.toString() + " OK Asyn " + a++.toString()
}
}
}
suspend fun soundDb(): Double = withContext(Dispatchers.Default) {
var k=0.0
for (i in 1..500000000){
k=k+i
}
return@withContext k //I fixed it
}
从 viewModelScope
启动的协程默认在主调度器上运行。只要您不在其中调用任何阻塞函数,它就不会阻塞主线程。如果需要调用阻塞函数,可以将其包裹在withContext
中,并指定一个非Dispatchers.Main
.
我在您的代码中看到的唯一可疑之处是 soundDb()
。如果那是一个阻塞函数,那么这个协程将阻塞主线程。
函数可以属于三个类别之一。
- 常规non-blocking
- 常规屏蔽
- 暂停(non-blocking)
可以创建一个阻塞的挂起函数,但按照惯例这是被禁止的,因为它会造成混淆并且违背了拥有挂起函数的目的。如果编译器能够检测到挂起函数中的阻塞函数调用,它会发出警告。并非所有阻塞函数都可以被编译器检测到。
编辑
增加 5 亿次不会花费足够的时间来导致 ANR 错误,但它可能会导致 UI 出现明显的卡顿。当你做类似 long-running 计算的事情时,它可以被认为是阻塞的,所以这将是一个无效的挂起函数。您可以通过将阻塞工作包装在 withContext
中来修复它,以便它使用可以处理阻塞工作的 Dispatcher。现在挂起函数是 non-blocking(按照惯例应该始终是你编写挂起函数的方式)所以从任何协程调用都是安全的,不管协程当前使用的是什么调度程序。
suspend fun soundDb(): Double = withContext(Dispatchers.Default) {
var k=0.0
for (i in 1..500000000){
k=k+i
}
k
}