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

ViewPager的PagerAdapter重复调用导致Exoplayer音频异常播放问题求助

核心问题根因

  • ExoPlayer实例管理错误:你将ImageSlideAdapter中的player声明为静态变量,导致所有视频项共用同一个播放器实例,操作时互相干扰,这是多音频同时播放的核心原因。
  • ViewPager预加载逻辑冲突:setOffscreenPageLimit(0)是无效配置,Android ViewPager的最小预加载页数为1,前后相邻页会提前执行instantiateItem初始化,视频页预加载时调用player.prepare()后没有主动暂停,就会触发后台播放。
  • 状态判断逻辑错误:onPageSelected里的播放/暂停判断逻辑混乱,currentPage == position的判断永远为真,导致判断条件完全失效。
  • 资源释放时机错误:OnAttachStateChangeListener里的暂停/释放逻辑完全错误,页面detach时应该直接释放当前页的播放器,而不是根据全局页面判断。
  • 播放器状态未统一管理:没有统一的逻辑控制只有当前选中的视频页可以播放,其余页面都要暂停并释放资源。

具体修复步骤

1. 修改ImageSlideAdapter,移除静态player,统一管理播放器实例

首先移除全局静态player变量,新增SparseArray存储每个视频位置对应的独立ExoPlayer实例:

// ImageSlideAdapter类顶部新增成员变量
private SparseArray<ExoPlayer> playerMap = new SparseArray<>();

修改instantiateItem中的视频初始化逻辑,创建player后存入map,prepare后主动暂停,等待页面选中再播放,同时移除原有无效的OnAttachStateChangeListener逻辑:

if (currentFile.getAbsolutePath().endsWith(".mp4")) {
    statusImageView.setVisibility(View.GONE);
    playerView.setVisibility(View.VISIBLE);
    // 每个视频项创建独立播放器实例
    ExoPlayer player = new ExoPlayer.Builder(context).build();
    // 存入map统一管理
    playerMap.put(position, player);
    MediaItem mediaItem = MediaItem.fromUri(filePath);
    player.addMediaItem(mediaItem);
    playerView.setPlayer(player);
    player.prepare();
    // 初始化后主动暂停,避免预加载时自动播放
    player.setPlayWhenReady(false);
    playerView.setBackgroundColor(context.getResources().getColor(android.R.color.black));
}

修改destroyItem方法,页面销毁时释放对应播放器资源:

@Override
public void destroyItem(@NonNull @NotNull ViewGroup container, int position, @NonNull @NotNull Object object) {
    // 销毁页面之前先释放对应位置的播放器
    ExoPlayer player = playerMap.get(position);
    if (player != null) {
        player.release();
        playerMap.remove(position);
    }
    container.removeView((ConstraintLayout) object);
}

2. 重构StatusViewer的onPageSelected逻辑,统一控制播放状态

@Override
public void onPageSelected(int position) {
    currentPage = position;
    File currentFile = modelFeedArrayList.get(position);
    // 先暂停所有已创建的播放器,避免多实例同时播放
    for(int i = 0; i < imageSlideAdapter.playerMap.size(); i++) {
        ExoPlayer player = imageSlideAdapter.playerMap.valueAt(i);
        if (player != null) {
            player.setPlayWhenReady(false);
        }
    }
    // 仅当前选中页为视频时才触发播放
    if (currentFile.getAbsolutePath().endsWith(".mp4")) {
        ExoPlayer currentPlayer = imageSlideAdapter.playerMap.get(position);
        if (currentPlayer != null) {
            currentPlayer.setPlayWhenReady(true);
        }
    }
}

3. 处理点击事件冲突

给TouchImageView和PlayerView的点击事件增加拦截,点击时仅处理当前选中页的逻辑,不要触发其他页面的播放:

  • TouchImageView点击时不要修改播放器状态,统一走onPageSelected的控制逻辑
  • PlayerView点击时仅控制当前播放器的暂停/播放,不要影响其他实例

替代方案推荐

如果需要更平滑的体验,可替换为ViewPager2实现,ViewPager2基于RecyclerView实现,默认支持懒加载,不会预加载不必要的页面,可大幅降低播放器状态管理的复杂度。

内容的提问来源于stack exchange,提问作者Devarshi Rawal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 08:09:00