問題:
在 Compose- kotlin 中,如果在 ViewModel 中的 init 函數中
使用非主線程上的協程
會導致閃退問題,
具體代碼為:
@HiltViewModel
class ApkScreenViewModel @Inject constructor(...
) : ViewModel() {// 1. 在非 主線程的協程上初始化數據fun initData1() {viewModelScope.launch(Dispatchers.Default) {// 在 默認線程上初始化數據()// 或者viewModelScope.launch(Dispatchers.IO)// 在IO線程上初始化...}}// 2. 在 主線程的協程上初始化數據fun initData2() {viewModelScope.launch(Dispatchers.Main) {// 在 主線程上初始化數據()// 或者viewModelScope.launch()// 在主線程上初始化,默認就是主線程,參數可以不寫...}}init {println("vm初始化測試")initData1()// 1 調用此函數會導致閃退initData2()// 2 調用此函數不不不會導致閃退}
}
猜測的原因:
ViewModel 的 init 函數本身,
可能就是一個協程作用域(默認在主線程上,比如init(Dispatchers.Main)
),
1、所以在主線程上的協程作用域內在運行其他線程上的協程,就會導致錯誤閃退(比如運行initData1)。
2、但是如果在主線程上再運行主線程上的協程,不會導致閃退(比如運行initData2)
1、正確做法:fun initData() {viewModelScope.launch(Dispatchers.Main) {// 在 主線程上初始化數據()// 或者viewModelScope.launch()// 在主線程上初始化,默認就是主線程,參數可以不寫viewModelScope.launch(Dispatchers.Main) {// 在 主線程上初始化數據()// 主線程的協程內可以再運行主線程上的協程,但是不可以運行其他線程上的協程,比如不可以運行IO、Default}}}
2、錯誤做法:(閃退)fun initData() {viewModelScope.launch(Dispatchers.Main) {// 在 主線程上初始化數據()// 或者viewModelScope.launch()// 在主線程上初始化,默認就是主線程,參數可以不寫viewModelScope.launch(Dispatchers.IO) {// 在 主線程上初始化數據()// 主線程不可以運行其他線程上的協程,比如不可以運行IO、Default}}}
總結:在使用 kotlin 協程的時候要清楚所在的線程,避免嵌套不同線程的協程!