android - 视图中的协程作业在哪里取消?
问题描述
我在视图(自定义视图)中使用协程,这些视图被添加到回收器视图中。
我在协程上运行的大部分计算(复杂且长)scopeIO
并更新scopeMain
.
但是,当这些视图被添加到 Recycler View 时,它可以完美地工作,但是当我快速滚动时,即使视图不再可见,作业也会在后台运行。
我不确定在哪里取消作业。我见过的大多数示例代码都是正确定义生命周期的活动中的协程。
我尝试取消作业,
onDetachedFromWindow
但是当我在回收站视图中快速滚动时,它取消了作业,而当视图再次附加到窗口时,它是空视图。
下面是我的协程声明
CustomView{
....
....
private val job = Job()
private val scopeMain = CoroutineScope(job + Dispatchers.Main)
private val scopeIO = CoroutineScope(job + Dispatchers.IO)
....
....
}
由于上述原因,许多工作仍然存在,整个应用程序变得滞后,并且在某些时候也会崩溃。
PS-是否有可能有一个可用于渲染整个 recyclerView 的作业,即所有孩子(CustomView)的相同作业,我相信新的 Job() 创建会导致滞后。
我正在进行的演示项目:
已经提到这个
解决方案
您可以覆盖' onViewDetachedFromWindow() '并在相应的作业上调用cancel()。
onViewDetachedFromWindow 在视图变得不可见并且适合您的目的时被调用。
从安卓文档:
当 RecyclerView.LayoutManager 决定不再需要将视图附加到其父 RecyclerView 时,视图将被回收。这可能是因为它已失去可见性,或者由仍附加到父 RecyclerView 的视图表示的一组缓存视图。如果项目视图绑定了大型或昂贵的数据,例如大型位图,那么这可能是释放这些资源的好地方。
链接在这里
override fun onViewDetachedFromWindow(holder: ViewHolder) {
holder.yourView.cancelJob()
}
同样,当您的视图再次出现时:
onViewAttachedToWindow(holder:ViewHolder)
将被调用。在这里,您必须重新启动协程作业。
holder.yourJob.start()
您的问题的原因是,您正在取消作业,但是当再次查看时(它没有再次创建,它正在被重新使用,即绑定已完成到已创建的视图),因此您需要开始自己的工作。
来自谷歌的文档说:
当此适配器创建的视图已附加到窗口时调用。这可以用作用户即将看到视图的合理信号。如果适配器之前释放了 onViewDetachedFromWindow 中的任何资源,则应在此处恢复这些资源。
链接在这里
现在为您的建议:
整个回收商的 OneJob:
您的作业在视图内,因此当创建视图时,作业就会执行。为了让您拥有一份工作,您的工作应该存在于自定义视图之外。您的方法应该接受视图,并且视图应该将视图元素的创建/初始化委托给此方法。这也意味着,您需要将视图内部暴露给这个外部方法。对我来说听起来不是很优雅。此外,如果有 7 个项目可见,您的这个“外部”方法将负责渲染所有 7 个元素,当您快速滚动时,这也会影响性能,因为对于相当大的列表,该方法将很快被淹没。
推荐阅读
- azure - 多次触发带有队列的 Azure WebJob
- c# - WPF 中的编程数据绑定不起作用
- laravel - 返回数组 Api 资源对象时分页
- javascript - Highcharts,5个小图表,有些随机不画
- javascript - 将事件对象发送到没有 event.persist 的回调
- ubuntu - HADOOP - 权限被拒绝执行 start-all.sh
- mongodb - 具有嵌套结构的 MongoDB 查询
- node.js - Nightwatchjs 读取文本文件 nodejs
- c - 无法使用 gcc 编译 main.c 并将其链接到另一个源文件
- c# - 在 asp.net core 中基于语言环境的时间格式