FragmentTransaction 的 replace, add, hide, show 的使用和区别

引入

现在 APP 的主页面大多采用“单 Activity + 多 Fragment”的形式。多 Fragment 的使用需要解决两个问题:

  1. Fragment 怎么依附在 Activity 上
  2. 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();

注意:

  1. 确保一次业务中,所有的事务通过同一个 FragmentTransaction 对象进行 commit。
  2. 如果一次业务中 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 移除,而是继续往容器里添加 Fragment1. 如果同一个对象多次添加会报错
2. 由于 add 操作不会将之前的 Fragment 删除,所以会造成多个 Fragment 重叠的现象,要解决这个问题可以使用 hide 隐藏之前的 Fragment
hide隐藏容器中的 Fragment
show将隐藏的 Fragment 显示出来hide 和 show 是配对的,当要显示隐藏的 Fragment A 时,就 show(A);而对于其他 Fragment,则先 hide 起来,等之后要显示时再 show

实现切换 Fragment

通过上面介绍的几个方法可以实现 Fragment 的切换。有两种实现方式:

  1. 使用 replace
  2. add, hide, show 配合使用

第一种方式比较简单,想要显示哪个 Fragment 就 replace 它就行了。例如我要显示 FragmentA,那么我就这样写:

    ft.replace(R.id.container, FragmentA);

其中 ft 是上面创建的 FragmentTransaction,R.id.container 是容器(FrameLayout) 的 id。

这种方式的优点是使用简单,但缺点是导致每次切换 Fragment 都会重新执行该 Fragment 的生命周期,影响性能。

由于会影响性能,所以不推荐第一种方式

重点看第二种方式,第二种方式需要 add, hide, show 配合使用,它的步骤如下:

  1. 如果要切换的 Fragment 还未创建,就先创建 Fragment 对象,并通过 add 方法添加到容器中
  2. 通过 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 失效了)。

解决方法的话,网上有很多这方面的文章,这里就不多说了。

参考

点赞