问题:
-
Activity重建后,为什么 ViewPager里的Fragment多了一倍
- 我的case:自己在ViewPager的adapter里 new的Fragment,系统又 restore 一个 Fragment。
- 然后业务逻辑用 new的Fragment,系统却用restore的Fragment,导致new的Fragment声明周期都没走,之后就会各种异常。
-
怎样复现 activity 被回收: 开发者选项,点击 不保存活动
- 这样Activity stack中不可见的(即不在stack 顶部的Activity都会被回收 (走onActivityDestroyed回调))
-
什么时候,FragmentManager的内容被 restore: Activity的 super.onCreate(savedInstanceState); 执行完后恢复
- debug查看
- 怎么创建Fragment (下文有写)
结论先行
- 创建Fragment时,要考虑到Fragment被恢复的case,这时不该 new,而是 恢复状态
-
Activity被 销毁 重建后,如果用ViewPager用的 FragmentStatePagerAdapter,系统会重新创建 Fragment 实例
- Activity被销毁时,FragmentManagetImpl 调用saveAllState,将保存Fragment的状态 FragmentManagerState(Parcelable子类 IPC跨进程使用)。
- Activity重建时,会根据 FragmentManagerState ,重新创建Fragment
-
编写Activity时,一定要考虑他会被destroy的情景(比如内存紧张, 这不受你控制)
- 一个内存泄漏就可以引发,当然泄漏多了就OOM,看起来指标不治本
Parcelable saveAllState() {
FragmentManagerState fms = new FragmentManagerState();
fms.mActive = active;
fms.mAdded = added;
fms.mBackStack = backStack;
怎么创建Fragment
创建时,一定要判断 FragmentMananger 中是否已有Fragment
Fragment的创建、恢复(不用ViewPager)
private MainFragment mainFragment;
private SecondaryFragment secondaryFragment;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mainFragment = (MainFragment) fm.getFragment(savedInstanceState, MainFragment.TAG);
secondaryFragment = (SecondaryFragment) fm.getFragment(savedInstanceState, SecondaryFragment.TAG);
}
if (mainFragment == null) {
mainFragment = new MainFragment();
}
if(secondaryFragment == null){
secondaryFragment = new SecondaryFragment()
}
// ViewPager 的相关操作
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mainFragment.isAdded()) {
fm.putFragment(outState, MainFragment.TAG, mainFragment);
}
if (secondaryFragment.isAdded()) {
fm.putFragment(outState, SecondaryFragment.TAG, secondaryFragment);
}
}
Fragment + ViewPager
YourActivity
private final YourFragmentAdapter adapter = new YourFragmentAdapter(getSupportFragmentManager());
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
adapter.initData();
viewPager.setAdapter(adapter);
}
//...........
YourAdapter
public class YourAdapter extends FragmentStatePagerAdapter {
private final List<Fragment> tabFragments = new ArrayList<>();
public YourAdapter(FragmentManager supportFragmentManager) {
super(supportFragmentManager);
}
private void initData(FragmentManager fragmentManager) {
YouFragment1 normalFragment = null;
YouFragment2 specialFragment = null;
if (fragmentManager != null && fragmentManager.getFragments().size() > 0) {
List<Fragment> fragments = fragmentManager.getFragments();
for (int i = 0; i<fragments.size(); i++) {
Fragment fragment = fragments.get(i);
if (fragment instanceof YouFragment1) {
normalFragment = (YouFragment1) fragment;
} else if (fragment instanceof YouFragment2) {
specialFragment = (YouFragment2) fragment;
}
}
}
if (normalFragment == null) {
normalFragment = YouFragment1.newInstance();
}
if (specialFragment == null) {
specialFragment = YouFragment2.newInstance();
}
tabFragments.add(normalFragment);
tabFragments.add(specialFragment);
}
@Override
public Fragment getItem(int position) {
return tabFragments.get(position);
}
@Override
public int getCount() {
return tabFragments.size();
}
FragmentPagerAdapter 与 FragmentStatePagerAdapter
-
看这个
文章
-
FragmentPagerAdapter 是将Fragment保存到 FragmentManager里,进行复用
- 适合静态的、少界面的ViewPager,加载Fragment过多,会增加内存消耗
-
FragmentStatePagerAdapter 是通过对 FragmentManagerState 来实现状态的复用(Fragment会被新创建,但状态一致)
- 默认不保存所有的Fragment,而是 前页面1个+当前+后页面1个= 3个页面被缓存
- 前面、后面页面缓存个数通过 ViewPager setOffscreenPageLimit (int limit)设置
- 可以在Activity销毁重建后,回复UI状态
版权声明:本文为zhjali123原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。