Kotlin如何实现RecyclerView中Dispatchers.IO后台任务顺序执行
问题原因
你当前的代码每次触发onBindViewHolder时,都会直接通过async(Dispatchers.IO)把任务提交到IO调度器的共享线程池,该线程池默认支持多线程并行执行任务,因此多个tools.networkFileManager任务会同时运行,不存在排队等待逻辑。
实现方案
要让后台任务严格顺序执行,核心是给所有networkFileManager任务创建一个并行度限制为1的专用协程上下文,让所有任务进入同一个FIFO队列,前一个任务执行完成后才会启动下一个。
具体实现步骤
- 在Adapter内部定义和Adapter生命周期绑定的串行协程作用域,复用
Dispatchers.IO的线程池同时限制同一时间只能执行1个任务,比单独创建单线程调度器开销更低:
class FileAdapter( val isFromNetwork : Boolean, val context: Context, val tools: Tools, val coroutineScope: CoroutineScope ):RecyclerView.Adapter<FileAdapter.FileHolder>() { // 串行IO任务专用作用域,并行度限制为1,自带异常隔离 private val serialTaskScope = CoroutineScope( Dispatchers.IO.limitedParallelism(1) + SupervisorJob() ) // 其他原有代码...
- 修改
onBindViewHolder逻辑,把后台任务提交到上述串行作用域,注意更新UI必须切回主线程:
override fun onBindViewHolder(holder: FileHolder, position: Int) { serialTaskScope.launch { // 这部分代码运行在串行IO上下文,自动排队顺序执行 val fileResult = tools.networkFileManager(networkFileList[position]) // 切回主线程执行View更新操作,避免线程异常 withContext(Dispatchers.Main) { // 执行holder的视图绑定逻辑 holder.tvFileName.text = fileResult.name // 其他视图操作... } } }
- 增加生命周期回收逻辑,在Adapter和RecyclerView分离时取消所有排队任务,避免内存泄漏和无用任务执行:
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) { super.onDetachedFromRecyclerView(recyclerView) serialTaskScope.cancel() }
注意事项
- 不要使用Mutex锁等方案实现串行,额外增加锁开销还容易写出死锁bug,
limitedParallelism(1)是协程官方提供的原生限流方案,逻辑更可靠 - 不要直接用外部传入的
coroutineScope提交串行任务,外部scope一般是主线程/LifecycleScope,默认并行调度,无法保证任务顺序 - 如果需要优化列表滑动体验,可以给每个ViewHolder绑定对应Job,在
onViewRecycled回调中取消已经滑出屏幕的对应任务,避免队列中堆积大量无用任务 - 所有视图操作必须在
Dispatchers.Main线程执行,否则会触发安卓原生的线程访问异常
内容的提问来源于stack exchange,提问作者HT__
相关产品推荐
相关产品推荐

