彻底解决Fragment重叠的问题

时间:2021-12-05 18:34:06

在布局应用一级页面时很多App都会采取BottomBar + Fragment切换来构建。一般Fragment会使用FragmentManager管理,就是在一个FrameLayout构成的ContentView上做show和hide,

在这里有一个问题需要注意,在这种有多个按钮处于一个屏幕可以快速切换Fragment的UI布局下,不要使用add和replace去切换fragment,使用show和hide去切换是最好的选择,因为show和hide本质上是在控制Fragment中View的Visiblity,而执行replace则会触发fragment的detach()函数与Activity解除关联,如果此时用户快速点击,在detach还没执行完就执行attach(),很容易产生IllegalStateException:no host;应用直接崩溃。

使用show和hide很容易出现的问题就是承载Fragmen的Activity在旋转屏幕,资源不足被释放资源然后恢复重建这些情况下,被承载的Fragment在恢复时没能正确恢复状态,然后全部都显示了出来。解决这个问题的核心就是在Fragment恢复时全部隐藏,然后根据当前显示的Fragment的TAG显示Fragment。

本来想把这段代码封装成一个Activity基类,后面想想应用一级的需求页面千奇百怪,封装了也没什么通用性,就在这里记录一下,分享一下顺便备忘了=。=

上代码:

public abstract class MainActivity extends BaseActivity {

private static final String SAVED_CURRENT_ID = "currentId";

public static final List<String> PAGE_TAGS = new ArrayList<>();
private List<Class<? extends BaseFragment>> fragmentClasses = Arrays.asList(HomeFragment.class,
MoreFragment.class, ProfileFragment.class); //自定义的Fragment,主要目的是在初始化时能够通过循环初始化,与重建时的恢复统一
private List<Fragment> fragments = new ArrayList<>();

private FragmentManager mFragmentManager;

private int currentId = 0;

@Override
public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
setContentView(R.layout.activity_main);
initFragments();
}

private void initFragments(Bundle savedInstanceState) {
mFragmentManager = getSupportFragmentManager();
for(int i = 0; i < fragments.size(); i++) {
fragments.set(i, mFragmentManager.findFragmentByTag(PAGE_TAGS.get(i)));
if(fragments.get(i) == null) {
try {
fragments.set(i,fragmentClasses.get(i).newInstance());
} catch (Exception e) {
e.printStackTrace();
}
}
//先重置所有fragment的状态为隐藏,彻底解决重叠问题
if(fragments.get(i).isAdded()) {
mFragmentManager.beginTransaction()
.hide(fragments.get(i))
.commitAllowingStateLoss();
}
}
if(savedInstanceState != null) {
int cachedId = savedInstanceState.getInt(SAVED_CURRENT_ID, 0);
if(cachedId >= 0 && cachedId <= 4) {
currentId = cachedId;
}
}
switchFragment(currentId, false);
}

@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(SAVED_CURRENT_ID, currentId);
}

private void switchFragment(int index) {
switchFragment(index, true);
}

private void switchFragment(int index, boolean anim) {
/* Fragment 切换 */
FragmentTransaction transaction = mFragmentManager.beginTransaction();
if(anim) { //显示切换动画
if(index > currentId) {
transaction.setCustomAnimations(R.anim.slide_right_in, R.anim.slide_left_out);
}
else {
transaction.setCustomAnimations(R.anim.slide_left_in, R.anim.slide_right_out);
}
}
if(fragments.get(index).isAdded()) {
transaction.hide(fragments.get(currentId));
transaction.show(fragments.get(index));
}
else {
transaction.hide(fragments.get(currentId));
transaction.add(getFragmentContainerLayoutRes(), fragments.get(index), PAGE_TAGS.get(index));
transaction.show(fragments.get(index));
}
transaction.setTransitionStyle(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
transaction.commitAllowingStateLoss();
currentId = index;
}


}