引入
现在 APP 的主页面大多采用“单 Activity + 多 Fragment”的形式。多 Fragment 的使用需要解决两个问题:
- Fragment 怎么依附在 Activity 上
- Fragment 间的切换
对于第一个问题,可以利用 FrameLayout 来解决,FrameLayout 可以作为承载 Fragment 的容器,又可以成为 Activity 布局的一部分,这样就可以把 Fragment 和 Activity 连接起来。
重点是第二个问题,如果进行 Fragment 的切换。Fragment 的切换需要用到 FragmentTransaction。接下来就介绍一下 FragmentTransaction 的 创建以及它的 replace, add, hide, show 等方法,并学会如何使用这些方法完成 Fragment 的切换。
FragmentTransaction 的创建和提交
首先是 FragmentTransaction 的创建:
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
创建完后 FragmentTransaction 可以进行相应的操作(replace, add 等),具体操作之后再说。
最后记得进行提交:
ft.commit();
注意:
- 确保一次业务中,所有的事务通过同一个 FragmentTransaction 对象进行 commit。
- 如果一次业务中 commit 次数大于 1 次,那么就会报 java.lang.IllegalStateException: commit already called 异常,所以同一个 FragmentTransaction 对象只能 commit 一次。
FragmentTransaction 进行事务处理
FragmentTransaction 在进行事务处理的时候,主要是调用这四个方法:replace, add, hide, show。它们的作用和区别如下:
方法表
操作 | 说明 | 备注 |
---|---|---|
replace | 先将之前存在于容器的 Fragment 全部移除(销毁),然后添加要显示的 Fragment(会重新执行一遍它的生命流程) | 如果容器中已经存在和要添加的 Fragment 相同的实例(注意:相同是指同一个对象,同一个类但对象不同, 例如两次 new,则不算相同) 那么它只会将除此以外的其他 Fragment 清除,而不会再次添加相同的 Fragment 实例 |
add | 不会将之前存在于容器的 Fragment 移除,而是继续往容器里添加 Fragment | 1. 如果同一个对象多次添加会报错 2. 由于 add 操作不会将之前的 Fragment 删除,所以会造成多个 Fragment 重叠的现象,要解决这个问题可以使用 hide 隐藏之前的 Fragment |
hide | 隐藏容器中的 Fragment | |
show | 将隐藏的 Fragment 显示出来 | hide 和 show 是配对的,当要显示隐藏的 Fragment A 时,就 show(A);而对于其他 Fragment,则先 hide 起来,等之后要显示时再 show |
实现切换 Fragment
通过上面介绍的几个方法可以实现 Fragment 的切换。有两种实现方式:
- 使用 replace
- add, hide, show 配合使用
第一种方式比较简单,想要显示哪个 Fragment 就 replace 它就行了。例如我要显示 FragmentA,那么我就这样写:
ft.replace(R.id.container, FragmentA);
其中 ft 是上面创建的 FragmentTransaction,R.id.container 是容器(FrameLayout) 的 id。
这种方式的优点是使用简单,但缺点是导致每次切换 Fragment 都会重新执行该 Fragment 的生命周期,影响性能。
由于会影响性能,所以不推荐第一种方式。
重点看第二种方式,第二种方式需要 add, hide, show 配合使用,它的步骤如下:
- 如果要切换的 Fragment 还未创建,就先创建 Fragment 对象,并通过 add 方法添加到容器中
- 通过 hide 方法隐藏当前的 Fragment,然后通过 show 方法显示要切换的 Fragment
具体代码如下:
private void changeFragment(Fragment showFragment) {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
if (showFragment == null) {
showFragment = new ShowFragment();
ft.add(R.id.container, showFragment);
}
// mCurrFragment 存储当前显示的 Fragment
if (mCurrFragment != null) {
ft.hide(mCurrFragment);
}
ft.show(showFragment);
mCurrFragment = showFragment;
ft.commit();
}
这种方式的优点当然是可以提高性能了,但是它也有缺点,就是可能会出现 Fragment 重叠的现象。例如你在切换了几次 Fragment 后,旋转屏幕,这时 Activity 发生重建,你会发现重建后的 Activity 上几个 Fragment 重叠在了一起(hide 失效了)。
解决方法的话,网上有很多这方面的文章,这里就不多说了。