背景:
在ViewModel中有个协程方法(viewModelScope),里面是whlie(true),始终进行网络查询。
该方法由fragment中的onResume调用
现象:
发现在viewmodel结束后,该协程依旧不停止。(原因有待确认)
过程:
- 改进为while(flag),在viewmodel中,重写onCleared()方法,将flag置为false。
此方法仅在viewmodel生命周期结束后才有效。即对应的 fragment / activity onDestroy 之后才有效。如果是OnReusme()的时候,则无效。
fun getLocation(devId: String) {
locationJob = viewModelScope.launch(Dispatchers.IO) {
while (flag) {
//do something
Thread.sleep(GET_LOCATION_DURATION_TIME)
}
}
}
override fun onCleared() {
super.onCleared()
Log.d(TAG, "MapViewModel onDestroy ")
flag = false
}
- 将ViewModel绑定LifeCycler,在onPause的时候,把flag置为false。
发现该方法在APP快速切入切出的时候,会产生多次构造协程体,导致同时产生多个协程执行。这无疑是错误的。(怀疑是sleep没执行完,故协程未执行完,导致旧的协程未取消,新的协程就进来了,此时公用一个flag,旧的协程就继续执行下去了,未能被取消)
fun getLocation(devId: String) {
locationJob = viewModelScope.launch(Dispatchers.IO) {
while (flag) {
//do something
Thread.sleep(GET_LOCATION_DURATION_TIME)
}
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause() {
flag = false
}
- 将ViewModel绑定LifeCycler,在onPause的时候,把协程cancel()掉。while循环通过协程的isActive状态判断。
fun getLocation(devId: String) {
locationJob = viewModelScope.launch(Dispatchers.IO) {
Log.d(TAG, "getLocation >>> is active : $isActive") // 3. true
while (isActive) {
// todo something
}
Thread.sleep(GET_LOCATION_DURATION_TIME)
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun onPause() {
locationJob?.cancel()
Log.d(TAG, "onPause >> is active :${locationJob?.isActive}") // 1. true
}
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun onResume(){
Log.d(TAG, "onPause >> is active :${locationJob?.isActive}") // 2. true
}
这个方法达到了最终目的,即无论是viewmodel onCleared() 还是 fragment onPause(),都可以保证只有一个协程在运行。
问题
目的虽然达到了,但是是试出来的。留下的疑问是为什么 在onResume()的时候,协程的状态被恢复了(即 log 2)。job.cancel()是否真正取消了协程。