Android中ViewPager滑动时如何停止视频播放?解决相邻页面视频仍播放问题
解决ViewPager中视频滑动相邻页面仍播放的问题
我来帮你搞定这个视频播放的问题!你的核心问题其实和ViewPager的预加载机制,以及你当前的Player管理方式有关,咱们一步步来解决:
问题根源分析
- ViewPager默认预加载:ViewPager默认会预加载当前页面左右各1个页面(
offscreenPageLimit=1),这意味着你滑动到相邻页面时,原视频页面并没有被销毁(destroyItem方法不会触发),所以视频会继续在后台播放。 - 全局单一Player实例:你在Adapter里只创建了一个
SimpleExoPlayer,所有视频页面的PlayerView都绑定到这个player——这会导致切换页面时,player被重复设置新的数据源,同时旧页面的PlayerView还会继续播放这个player的内容,造成混乱。
解决方案
我们分两步修改代码,彻底解决这个问题:
第一步:重构Adapter,为每个视频页面独立管理Player
我们不再使用全局player,而是给每个视频页面创建独立的Player实例,并在页面销毁时及时释放资源:
public class SelectedMediaViewPagerAdapter extends PagerAdapter { private final Context context; private final LayoutInflater layoutInflater; public ArrayList<MediaItem> mediaItems; // 用HashMap保存每个页面对应的Player,方便后续控制 private final HashMap<Integer, SimpleExoPlayer> playerMap = new HashMap<>(); public SelectedMediaViewPagerAdapter(Context context, ArrayList<MediaItem> mediaItems) { this.mediaItems = mediaItems; this.context = context; layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public int getCount() { return mediaItems.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } @Override public Object instantiateItem(final ViewGroup container, int position) { RelativeLayout layout = (RelativeLayout) layoutInflater.inflate(R.layout.item_selected_media_view_pager, container, false); RelativeLayout vidView = layout.findViewById(R.id.vidView); ImageView imgView = layout.findViewById(R.id.imgView); if (mediaItems.get(position).isVideo()) { imgView.setVisibility(View.GONE); vidView.setVisibility(View.VISIBLE); PlayerView playerView = layout.findViewById(R.id.player_view); final ProgressBar progressBar = layout.findViewById(R.id.progresbar_video_play); progressBar.setVisibility(View.VISIBLE); // 为当前视频页面创建独立的Player DefaultTrackSelector trackSelector = new DefaultTrackSelector(); SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(context, trackSelector); playerMap.put(position, player); playerView.setPlayer(player); DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory( context, Util.getUserAgent(context, context.getResources().getString(R.string.app_name)) ); MediaSource videoSource = new ExtractorMediaSource.Factory(dataSourceFactory) .createMediaSource(Uri.parse(mediaItems.get(position).getPath())); player.prepare(videoSource); player.setPlayWhenReady(false); // 默认不自动播放,可根据需求调整 player.addListener(new Player.DefaultEventListener() { @Override public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { // 视频准备好并开始播放时隐藏进度条 if (playWhenReady && playbackState == Player.STATE_READY) { progressBar.setVisibility(View.GONE); } super.onPlayerStateChanged(playWhenReady, playbackState); } }); } else { imgView.setVisibility(View.VISIBLE); vidView.setVisibility(View.GONE); Glide.with(context).load("file://" + mediaItems.get(position).getPath()).into(imgView); } container.addView(layout); return layout; } @Override public void destroyItem(ViewGroup container, int position, Object object) { // 页面销毁时,释放对应的Player资源,避免内存泄漏 SimpleExoPlayer player = playerMap.get(position); if (player != null) { player.stop(); player.release(); playerMap.remove(position); } container.removeView((RelativeLayout) object); } // 对外提供暂停指定页面视频的方法 public void pauseVideo(int position) { SimpleExoPlayer player = playerMap.get(position); if (player != null && player.getPlayWhenReady()) { player.setPlayWhenReady(false); } } // 对外提供播放指定页面视频的方法 public void playVideo(int position) { SimpleExoPlayer player = playerMap.get(position); if (player != null && !player.getPlayWhenReady()) { player.setPlayWhenReady(true); } } }
第二步:监听ViewPager页面切换,控制视频播放状态
在你的Activity或Fragment中,给ViewPager添加页面切换监听,切换页面时自动暂停上一个页面的视频,播放当前页面的视频:
// 假设你的ViewPager实例是viewPager,Adapter实例是mediaAdapter viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { private int previousPosition = -1; @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} @Override public void onPageSelected(int position) { // 暂停上一个页面的视频 if (previousPosition != -1) { mediaAdapter.pauseVideo(previousPosition); } // 如果当前页面是视频,自动播放 if (mediaAdapter.mediaItems.get(position).isVideo()) { mediaAdapter.playVideo(position); } previousPosition = position; } @Override public void onPageScrollStateChanged(int state) {} });
额外的生命周期优化
别忘了在页面生命周期变化时处理视频状态,比如Activity暂停时暂停当前视频,恢复时继续播放:
@Override protected void onPause() { super.onPause(); int currentPos = viewPager.getCurrentItem(); if (mediaAdapter.mediaItems.get(currentPos).isVideo()) { mediaAdapter.pauseVideo(currentPos); } } @Override protected void onResume() { super.onResume(); int currentPos = viewPager.getCurrentItem(); if (mediaAdapter.mediaItems.get(currentPos).isVideo()) { mediaAdapter.playVideo(currentPos); } }
可选优化建议
如果你的视频数量较多,为了避免内存占用过高,可以考虑实现Player实例复用(比如维护一个Player池),但这需要更复杂的管理逻辑,当前的方案已经能解决你的核心问题啦。
内容的提问来源于stack exchange,提问作者sam chaudhari
相关产品推荐
相关产品推荐

