android - Kotlin CoroutineScope 无法在 android 视图中取消
问题描述
例如,这个视图。当onDetachedFromWindow
调用范围被取消时,但启动的作业仍然处于活动状态。
class TestView : FrameLayout,CoroutineScope {
val TAG = "TestView"
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + Job()
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
launch {
while (true) {
Log.i(TAG,"is in launch coroutine....${coroutineContext} ${this@TestView.coroutineContext}")
delay(1000)
}
}
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
cancel()
Log.i(TAG,"onDetachedFromWindow")
}
}
日志是
2019-09-19 21:32:26.652 22912-22912/com.ymr.myapplication I/TestView: is in launch coroutine....[StandaloneCoroutine{Active}@7f9d20f, Main] [JobImpl{Active}@2f3fde2, Main]
2019-09-19 21:32:27.655 22912-22912/com.ymr.myapplication I/TestView: is in launch coroutine....[StandaloneCoroutine{Active}@7f9d20f, Main] [JobImpl{Active}@80a2573, Main]
2019-09-19 21:32:28.656 22912-22912/com.ymr.myapplication I/TestView: is in launch coroutine....[StandaloneCoroutine{Active}@7f9d20f, Main] [JobImpl{Active}@dad2c30, Main]
2019-09-19 21:32:29.649 22912-22912/com.ymr.myapplication I/TestView: onDetachedFromWindow
2019-09-19 21:32:29.665 22912-22912/com.ymr.myapplication I/TestView: is in launch coroutine....[StandaloneCoroutine{Active}@7f9d20f, Main] [JobImpl{Active}@dab39f4, Main]
2019-09-19 21:32:30.666 22912-22912/com.ymr.myapplication I/TestView: is in launch coroutine....[StandaloneCoroutine{Active}@7f9d20f, Main] [JobImpl{Active}@448351d, Main]
2019-09-19 21:32:31.668 22912-22912/com.ymr.myapplication I/TestView: is in launch coroutine....[StandaloneCoroutine{Active}@7f9d20f, Main] [JobImpl{Active}@45ba392, Main]
2019-09-19 21:32:32.669 22912-22912/com.ymr.myapplication I/TestView: is in launch coroutine....[StandaloneCoroutine{Active}@7f9d20f, Main] [JobImpl{Active}@bc75163, Main]
那么为什么不能取消范围启动的作业呢?
解决方案
问题是你每次都在创造一个新Job
的。coroutineContext
您可以使用以下方法轻松解决此问题
override val coroutineContext = Dispatchers.Main + Job()
但是,请记住,如果您的视图在分离后附加到窗口,则该视图coroutineContext
已被取消。
查看以下示例,以更好地了解它应该如何工作:
class MyActivity : AppCompatActivity(), CoroutineScope {
lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
job = Job()
}
override fun onDestroy() {
super.onDestroy()
job.cancel() // Cancel job on activity destroy. After destroy all children jobs will be cancelled automatically
}
/*
* Note how coroutine builders are scoped: if activity is destroyed or any of the launched coroutines
* in this method throws an exception, then all nested coroutines are cancelled.
*/
fun loadDataFromUI() = launch { // <- extension on current activity, launched in the main thread
val ioData = async(Dispatchers.IO) { // <- extension on launch scope, launched in IO dispatcher
// blocking I/O operation
}
// do something else concurrently with I/O
val data = ioData.await() // wait for result of I/O
draw(data) // can draw in the main thread
}
}
推荐阅读
- bash - 根据年份提取 bibtex 条目
- javascript - window.removeEventListener 没有从窗口中删除事件
- python - Serverless-offline 适用于 javascript 但在 python 中抛出错误
- c - 为什么 fgets() 不接受 C 程序中的输入?
- java - Hibernate - CriteriaBuilder 集合是否包含过滤器集合的任何元素
- editor - Texstudio 中的块选择或多个光标?
- android - 防止通知被其他应用读取
- asp.net - 尝试访问 Azure Web 应用程序中的特定页面时发生错误
- oracle-apex - 为一个登录 apex oracle 生成密码
- javascript - ReferenceError:显示未在 HTMLInputElement.onclick 中定义