如何在MainActivity中操控RecyclerView适配器VideoItemAdapter内的MediaPlayer
解决方案
你的核心问题是MediaPlayer作为ViewHolder内的局部变量,外部无法访问,且多视频场景下多个实例会导致资源浪费和状态混乱,以下是可直接落地的实现:
1. 实现全局单例MediaPlayer管理类
这个类统一管控所有播放逻辑,全局只有一个实例,避免多实例冲突:
import android.media.MediaPlayer; import android.widget.VideoView; public class MediaPlayerManager { private static volatile MediaPlayerManager INSTANCE; private MediaPlayer currentMediaPlayer; private VideoView currentPlayingVideoView; private boolean isPlaying = false; private int currentPosition = 0; // 私有构造禁止外部实例化 private MediaPlayerManager() {} // 双检锁单例实现 public static MediaPlayerManager getInstance() { if (INSTANCE == null) { synchronized (MediaPlayerManager.class) { if (INSTANCE == null) { INSTANCE = new MediaPlayerManager(); } } } return INSTANCE; } // 绑定新的VideoView播放视频 public void playNewVideo(VideoView videoView, String videoUrl) { // 先停止之前的播放 stopCurrentPlay(); currentPlayingVideoView = videoView; currentPlayingVideoView.setVideoPath(videoUrl); currentPlayingVideoView.setOnPreparedListener(mp -> { currentMediaPlayer = mp; isPlaying = true; // 支持续播 if (currentPosition > 0) { mp.seekTo(currentPosition); } mp.start(); }); currentPlayingVideoView.setOnCompletionListener(mp -> { // 按需修改循环逻辑 mp.start(); }); } // 暂停播放 public void pausePlay() { if (currentMediaPlayer != null && currentMediaPlayer.isPlaying()) { currentPosition = currentMediaPlayer.getCurrentPosition(); currentMediaPlayer.pause(); isPlaying = false; } } // 恢复播放 public void resumePlay() { if (currentMediaPlayer != null && !isPlaying) { currentMediaPlayer.seekTo(currentPosition); currentMediaPlayer.start(); isPlaying = true; } } // 停止当前播放 public void stopCurrentPlay() { if (currentMediaPlayer != null) { currentMediaPlayer.release(); currentMediaPlayer = null; } if (currentPlayingVideoView != null) { currentPlayingVideoView.stopPlayback(); currentPlayingVideoView = null; } isPlaying = false; currentPosition = 0; } // 页面销毁时调用释放资源 public void release() { stopCurrentPlay(); INSTANCE = null; } // 获取当前播放状态 public boolean isPlaying() { return isPlaying; } }
2. 修改VideoItemAdapter相关代码
移除ViewHolder内独立的MediaPlayer逻辑,统一交给管理器处理:
// 修改ViewHolder的setVideoData方法 void setVideoData(VideoItem videoItem){ textVideoTitle.setText(videoItem.videoTitle); textVideoDescription.setText(videoItem.videoDescription); // 这里不要自行设置播放逻辑,等待ViewPager2滑动到当前页面时再触发播放 }
然后在MainActivity中给ViewPager2添加页面变化监听,滑动到对应页面时触发播放:
videosViewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { @Override public void onPageSelected(int position) { super.onPageSelected(position); // 获取当前页面的ViewHolder VideoItemAdapter.VideoViewHolder holder = (VideoItemAdapter.VideoViewHolder) videosViewPager.findViewHolderForAdapterPosition(position); if (holder != null) { // 调用管理器播放当前视频 MediaPlayerManager.getInstance().playNewVideo(holder.videoView, videoItems.get(position).videoURL); } } });
3. MainActivity按钮控制逻辑
直接调用管理器的对应方法即可实现启停,不需要手动获取MediaPlayer实例:
// 找到你的控制按钮 Button controlBtn = findViewById(R.id.your_control_btn_id); controlBtn.setOnClickListener(v -> { if (MediaPlayerManager.getInstance().isPlaying()) { // 当前正在播放,点击暂停 MediaPlayerManager.getInstance().pausePlay(); controlBtn.setText("播放"); } else { // 当前暂停,点击恢复 MediaPlayerManager.getInstance().resumePlay(); controlBtn.setText("暂停"); } }); // 页面销毁时释放资源,避免内存泄漏 @Override protected void onDestroy() { super.onDestroy(); MediaPlayerManager.getInstance().release(); }
注意事项
- 不要在ViewHolder的onBindViewHolder中直接触发播放,否则ViewPager2预加载页面时会同时加载多个视频,导致逻辑混乱
- 如果不需要视频自动循环,可以删掉管理器中setOnCompletionListener的start逻辑
- 如果要实现后台播放功能,需要配合Service使用,当前实现适用于前台短视频流播放场景
内容的提问来源于stack exchange,提问作者Fábio Monteiro
相关产品推荐
相关产品推荐

