在哪里取消视图中的协程作业?

Anm*_*mol 0 android kotlin kotlin-coroutines

我在视图(自定义视图)中使用协程,这些视图被添加到回收器视图中。

大部分计算(复杂且漫长)我都在协程上运行scopeIO并更新scopeMain.

但是,当这些视图添加到回收器视图时,它工作得很好,但当我快速滚动时,即使视图不再可见,作业也会在后台运行。

我不知道在哪里取消该工作。我见过的大多数示例代码都是活动中的协程,其中生命周期被正确定义。

我尝试取消其中的作业onDetachedFromWindow,但是当我在回收器视图中快速滚动时,它会取消作业,而当视图再次附加到窗口时,它会变成空视图。

下面是我的协程声明

 CustomView{
    .... 
    ....
    private val job = Job()
    private val scopeMain = CoroutineScope(job + Dispatchers.Main)
    private val scopeIO = CoroutineScope(job + Dispatchers.IO)
    .... 
    ....
    }
Run Code Online (Sandbox Code Playgroud)

由于上述原因,许多作业都处于活动状态,整个应用程序变得缓慢,并且在某些时候还会崩溃。

PS-是否有可能有一个可用于渲染整个 recyclerView 的作业,即所有子视图(CustomView)的相同作业,我相信 new Job() 创建导致了滞后。

我正在开发的演示项目:

已经提到过这个

Pri*_*ata 5

您可以重写“ onViewDetachedFromWindow() ”并调用相应作业的cancel()。

当视图变得不可见并且适合您的目的时,将调用 onViewDetachedFromWindow 。

来自安卓文档:

当 RecyclerView.LayoutManager 决定不再需要附加到其父 RecyclerView 时,视图将被回收。这可能是因为它已经不再可见,或者是一组由仍附加到父 RecyclerView 的视图表示的缓存视图。如果项目视图绑定了大型或昂贵的数据(例如大型位图),那么这可能是释放这些资源的好地方。

链接在这里

override fun onViewDetachedFromWindow(holder: ViewHolder) {
    holder.yourView.cancelJob()
}
Run Code Online (Sandbox Code Playgroud)

同样,当您的视图再次出现时:

onViewAttachedToWindow(holder:ViewHolder)
Run Code Online (Sandbox Code Playgroud)

将被调用。这里你必须重新启动协程作业。

holder.yourJob.start()
Run Code Online (Sandbox Code Playgroud)

您的问题的原因是,您正在取消作业,但是当再次查看时(它不会再次创建,它正在被重新使用,即绑定已完成到已创建的视图),因此您需要开始工作由你自己承担。

谷歌的文档说:

当此适配器创建的视图已附加到窗口时调用。这可以用作视图即将被用户看到的合理信号。如果适配器之前在 onViewDetachedFromWindow 中释放了任何资源,则应在此处恢复这些资源。

链接在这里

现在向您提出建议:

整个回收商的 OneJob

您的作业位于视图内,因此当创建视图时,作业就会执行。为了让您拥有一份工作,您的工作应该存在于自定义视图之外。您的方法应该接受视图,并且视图应该将视图元素的创建/初始化委托给该方法。这也意味着,您需要向此外部方法公开视图内部。对我来说听起来不太优雅。另外,如果有 7 个可见项目,您的这个“外部”方法将负责渲染所有 7 个元素,这也会影响快速滚动时的性能,因为对于相当大小的列表,该方法很快就会被淹没。