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

Android中ViewPager滑动时如何停止视频播放?解决相邻页面视频仍播放问题

解决ViewPager中视频滑动相邻页面仍播放的问题

我来帮你搞定这个视频播放的问题!你的核心问题其实和ViewPager的预加载机制,以及你当前的Player管理方式有关,咱们一步步来解决:

问题根源分析

  1. ViewPager默认预加载:ViewPager默认会预加载当前页面左右各1个页面(offscreenPageLimit=1),这意味着你滑动到相邻页面时,原视频页面并没有被销毁(destroyItem方法不会触发),所以视频会继续在后台播放。
  2. 全局单一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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:13:57