解决 ViewPager + Fragment 的恢复问题
你可能是这么使用 ViewPager + Fragment 这个组合的:
public class MainActivity extends AppCompatActivity {
private ViewPager mViewPager;
private List<Fragment> mFragments;
private CustomViewPagerAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = (ViewPager) findViewById(R.id.view_pager);
mFragments = new ArrayList<>();
mFragments.add(new SimpleFragment());
mFragments.add(new SimpleFragment());
mAdapter = new CustomViewPagerAdapter(getSupportFragmentManager(), mFragments);
mViewPager.setAdapter(mAdapter);
}
public class CustomViewPagerAdapter extends FragmentStatePagerAdapter {
private List<Fragment> mFragments;
public CustomViewPagerAdapter(FragmentManager manager, List<Fragment> fragments) {
super(manager);
mFragments = fragments;
}
@Override
public Fragment getItem(int position) {
return mFragments == null ? null : mFragments.get(position);
}
@Override
public int getCount() {
return mFragments == null ? 0 : mFragments.size();
}
}
其中 SimpleFragment 就是一个普通的 Fragment,这里就不贴代码了。
正常情况使用,一般不会有什么问题——这里的正常情况,包括应用冷启动,然后你按 Home 键盘放到后台,然后再回来。但是有一种情况我们经常会忽视:当这个 Activity 被杀再次回来的情况。
一般来说这个情况在内存低的时候容易出现,毕竟内存少了被杀很正常,但是现在动辄大内存的 Android 设备上可能要重现这个有点困难——其实也不困难,到开发者选项里,把 “不保留活动” 开关打开就可以了,这时候再测试,嗯可能简单地使用并没有发现什么问题,但是没发现不代表就没有问题。
首先,Activity 的 onCreate 方法将会被再次调用,Fragment 的列表依然会再次初始化,两个 Fragment 都是重新 new 出来的。但是跟第一次启动的区别在于,savedInstanceState 这个变量不再是 null。同时,这种情况(不保留 Activity)下,Activity 是会被销毁的,但是 Fragment 却不会,所以就会导致有 Fragment 重叠的问题——当前显示屏上显示的 Fragment 并不是你当前 Activity 里的那个。
为了解决这个,可以从以下方面入手:
- 重写
protected void onSaveInstanceState(Bundle outState)
方法,并在里面不做任何操作(不调 super 的方法);这样在 Activity 被销毁的时候,FragmentManager 里的 Fragment 也不会得到保留。 - 在 onCreate 方法里,如果 savedInstanceState 不为 null,那么拿到之前的 Fragment,重新添加到列表里。
嗯,第二个方法有个问题:怎样拿到之前的 Fragment?
FramgentManager 有两个方法:
- findFragmentByTag(String tag);
- findFragmentById(int id);
看以上的代码 ,你并没有发现有任何地方给这些 Fragment 设置 Id/Tag 啊?嗯,事实上,你对这两个 Fragmente 输出一下的话,就可以看到,这两个 Fragment 的 id,就是这个 ViewPager 的 Id,然后 Tag 是 null。
你可能会说:等等,我看到 SO 里,说这个 Tag 可以这样得到的啊 "android:switcher:"+R.id.page+pos; 当我查阅源码的时候,发现 FragmentStatePagerAdapter 并没有给 Fragment 设置这么一个东西,估计是新版本的 Support 库(当前我使用的是 25.2.0)已经移除了这样的方法,所以得到的 Tag 是 null。
所以也别无他法了,只有使用第一个方法:重写 onSaveInstanceState 解决。
Subscribe to JuniperPhoton's Blog
Get the latest posts delivered right to your inbox