Fragment的状态保存与恢复导致的重叠
我们在开发过程中有时会遇到Fragment内容重叠的情况,其具体原因可以参考这篇文章:从源码角度分析,为什么会发生Fragment重叠?
简单说就是Support 24.0.0之前的Fragment在onSaveInstanceState()时并没有保存mHidden状态,导致Activity在重新创建后恢复Fragment时其被新创建的恢复的fragment都是默认为show状态的,引起了内容重叠.
其实上面的文章中也提到了解决办法,不过对于Activity中的处理方式没有进行具体说明,下面我讲列出我的示例代码说明一下:
Fragment的修改:
public class BaseFragment extends Fragment {
private static final String STATE_SAVE_IS_HIDDEN = "STATE_SAVE_IS_HIDDEN";
protected Context mContext;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
log();
//fragment恢复后,恢复到原来的show,hide状态
if (savedInstanceState != null) {
boolean isSupportHidden = savedInstanceState.getBoolean(STATE_SAVE_IS_HIDDEN);
FragmentTransaction ft = getFragmentManager().beginTransaction();
if (isSupportHidden) {
ft.hide(this);
} else {
ft.show(this);
}
ft.commitAllowingStateLoss();
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
log();
outState.putBoolean(STATE_SAVE_IS_HIDDEN, isHidden());
}
}
Activity中对于Fragment的创建于恢复使用:
public class MainActivity extends BaseActivity {
private BottomNavigationBar bottomNavigationBar;
private FragmentManager fragmentManager;
private final static String TAG_HOT = "热映";
private final static String TAG_EXPLORER = "找片";
private final static String TAG_MINE = "我的";
private final static String[] TAGS = new String[]{"热映", "找片", "我的"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initListener();
bottomNavigationBar.selectTab(0);
}
private void initView() {
fragmentManager = getFragmentManager();
bottomNavigationBar = (BottomNavigationBar) findViewById(R.id.bottom_navigation_bar);
bottomNavigationBar
.addItem(new BottomNavigationItem(R.drawable.ic_hot_normal, "热映"))
.addItem(new BottomNavigationItem(R.drawable.ic_explore_normal, "找片"))
.addItem(new BottomNavigationItem(R.drawable.ic_mine_normal, "我的"))
.setMode(BottomNavigationBar.MODE_FIXED)
.initialise();
}
private void initListener() {
bottomNavigationBar.setTabSelectedListener(new BottomNavigationBar.OnTabSelectedListener() {
@Override
public void onTabSelected(int position) {
FragmentTransaction transaction = fragmentManager.beginTransaction();
Fragment fragment = fragmentManager.findFragmentByTag(TAGS[position]);
if (fragment == null) {
switch (position) {
case 0:
fragment = new HotMovieFragment();
break;
case 1:
fragment = new ExploreMovieFragment();
break;
case 2:
fragment = new MineFragment();
break;
}
if (fragment != null) {
transaction.add(R.id.fl_fragment_container, fragment, TAGS[position]);
}
} else {
transaction.show(fragment);
}
transaction.commitAllowingStateLoss();
}
@Override
public void onTabUnselected(int position) {
FragmentTransaction transaction = fragmentManager.beginTransaction();
Fragment fragment = fragmentManager.findFragmentByTag(TAGS[position]);
if (fragment != null) {
transaction.hide(fragment);
transaction.commitAllowingStateLoss();
}
}
@Override
public void onTabReselected(int position) {
}
});
}
}
需要注意的是:
transaction.add(R.id.fl_fragment_container, fragment, tag);
上面这行代码要慎用,因为Activity重建后,之前的Fragment会被系统重新恢复,如果Activity重建后你在Activity中再次add的话就会可能出现重叠的情况.这种情况下就不用再去创建了,而是应该找到系统给我们恢复了的那些Fragment,
Fragment fragment = fragmentManager.findFragmentByTag(tag);
用上面这行代码就可以找到我们恢复的fragment,如果为空我们再去创建新的.
关于Activity,Fragment重建的个人理解:
所谓Activity重建,其实应该是系统保存了Activity的状态,系统给重新创建了个新的Activity实例并且恢复了之前保存的销毁的那个Activity的状态,使得Activity像是被重启了一样,新创建的其实是一个全新的Activity,其成员变量等都是新实例的.同样,Fragment也是如此,系统会恢复之前保存的销毁了的Fragemnt的状态,而重新创建Fragment,这些重新创建的Fragment可以通过FragmentManager的findFragmentByTag()方法来获取到.
至此,我们就明白了Fragment的保存与恢复了吧.