Android ViewPager切换3个Fragment时滚动卡顿问题求助
你已经排除了指示器更新导致的卡顿,那咱们从其他常见的性能坑入手来解决这个问题,结合你的代码片段,给你几个针对性的方案:
1. 给Fragment加上懒加载,避免预加载耗时操作
默认ViewPager会预加载相邻的Fragment(默认1个),如果你的Fragment在onCreateView里直接做了网络请求、大图片加载、复杂数据处理这些耗时活,主线程肯定会被卡爆,滚动自然不流畅。
给你一个现成的懒加载Fragment基类,直接让你的Fragment继承它就行:
public abstract class LazyLoadFragment extends Fragment { private boolean isViewCreated = false; private boolean isFirstVisible = true; @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); isViewCreated = true; // 视图建好后马上检查是否可见,触发懒加载 checkLazyLoad(); } @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); checkLazyLoad(); } private void checkLazyLoad() { // 只有视图已创建、当前Fragment可见、且是第一次可见时,才执行加载逻辑 if (isViewCreated && getUserVisibleHint() && isFirstVisible) { lazyLoad(); isFirstVisible = false; } } // 把你原来在onCreateView里的耗时操作,放到这个方法里实现 protected abstract void lazyLoad(); }
这样只有当Fragment真正被用户看到时,才会执行那些重操作,预加载的时候只会创建视图,不会做耗时活,滚动就顺畅多了。
2. 优化ViewPager的Adapter实现
你用的FragmentPagerAdapter,在AndroidX里一定要注意构造方法的参数!加上BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT,这个参数会让非当前页的Fragment处于STARTED状态,减少资源占用,对滚动流畅度提升很明显:
public class ViewPagerAdapter extends FragmentPagerAdapter { private final List<Fragment> fragments = new ArrayList<>(); public ViewPagerAdapter(FragmentManager fm) { // 关键参数!别漏了 super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); } public void addFragment(Fragment fragment) { fragments.add(fragment); } @Override public Fragment getItem(int position) { return fragments.get(position); } @Override public int getCount() { return fragments.size(); } }
另外,别在getItem方法里每次都new Fragment,提前把Fragment实例化好存到列表里,避免重复创建带来的性能损耗。
3. 检查布局的过度绘制和嵌套层级
过度绘制和过深的布局嵌套会让视图渲染变慢,滚动时自然卡顿。你可以用Android Studio的Profile工具开过度绘制检测:
- 连接设备打开你的应用,点Android Studio右上角的Profile,选你的应用,然后点Layout Inspector旁边的三个点,选Enable Overdraw Debugging
- 如果看到红色区域很多,说明过度绘制严重,赶紧优化:比如移除父布局不必要的背景,用ConstraintLayout替代多层嵌套的LinearLayout/RelativeLayout。
4. 排查主线程的耗时操作
如果上面的方法都试过还是卡,那大概率是有耗时操作跑在主线程了。用CPU Profiler抓个调用栈看看:
- 打开Profile选CPU,点Record按钮,然后滚动ViewPager,停止录制后看哪个方法占用CPU最高,把它移到子线程里执行,比如用
Coroutine或者AsyncTask,更新UI的时候再切回主线程。
最后提一句,别随便把setOffscreenPageLimit设为0,虽然能关闭预加载,但切换Fragment时会重新创建,反而会出现白屏和卡顿,配合懒加载用默认的1就好。
内容的提问来源于stack exchange,提问作者jobin

