ViewPager结合View与Fragment实现视频播放列表的播放异常问题
解决ViewPager切换时视频播放页面错位的问题
嘿,我来帮你搞定这个头疼的问题!你遇到的核心问题是ViewPager的预加载机制+播放器实例没有和对应页面绑定,导致切换页面时播放器还“粘”在最后打开的页面上。下面给你一步步的解决方案:
1. 让每个Fragment独立管理自己的播放器
别在PagerAdapter里全局存播放器实例了,让每个Fragment自己初始化、持有、释放对应的视频播放器。这样每个页面的播放状态都是独立的,不会串页。
比如写一个VideoFragment:
public class VideoFragment extends Fragment { private VideoView videoView; private String videoUrl; // 静态方法传参创建Fragment public static VideoFragment newInstance(String videoUrl) { VideoFragment fragment = new VideoFragment(); Bundle args = new Bundle(); args.putString("VIDEO_URL", videoUrl); fragment.setArguments(args); return fragment; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootView = inflater.inflate(R.layout.fragment_video_player, container, false); videoView = rootView.findViewById(R.id.video_view); videoUrl = getArguments().getString("VIDEO_URL"); setupPlayer(); return rootView; } private void setupPlayer() { videoView.setVideoPath(videoUrl); // 准备好后自动播放 videoView.setOnPreparedListener(mediaPlayer -> mediaPlayer.start()); } // 页面暂停时暂停播放 @Override public void onPause() { super.onPause(); if (videoView != null && videoView.isPlaying()) { videoView.pause(); } } // 页面恢复时继续播放 @Override public void onResume() { super.onResume(); if (videoView != null) { videoView.start(); } } // 销毁页面时释放播放器资源 @Override public void onDestroyView() { super.onDestroyView(); if (videoView != null) { videoView.stopPlayback(); videoView = null; } } }
2. 用FragmentPagerAdapter管理页面(别混写View和Fragment)
你之前用View+Fragment混合布局容易出问题,建议统一用Fragment来做ViewPager的页面。用FragmentPagerAdapter时,记得加上BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT,这个参数会让只有当前显示的Fragment走到onResume状态,其他预加载的Fragment停在onStart,刚好配合我们上面写的播放逻辑。
PagerAdapter代码示例:
public class VideoPagerAdapter extends FragmentPagerAdapter { private List<String> videoUrlList; public VideoPagerAdapter(FragmentManager fm, List<String> videoUrls) { // 关键参数:只让当前Fragment触发onResume super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); this.videoUrlList = videoUrls; } @Override public Fragment getItem(int position) { return VideoFragment.newInstance(videoUrlList.get(position)); } @Override public int getCount() { return videoUrlList.size(); } }
3. 在Activity里处理页面切换的播放状态
虽然上面的生命周期回调已经能处理大部分情况,但保险起见,你可以监听ViewPager的页面切换事件,手动控制上一页暂停、当前页播放:
public class PlaylistActivity extends AppCompatActivity { private ViewPager viewPager; private VideoPagerAdapter adapter; private VideoFragment currentFragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_playlist); // 获取传过来的播放列表和起始位置 List<String> videoUrls = getIntent().getStringArrayListExtra("PLAYLIST"); int startPos = getIntent().getIntExtra("START_POS", 0); viewPager = findViewById(R.id.view_pager); adapter = new VideoPagerAdapter(getSupportFragmentManager(), videoUrls); viewPager.setAdapter(adapter); viewPager.setCurrentItem(startPos); // 初始化当前显示的Fragment currentFragment = (VideoFragment) adapter.getItem(startPos); // 监听页面切换 viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} @Override public void onPageSelected(int position) { // 暂停上一页的视频 if (currentFragment != null) { currentFragment.onPause(); } // 获取并播放当前页的视频 currentFragment = (VideoFragment) adapter.getItem(position); currentFragment.onResume(); } @Override public void onPageScrollStateChanged(int state) {} }); } }
4. 如果你非要保留View+Fragment混合布局
如果因为某些原因不能全用Fragment,那你需要给每个View设置唯一的Tag,在PagerAdapter的instantiateItem里初始化对应View的播放器,切换页面时通过Tag找到对应的View和播放器,暂停其他的,播放当前的。比如:
@Override public Object instantiateItem(ViewGroup container, int position) { View view = inflater.inflate(R.layout.item_video_page, container, false); view.setTag("VIDEO_PAGE_" + position); VideoView videoView = view.findViewById(R.id.video_view); videoView.setVideoPath(videoUrlList.get(position)); container.addView(view); return view; }
然后在页面切换时:
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageSelected(int position) { // 遍历所有页面,暂停非当前页的播放 for (int i = 0; i < viewPager.getChildCount(); i++) { View page = viewPager.findViewWithTag("VIDEO_PAGE_" + i); if (page != null) { VideoView vv = page.findViewById(R.id.video_view); if (i != position && vv.isPlaying()) { vv.pause(); } else if (i == position) { vv.start(); } } } } });
这个方法不如全用Fragment优雅,但也能解决问题。
内容的提问来源于stack exchange,提问作者ppgdn
相关产品推荐
相关产品推荐

