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

Android ViewPager加载多Fragment致Activity启动慢ANR,getItem报错如何解决

问题根源

  1. 执行时序错误:你通过Handler(getMainLooper()).post()提交的任务会被加入主线程消息队列尾部等待执行,而onCreate里的fragments.addAll()是同步执行的代码,执行合并操作时两个分批创建Fragment的任务根本还未运行,所以fragments列表为空,getItem调用时自然触发下标越界报错。
  2. 优化方向错误:你完全不需要提前创建所有30个Fragment,ViewPager的PagerAdapter本身自带按需加载机制,默认仅会缓存当前页和左右相邻1-2个Fragment,提前创建全部属于完全不必要的性能浪费,反而会拖慢启动速度、增大ANR风险。

解决方案

方案1:快速修复当前报错(不推荐,仅解决崩溃问题)

调整执行时序,等两个异步创建任务都执行完成后,再合并列表、设置ViewPager的Adapter:

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 先初始化ViewPager,暂时不设置Adapter
    viewPager = findViewById(R.id.viewpager);

    new Handler(getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            for (int i = 0; i <= 14; i++){
                fragmentsType1.add(QuestionFragment1.newInstance(questions.get(i), i));
            }
            checkAndInitAdapter();
        }
    });

    new Handler(getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            for (int i = 15; i <= 29; i++){
                fragmentsType2.add(QuestionFragment2.newInstance(questions.get(i), i));
            }
            checkAndInitAdapter();
        }
    });
}

private synchronized void checkAndInitAdapter() {
    // 两个任务都执行完成再初始化Adapter
    if (fragmentsType1.size() == 15 && fragmentsType2.size() == 15) {
        fragments.addAll(fragmentsType1);
        fragments.addAll(fragmentsType2);
        viewPager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));
    }
}

方案2:彻底优化启动速度(推荐,从根源解决ANR问题)

放弃提前创建所有Fragment的思路,直接在Adapter的getItem方法中按需创建Fragment,不需要维护全局的Fragment列表:

// Adapter代码修改为如下
@Override
public Fragment getItem(int position) {
    if (position <= 14) {
        return QuestionFragment1.newInstance(questions.get(position), position);
    } else {
        return QuestionFragment2.newInstance(questions.get(position), position);
    }
}

@Override
public int getCount() {
    return questions.size(); // 直接返回题目列表长度即可
}

这种方案下Activity启动时仅会创建当前需要展示的1-3个Fragment,启动耗时会从3秒降到数百毫秒级别,完全避免ANR风险。


额外优化建议

从你提供的Fragment代码来看,还可以做如下优化进一步降低卡顿:

  1. Html.fromHtml解析标题的操作可以提前放到子线程完成,解析结果存在Question对象中,不需要每次创建Fragment时再在主线程解析
  2. 选项图片不要直接调用setImageResource加载,改用图片加载库异步加载,避免主线程阻塞
  3. 使用FragmentPagerAdapter时传入BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT参数,减少不必要的Fragment生命周期回调

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 00:36:04