自定义协程作用域如何继承其他协程作用域?以viewHolderScope实现为例
你当前的写法完全无法达到预期,核心问题有三个:
- 你定义的
viewHolderScope是全局单例,所有ViewHolder会共用同一个作用域,无法做到单个ViewHolder回收时单独取消协程 - 直接复制父协程上下文创建的新作用域没有和父作用域建立父子关联,父作用域销毁时不会自动取消这个独立的新作用域
- 没有和ViewHolder的
onBind/onRecycle生命周期绑定,无法做到回收时自动取消协程
正确实现方案
1. 给Adapter注入父作用域
Adapter构造函数接收外部传入的页面级协程作用域,和Fragment/Activity的生命周期直接绑定,确保页面销毁时所有子协程自动取消:
class ChatListAdapter( private val parentScope: CoroutineScope, private val chatStatusObserver: ChatStatusObserver // 其他参数如DiffCallback ) : RecyclerView.Adapter<ChatViewHolder>() {
2. 每个ViewHolder维护独立作用域
每个ViewHolder持有自己的协程作用域,绑定数据时重置,回收时取消,避免ViewHolder复用导致的数据错乱:
class ChatViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { private var viewHolderScope: CoroutineScope? = null fun bind(chat: Chat) { // 先取消上一次绑定启动的旧协程 viewHolderScope?.cancel() // 继承父作用域上下文建立父子关联,加SupervisorJob避免单个ViewHolder协程异常影响其他协程 viewHolderScope = parentScope + SupervisorJob() + Dispatchers.Main.immediate // 启动状态流收集 viewHolderScope?.launch { chatStatusObserver.statusFlow(chat).collect { status -> // 执行UI更新逻辑 } } } fun onRecycle() { viewHolderScope?.cancel() viewHolderScope = null } }
3. 绑定Adapter生命周期回调
override fun onBindViewHolder(holder: ChatViewHolder, position: Int) { val chat = getItem(position) ?: return holder.bind(chat) } override fun onViewRecycled(holder: ChatViewHolder) { super.onViewRecycled(holder) holder.onRecycle() } // 可选:Adapter从RecyclerView解绑时取消所有残留协程 override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { super.onDetachedFromRecyclerView(recyclerView) parentScope.cancel() }
4. 页面端传入对应的父作用域
// Fragment中传入viewLifecycleScope,和Fragment视图生命周期绑定 val adapter = ChatListAdapter(viewLifecycleOwner.lifecycleScope, chatStatusObserver) // Activity中直接传入lifecycleScope即可 val adapter = ChatListAdapter(lifecycleScope, chatStatusObserver)
该实现完全满足你的需求:
- 仅为屏幕可见的ViewHolder启动状态收集,符合性能优化要求
onBind时启动收集,onRecycle时立刻取消当前ViewHolder的所有协程- 页面销毁时父作用域自动取消,所有子ViewHolder的协程会连带取消,不会出现内存泄漏
内容的提问来源于stack exchange,提问作者Sourav Kannantha B
相关产品推荐
相关产品推荐

