为什么使用Job.cancel() 的Flow 启动两次后无法取消?
Why can't I cancel a Flow using Job.cancel() when I start it for two times?
在App中,我点击“开始”按钮每100ms显示一次新信息,然后点击“停止”按钮停止显示新信息。和我预期的一样。
但是如果我点击“开始”按钮两次,然后我点击“停止”按钮希望停止显示新信息,但是新信息一直显示,为什么?好像myJob.cancel()
不行。
class HandleMeter: ViewModel() {
var myInfo = mutableStateOf("Hello")
private lateinit var myJob: Job
private fun soundDbFlow(period: Long = 100) = flow {
while (true) {
emit(soundDb())
delay(period)
}
}
fun calCurrentAsynNew() {
myJob = viewModelScope.launch(Dispatchers.IO) {
soundDbFlow().collect { myInfo.value = it.toString() + " OK Asyn " + a++.toString() }
}
}
fun cancelJob(){
myJob.cancel()
}
...
}
@Composable
fun Greeting(handleMeter: HandleMeter) {
var info = handleMeter.myInfo
Column(
modifier = Modifier.fillMaxSize()
) {
Text(text = "Hello ${info.value}")
Button(
onClick = { handleMeter.calCurrentAsynNew() }
) {
Text("Start")
}
Button(
onClick = { handleMeter.cancelJob() }
) {
Text("Stop")
}
}
}
当您调用 handleMeter.calCurrentAsynNew()
时,它会启动一个新协程并将返回的 Job
分配给 myJob
。当你第二次点击 Start
时,它会再次启动一个新的协程并将 myJob
的值更新为这个新的 Job
实例,但这并没有取消之前的协程,它仍然是 运行.
调用calCurrentAsynNew()
时如果想取消之前的协程,需要使用myJob.cancel()
手动取消
fun calCurrentAsynNew() {
if(::myJob.isInitialized)
myJob.cancel()
myJob = viewModelScope.launch {
soundDbFlow().collect { myInfo.value = it.toString() + " OK Asyn " + a++.toString() }
}
}
除了使用 lateinit var myJob: Job
你也可以使用 var myJob: Job? = null
然后取消它,使用 myJob?.cancel()
在这种情况下也不需要 Dispatchers.IO
。
在App中,我点击“开始”按钮每100ms显示一次新信息,然后点击“停止”按钮停止显示新信息。和我预期的一样。
但是如果我点击“开始”按钮两次,然后我点击“停止”按钮希望停止显示新信息,但是新信息一直显示,为什么?好像myJob.cancel()
不行。
class HandleMeter: ViewModel() {
var myInfo = mutableStateOf("Hello")
private lateinit var myJob: Job
private fun soundDbFlow(period: Long = 100) = flow {
while (true) {
emit(soundDb())
delay(period)
}
}
fun calCurrentAsynNew() {
myJob = viewModelScope.launch(Dispatchers.IO) {
soundDbFlow().collect { myInfo.value = it.toString() + " OK Asyn " + a++.toString() }
}
}
fun cancelJob(){
myJob.cancel()
}
...
}
@Composable
fun Greeting(handleMeter: HandleMeter) {
var info = handleMeter.myInfo
Column(
modifier = Modifier.fillMaxSize()
) {
Text(text = "Hello ${info.value}")
Button(
onClick = { handleMeter.calCurrentAsynNew() }
) {
Text("Start")
}
Button(
onClick = { handleMeter.cancelJob() }
) {
Text("Stop")
}
}
}
当您调用 handleMeter.calCurrentAsynNew()
时,它会启动一个新协程并将返回的 Job
分配给 myJob
。当你第二次点击 Start
时,它会再次启动一个新的协程并将 myJob
的值更新为这个新的 Job
实例,但这并没有取消之前的协程,它仍然是 运行.
调用calCurrentAsynNew()
时如果想取消之前的协程,需要使用myJob.cancel()
fun calCurrentAsynNew() {
if(::myJob.isInitialized)
myJob.cancel()
myJob = viewModelScope.launch {
soundDbFlow().collect { myInfo.value = it.toString() + " OK Asyn " + a++.toString() }
}
}
除了使用 lateinit var myJob: Job
你也可以使用 var myJob: Job? = null
然后取消它,使用 myJob?.cancel()
Dispatchers.IO
。