FragmentStateAdapter与FragmentPagerAdapter对比

121 阅读2分钟

以下从多个维度对两者进行对比,包括核心代码、内存管理、适用场景等。


1. 所属组件及基类

  • FragmentPagerAdapter

    • 用于 ViewPager(旧版组件)。
    • 继承自 PagerAdapter
    • 适用于页面数量较少且相对静态的场景。
  • FragmentStateAdapter

    • 用于 ViewPager2(基于 RecyclerView 实现)。
    • 继承自 RecyclerView.Adapter<FragmentViewHolder>
    • 更灵活,支持动态数据、垂直滑动、RTL 布局等。

2. 内存管理策略

  • FragmentPagerAdapter

    • 不销毁 Fragment:仅调用 detach() 分离视图,Fragment 实例保留在内存中。
    • 页面切换速度快,但内存占用高。
    • 适合页面固定且数量少的情况(如 Tab 导航)。
  • FragmentStateAdapter

    • 销毁不可见 Fragment:通过 remove()saveState() 销毁实例,但保存状态(类似 FragmentStatePagerAdapter)。
    • 内存占用低,适合动态或大量页面(如轮播图、长列表)。
    • 默认保留当前页及相邻页,其余销毁。

3. 核心代码对比

FragmentPagerAdapter 实现
public class MyPagerAdapter extends FragmentPagerAdapter {
    private static final int NUM_PAGES = 3;

    public MyPagerAdapter(FragmentManager fm) {
        super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
    }

    @Override
    public Fragment getItem(int position) {
        return MyFragment.newInstance(position); // 创建新 Fragment
    }

    @Override
    public int getCount() {
        return NUM_PAGES;
    }

    // 可选:数据更新时标记位置无效
    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }
}
FragmentStateAdapter 实现
public class MyStateAdapter extends FragmentStateAdapter {
    private static final int NUM_PAGES = 3;

    public MyStateAdapter(FragmentActivity fa) {
        super(fa);
    }

    @Override
    public Fragment createFragment(int position) {
        return MyFragment.newInstance(position); // 创建新 Fragment
    }

    @Override
    public int getItemCount() {
        return NUM_PAGES;
    }

    // 数据更新时直接调用 notify 方法
    public void updateData() {
        notifyDataSetChanged();
    }
}

4. 数据更新方式

  • FragmentPagerAdapter

    • 需重写 getItemPosition() 返回 POSITION_NONE,并调用 notifyDataSetChanged()
    • 强制 ViewPager 重新加载所有页面,可能引发性能问题。
  • FragmentStateAdapter

    • 直接调用 notifyItemChanged()notifyDataSetChanged()(继承自 RecyclerView.Adapter)。
    • 支持增量更新,性能更优。

5. 生命周期差异

  • FragmentPagerAdapter

    • Fragment 实例始终存在,onDestroyView() 被调用但 onDestroy()onDetach() 不会触发。
    • 适合需要保持 Fragment 活跃状态的场景。
  • FragmentStateAdapter

    • 不可见 Fragment 会被销毁,触发完整的 onDestroy() 生命周期。
    • 通过 SavedState 恢复状态,适合内存敏感场景。

6. 构造函数差异

  • FragmentPagerAdapter

    • 需传入 FragmentManagerBEHAVIOR 参数(如 BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT)。
  • FragmentStateAdapter

    • 需传入 FragmentActivityFragment(内部自动获取 FragmentManager)。

7. 适用场景总结

场景FragmentPagerAdapterFragmentStateAdapter
页面数量少且固定✔️ 适合❌ 过度设计
页面数量多或动态变化❌ 内存溢出风险✔️ 适合
需要保存 Fragment 状态❌ 需手动处理✔️ 自动保存
垂直滑动/RTL 支持❌ 不支持✔️ 支持(ViewPager2)

8. 关键结论

  • 迁移建议:优先使用 ViewPager2 + FragmentStateAdapter,因其功能更强大且内存友好。
  • 性能取舍:少量页面用 FragmentPagerAdapter(快速响应),大量页面用 FragmentStateAdapter(低内存占用)。
  • 数据更新FragmentStateAdapter 的增量更新更高效。