You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin练习开发音乐应用时RecyclerView滚动卡顿问题如何解决?

问题根因

MediaStore.Images.Media.getBitmap属于磁盘IO操作,耗时通常在几十到几百毫秒不等,不管是在onBindViewHolder中实时加载(滚动时频繁触发主线程耗时操作导致卡顿),还是主线程一次性全量加载(阻塞UI导致界面冻结),本质都是主线程执行了耗时IO任务导致的。

可选解决方案

方案1:使用Kotlin原生图片加载库Coil(最优解)

图片加载库已经默认实现了异步IO加载、内存/磁盘双缓存、ViewHolder复用错位校验、Bitmap自适应压缩、滚动时自动取消无效加载等全量优化,仅需少量代码即可完成需求,无需自行处理复杂的异步逻辑:

// 引入Coil后直接调用ImageView的扩展方法加载Uri即可
holder.song_image.load(songList[position].albumUri) {
    // 可选配置:设置加载占位图、错误图
    placeholder(R.drawable.default_album)
    error(R.drawable.album_load_fail)
}

方案2:自行用协程实现轻量异步加载

注意:协程并不是仅能处理复杂多任务场景,对于这种简单的异步IO任务,协程的写法比原生Thread更简洁,还能自动绑定生命周期避免内存泄漏,完全适配你的需求。
实现代码示例如下:

override fun onBindViewHolder(holder: SongHolder, position: Int) {
    val currentSong = songList[position]
    // 先设置占位图,避免滑动时显示上一个Holder的旧图片
    holder.song_image.setImageResource(R.drawable.default_album)

    // 绑定当前View的生命周期启动协程,View被复用/销毁时自动取消加载任务
    holder.itemView.findViewTreeLifecycleOwner()?.lifecycleScope?.launch(Dispatchers.IO) {
        // 先查内存缓存,有缓存直接用
        val cachedBitmap = memoryCache.get(currentSong.id)
        val targetBitmap = if (cachedBitmap != null) {
            cachedBitmap
        } else {
            // IO线程执行Bitmap加载操作,不会阻塞主线程
            MediaStore.Images.Media.getBitmap(contentResolver, currentSong.albumUri).also {
                // 加载完成后存入内存缓存
                memoryCache.put(currentSong.id, it)
            }
        }

        // 切回主线程设置图片
        withContext(Dispatchers.Main) {
            // 校验当前Holder的位置是否匹配,避免ViewHolder复用导致的图片错位
            if (holder.bindingAdapterPosition == position) {
                holder.song_image.setImageBitmap(targetBitmap)
            }
        }
    }
}

补充:上述代码中的memoryCache可以直接使用Android系统提供的LruCache实现,限制最大缓存容量避免OOM即可。

额外优化建议
  • 不要直接加载原始尺寸的专辑封面:可以先获取ImageView的尺寸,把Bitmap压缩到和控件尺寸一致后再加载,能大幅减少内存占用和加载耗时
  • 替换已废弃的getBitmap方法:Android 10及以上版本中MediaStore.Images.Media.getBitmap已被废弃,推荐使用ContentResolver.openInputStream配合BitmapFactory.decodeStream实现加载,兼容性更好
  • 如果歌曲数量较多,不要一次性全量加载所有Bitmap:即便是子线程加载全量Bitmap也会占用大量内存,甚至触发OOM,按需加载+缓存的方案适配性更强

内容的提问来源于stack exchange,提问作者hema ezzat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 21:36:03