Android Studio中点击RecyclerView图片时多音频同播问题修复咨询
多RecyclerView音频并行播放问题修复方案
原代码存在的核心问题
- 未维护全局唯一的MediaPlayer实例,在
onBindViewHolder中直接初始化MediaPlayer,列表滚动时每绑定一个item就会创建一个新的播放实例,存在大量无效资源占用 - MediaPlayer引用被适配器成员变量反复覆盖,早期创建的播放实例失去可控引用,无法被停止或释放,直接触发多个音频并行播放的异常
- 无统一的资源回收逻辑,Activity退出后仍可能有音频在后台播放,存在内存泄漏风险
单例模式改造实现单MediaPlayer播放
按照全局单实例管控的思路,分两步完成改造:
1. 实现单例音频管理类
类内部持有唯一的MediaPlayer实例,对外提供统一的播放、资源释放接口,每次发起新播放请求时,自动回收上一次的播放资源:
class AudioPlayerManager private constructor() { private var mediaPlayer: MediaPlayer? = null private object SingletonHolder { val INSTANCE = AudioPlayerManager() } companion object { fun getInstance(): AudioPlayerManager = SingletonHolder.INSTANCE } /** * 播放指定音频资源,自动停止上一段正在播放的音频 */ fun play(context: Context, soundResId: Int, isLooping: Boolean = true) { // 先回收之前的播放实例 releasePlayer() // 用全局上下文创建MediaPlayer,避免内存泄漏 mediaPlayer = MediaPlayer.create(context.applicationContext, soundResId) mediaPlayer?.isLooping = isLooping mediaPlayer?.start() } /** * 释放所有持有的MediaPlayer资源 */ fun releasePlayer() { mediaPlayer?.apply { if (isPlaying) stop() release() } mediaPlayer = null } }
2. 改造原有RecyclerView适配器
删除适配器内部自管理MediaPlayer的逻辑,点击item时直接调用单例管理器的播放接口,不再自行创建播放实例:
class RecylerViewAdapter (var context: Context, var arrayList: ArrayList<ItemModel>) : RecyclerView.Adapter<RecylerViewAdapter.ItemHolder>() { // 删除原代码中自维护的mediaPlayer成员变量 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemHolder { val viewHolder = LayoutInflater.from(parent.context) .inflate(R.layout.sound_item_list, parent, false) return ItemHolder(viewHolder) } override fun onBindViewHolder(holder: ItemHolder, position: Int) { val itemModel: ItemModel = arrayList[position] holder.soundImage.setImageResource(itemModel.soundImage) holder.soundTitle.text = itemModel.soundTitle holder.soundImage.setOnClickListener { Toast.makeText(context, itemModel.soundTitle, Toast.LENGTH_LONG).show() // 调用单例管理器的统一播放接口 AudioPlayerManager.getInstance().play(context, itemModel.soundTrack) } } override fun getItemCount(): Int { return arrayList.size } class ItemHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { var soundImage = itemView.soundImage var soundTitle = itemView.soundTitle } }
补充注意事项
- 宿主页面(Activity/Fragment)在销毁时,需要主动调用
AudioPlayerManager.getInstance().releasePlayer()释放资源,避免页面退出后音频仍后台播放 - 不要在
onBindViewHolder中做和视图绑定无关的重初始化逻辑(比如原代码中提前创建MediaPlayer的操作),这类资源操作应该放到用户实际触发点击时再执行 - 播放逻辑增加状态判断,避免MediaPlayer处于未初始化状态时调用
start()触发空指针异常
内容的提问来源于stack exchange,提问作者Aryan Raj
相关产品推荐
相关产品推荐

