在使用 FragmentPagerAdapter 创建 Fragment 时,默认情况下,当 Fragment 不再可见时,FragmentPagerAdapter 会将其销毁以节省资源。然而,有时候我们可能希望某些 Fragment 始终保持创建状态而不被销毁,特别是在这些 Fragment 中维护了一些重要的状态信息时。
第一种实现
为了实现这一点,我们可以重写 FragmentPagerAdapter 的 getItemPosition() 方法,并让其总是返回 POSITION_NONE。这样做会让 FragmentPagerAdapter 认为每次调用 getItem() 时都需要创建一个新的 Fragment,但实际上我们可以返回同一个 Fragment 实例。这种方法虽然有效,但它并不是最佳实践,因为它可能会导致性能问题,因为 getItem() 方法会被频繁调用。
第二种实现
一个更好的做法是继承自 FragmentStatePagerAdapter,并重写 isViewFromObject() 方法来判断是否应该保留 Fragment。不过,FragmentStatePagerAdapter 默认的行为就是不销毁 Fragment,直到它们不再被需要为止,通常不需要重写 isViewFromObject()。
下面是一个示例代码,展示了如何使用 FragmentStatePagerAdapter 来实现 Fragment 的持久化:
public class MyFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
private final List<Fragment> fragmentList = new ArrayList<>();
private final List<String> titleList = new ArrayList<>();
public MyFragmentStatePagerAdapter(FragmentManager fm) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
@Override
public int getCount() {
return fragmentList.size();
}
@Override
public CharSequence getPageTitle(int position) {
return titleList.get(position);
}
public void addFragment(Fragment fragment, String title) {
fragmentList.add(fragment);
if (title != null) {
titleList.add(title);
}
notifyDataSetChanged();
}
}
在这个例子中,MyFragmentStatePagerAdapter 继承自 FragmentStatePagerAdapter,并且在 getItem() 方法中返回了一个 Fragment 列表中的元素。Fragment 会在列表中被保存,直到 FragmentStatePagerAdapter 不再需要它们为止。
注意,BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT 表示只有当前选中的 Fragment 会调用 onResume() 方法,这有助于提高性能。
第三种实现
确实需要一个 FragmentPagerAdapter 来保持 Fragment 不被销毁,还可以按照以下方式实现:
public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> fragmentList = new ArrayList<>();
private final List<String> titleList = new ArrayList<>();
public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
@Override
public int getCount() {
return fragmentList.size();
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
// 将Fragment添加到集合中,以保持其存活
if (!fragmentList.contains(fragment)) {
fragmentList.add(fragment);
}
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
// 不销毁Fragment
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE; // 告诉ViewPager总是创建一个新的Fragment
}
@Override
public CharSequence getPageTitle(int position) {
return titleList.get(position);
}
public void addFragment(Fragment fragment, String title) {
fragmentList.add(fragment);
if (title != null) {
titleList.add(title);
}
notifyDataSetChanged();
}
}
这种方法虽然可以达到目的,但不如直接使用 FragmentStatePagerAdapter 那么高效和简洁。使用 FragmentStatePagerAdapter 是更推荐的做法。
FragmentStatePagerAdapter详细介绍
FragmentStatePagerAdapter 是 ViewPager 的一个适配器,允许在多个 Fragment 之间进行滑动切换。与 FragmentPagerAdapter 相比,FragmentStatePagerAdapter 更适合用于数量较多的 Fragment 场景,因为它仅会保存当前可见的 Fragment 的状态以及下一个将要显示的 Fragment 的状态。当 Fragment 不再需要时,它们的状态会被保存,而 Fragment 本身会被销毁。
下面是一个详细的示例,说明如何使用 FragmentStatePagerAdapter 来创建一个可以动态添加 Fragment 的 ViewPager。
1. 创建 Fragment 类
创建一个或多个 Fragment 类。
public class ExampleFragment extends Fragment {
private static final String ARG_SECTION_NUMBER = "section_number";
public static ExampleFragment newInstance(int sectionNumber) {
ExampleFragment fragment = new ExampleFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_example, container, false);
TextView textView = rootView.findViewById(R.id.section_label);
textView.setText("Section " + getArguments().getInt(ARG_SECTION_NUMBER));
return rootView;
}
}
这个 Fragment 有一个静态工厂方法 newInstance,它接受一个整数参数,并将其作为参数传递给 Fragment。在 onCreateView 方法中,我们根据传入的参数显示相应的文本。
2. 创建 FragmentStatePagerAdapter
接下来,创建一个 FragmentStatePagerAdapter 的子类,用于向 ViewPager 提供 Fragment:
public class SectionsPagerAdapter extends FragmentStatePagerAdapter {
private Context mContext;
public SectionsPagerAdapter(FragmentManager fm, Context context) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
mContext = context;
}
@Override
public Fragment getItem(int position) {
// 返回相应的Fragment实例
return ExampleFragment.newInstance(position + 1);
}
@Override
public int getCount() {
// 返回Fragment的数量
return 3; // 示例中假定有三个Fragment
}
@Override
public CharSequence getPageTitle(int position) {
return mContext.getResources().getStringArray(R.array.section_titles)[position];
}
}
在这个适配器中,getItem 方法返回一个 Fragment 的实例,getCount 方法返回 Fragment 的总数。getPageTitle 方法返回每个 Fragment 的标题。
3. 在 Activity 中使用 ViewPager
最后,在 Activity 中设置 ViewPager 和 FragmentStatePagerAdapter:
public class MainActivity extends AppCompatActivity {
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 设置适配器
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager(), this);
// 设置ViewPager
mViewPager = findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
// 设置TabLayout
TabLayout tabLayout = findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
// 设置TabLayout的Tab标题
tabLayout.getTabAt(0).setText("SECTION 1");
tabLayout.getTabAt(1).setText("SECTION 2");
tabLayout.getTabAt(2).setText("SECTION 3");
}
}
在这个 Activity 中,我们创建了一个 ViewPager 并设置了 SectionsPagerAdapter 作为它的适配器。我们还添加了一个 TabLayout 来显示 Fragment 的标题,并将其与 ViewPager 关联起来。
需要注意事项
FragmentStatePagerAdapter只会保留当前可见的Fragment和下一个即将可见的Fragment的状态。这意味着,如果Fragment数量很多,并且用户来回滑动多次,旧的Fragment会被销毁并重新创建。BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT参数确保只有当前可见的Fragment处于RESUMED状态,这有助于节省资源。- 如果需要动态添加或移除
Fragment,需要手动调整ViewPager的内容,并通知适配器数据集的变化。
FragmentPagerAdapter和FragmentStatePagerAdapter比较、区别
FragmentPagerAdapter 和 FragmentStatePagerAdapter 都是用来管理 ViewPager 中 Fragment 的适配器类,但它们在内存管理和生命周期控制上有显著的区别。下面将详细比较这两种适配器的不同之处:
1. 内存管理
-
FragmentPagerAdapter:
FragmentPagerAdapter会将所有创建的Fragment保留在内存中,即使它们当前不可见。这是因为FragmentPagerAdapter通过调用detach方法来隐藏Fragment,而不是销毁它们。这种方法适用于需要管理少量Fragment的场景,因为可以避免频繁创建和销毁Fragment的开销。
-
FragmentStatePagerAdapter:
FragmentStatePagerAdapter会销毁不可见的Fragment,仅保留它们的状态。当用户再次滑动到这些Fragment时,它们将被重新创建。这种方法适用于需要处理大量Fragment的情况,因为它能够节省内存。
2. Fragment 生命周期
-
FragmentPagerAdapter:
FragmentPagerAdapter会保持所有Fragment的生命周期,这意味着它们的生命周期状态(如onResume、onPause)不会改变,除非它们被销毁。
-
FragmentStatePagerAdapter:
FragmentStatePagerAdapter会在Fragment不可见时销毁它们,并保存它们的状态。当用户再次访问这些Fragment时,它们的状态会被恢复,但它们会经历完整的生命周期,包括重新创建、初始化等过程。
3. 性能和内存使用
-
FragmentPagerAdapter:
- 由于它会保存所有
Fragment的实例,因此可能会导致较高的内存消耗。但如果Fragment数量有限,这种方法可以提供更快的响应速度,因为不需要重新创建Fragment。
- 由于它会保存所有
-
FragmentStatePagerAdapter:
- 相对于
FragmentPagerAdapter,它更适合处理大量Fragment的场景,因为它会销毁不可见的Fragment,从而减少内存占用。虽然这种方法可能会在用户切换Fragment时带来一些延迟,但它更适合内存敏感的应用程序。
- 相对于
4. 实现方式
-
FragmentPagerAdapter:
- 需要实现
getItem(int)和getCount()方法。getItem(int)返回指定位置的Fragment实例,而getCount()返回Fragment的总数。
- 需要实现
-
FragmentStatePagerAdapter:
- 同样需要实现
getItem(int)和getCount()方法。getItem(int)返回指定位置的Fragment实例,而getCount()返回Fragment的总数。
- 同样需要实现
5. 适用场景
-
FragmentPagerAdapter:
- 适用于少量的
Fragment,如一组选项卡。
- 适用于少量的
-
FragmentStatePagerAdapter:
- 适用于大量的
Fragment或者Fragment内容动态变化的情况。
- 适用于大量的
总结
选择 FragmentPagerAdapter 还是 FragmentStatePagerAdapter 取决于你的应用场景:
- 如果你的应用中
Fragment的数量较少,并且这些Fragment需要在后台持续保持活跃状态,那么FragmentPagerAdapter是一个合适的选择。 - 如果你的应用需要处理大量的
Fragment,或者你关心内存使用效率,那么FragmentStatePagerAdapter会更合适,因为它能够在Fragment不可见时释放内存资源。
当前文章价值1.59元,扫一扫支付后添加微信提供帮助!(如不能解决您的问题,可以申请退款)

评论已关闭!