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

时间:2019-11-11 14:01:09

标签: android kotlin kotlin-coroutines

我正在View(自定义视图)中使用协程,并且这些视图已添加到回收者视图中。

我大部分的计算(复杂且冗长)都在协程scopeIO上运行,并在scopeMain上更新视图。

但是,当这些视图添加到“回收器视图”中时,它的工作原理是完美的,但是当我快速滚动时,即使视图不再可见,作业也在后台运行。

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

  

我尝试取消onDetachedFromWindow中的工作,但是当   我在回收站视图中快速滚动,它取消了工作,而在查看时   再次附加到窗口,它成为空视图。

下面是我的协程声明

 CustomView{
    .... 
    ....
    private val job = Job()
    private val scopeMain = CoroutineScope(job + Dispatchers.Main)
    private val scopeIO = CoroutineScope(job + Dispatchers.IO)
    .... 
    ....
    }

由于上述原因,许多工作还活着,整个应用程序变得很落后,有时甚至崩溃了。

P-S-是否可以有一个Job可以用于渲染整个recyclerView,即所有孩子的CustomView都使用同一作业,我相信新的Job()创建会造成延迟。

我正在研究的演示项目:

已经推荐了this

2 个答案:

答案 0 :(得分:2)

您可以覆盖“ onViewDetachedFromWindow()”并在相应的作业上调用cancel()。

  当视图变为不可见时,

onViewDetachedFromWindow被调用   适合您的目的。

来自android文档:

  

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

链接here

override fun onViewDetachedFromWindow(holder: ViewHolder) {
    holder.yourView.cancelJob()
}

类似地,当您的视图再次出现时:

onViewAttachedToWindow(holder:ViewHolder)

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

holder.yourJob.start()

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

来自Google的文档说:

  

由该适配器创建的视图已附加到   窗口。   这可以用作视图即将成为的合理信号   被用户看到。如果适配器先前释放了以下资源:   onViewDetachedFromWindow这些资源应在此处还原。

链接here

现在您的建议:

用于整个回收站的OneJob

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

答案 1 :(得分:1)

  

您可以在RecyclerView.Adapter中覆盖'onViewRecycled'并从此方法中取消您的“作业”

RecyclerView会在清除ViewHolder的内部数据并将其发送到RecycledViewPool之前立即调用此方法。这可能是释放大量资源或停止后台工作的好地方。


示例

override fun onViewRecycled(holder: CustomViewHolder) {
    holder.customView.cancelJob()
}

,您可以在ViewHolder的'onBindViewHolder'中开始后台工作