再谈Fragment

参考:java

声明

Fragment 就是一个 Activity 布局的一部分,能够把 Activity 的一部分布局抽离出来到 Fragment 中,而且 Fragment 也能够执行逻辑。就是把 Activity 复杂的内容抽离成几个碎片,而后拼凑起来,在 Activity 布局中,只须要引入各个不一样的 Fragment 就能够 了。android

好比咱们常见的布局,底部导航,而后每一个模块对应不一样的 Fragment。其实也是彻底能够不使用 Fragment 的,一个页面中包含各个模块的布局,而后经过点击导航来决定隐藏哪些模块。这样写的话一个 Activity 中的代码逻辑会很是多,全部模块都融合到一个 Activity 中了,至关冗余,耦合。若是用 Fragment 就灵活多了,Activity 只须要根据导航显示对应的 Fragment 就能够了。markdown

若是别的地方须要某一个模块,直接拿出对应的 Fragment 就能够了。若是都写在 Activity 中那抽离出来就费劲了,也增长了不肯定性。ide

再好比一个例子:网易新闻 手机端 和平板端。oop

平板端是新闻的标题和详情都在一个页面中。手机是详情在单独的一个页面。这样咱们就能够将 标题 和 详情写成两个 Fragment。充分利用了。布局

Fragment 相关的三个类

  • Fragmentspa

    具体的 Fragment.net

  • FragmentManagercode

    是管理 Fragment 的orm

  • FragmentTransaction

    经过事务来进行添加 Fragment、隐藏、移除 等操做 Fragment 动做,事务保证了原子性

主要方法

  • transaction.add()

    向 Activity 中添加 Fragment,只是添加 Fragment,不影响以前 Fragment 的声明周期,这一点和 Activity 不同,Activity 会由于新 Activity 而走生命周期。而 .add 不会。假如 FragmentA 已经在 Activity 中了,这个时候启动了 FragmentB,A 的生命周期是不会有任何变化的,仍是处于 onResume ,并不会由于 B 处于 onResume 而有影响。

  • transaction.remove()

    从 Activity 中移除一个 Fragment 。若是这个 Fragment 没有被添加到回退栈中,则实例被销毁。若是添加到回退栈了,会执行 onDestroyView 实例并不会被销毁。

  • transaction.replace()

    使用 Fragment 替换当前,至关于先移除以前的 Fragment(remove()) 而后再 add()

  • transaction.hide()

    隐藏当前 Fragment。仅仅是设为不可见。不会销毁

  • transaction.show()

    显示以前隐藏的 Fragment

  • detach()

    会将 view 从 UI 中移除。和 remove 不一样的是,此时 Fragment的状态依然由 FragmentManager 维护

  • attach()

    重建 view 视图,附加到UI上显示

  • .addToBackStack()

    是将事务放入回退栈,能够认为一个事务中能够有多个 Fragment .addToBackStack() 作的是将这个事务放入回退栈。

    相似于咱们每添加一个 Activity 都会默认放入回退栈中,若是想要 Fragment 放入回退栈中,那么就须要借助启动 Fragment 的事务了,调用事务的 .addToBackStack() 方法。

    默认状况下,按下返回键的时候的操做是从回退栈中弹出一个事务。

    按下返回键的时候,是从返回栈中弹出一个事务(Fragment)。显示栈顶的事务(对应的 Fragment)

    若是当前栈顶的Fragment 已经执行过 destroyView 了,则会从新执行生命周期(从 createView 开始)

    若是任务栈中只有一个Fragment,则此时按下返回键,进行的操做是把这个 Fragment 销毁。

    在 Fragment A 中启动另外一个 Fragment B 这个时候 .addToBackStack() 是将 A 加入栈中。

基本使用

静态添加

// 直接在 xml 中添加
    <fragment android:id="@+id/fragment" android:layout_width="match_parent" android:layout_height="200dp" android:name="com.syd.good.feature.fragment.fragment.FragmentMy" />
复制代码

在代码中获取的这个 Fragment

经过

Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment);
复制代码

注意静态添加 Fragment 的生命周期

E/FragmentMy: onAttach
E/FragmentMy: onCreate
E/FragmentMy: onCreateView
E/FragmentMy: onViewCreated
E/FragmentStaticActivity: onCreate()
E/FragmentMy: onActivityCreated
E/FragmentMy: onStart
E/FragmentStaticActivity: onStart()
E/FragmentStaticActivity: onResume()
E/FragmentMy: onResume
// 中止
E/FragmentMy: onPause
E/FragmentStaticActivity: onPause()
E/FragmentMy: onStop
E/FragmentStaticActivity: onStop()
E/FragmentMy: onDestroyView
E/FragmentMy: onDestroy
E/FragmentMy: onDetach()
E/FragmentStaticActivity: onDestroy()
复制代码

动态添加

动态添加,通常都会选择加载到 FrameLayout 布局上,是由于 FrameLayout 布局足够简单,能够减小没必要要的布局加载。

Fragment 的布局只是附着在 FrameLayout 上,做为 FrameLayout 的 子 View ,并无取代 FrameLayout

<FrameLayout android:id="@+id/fl" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" />
复制代码
getSupportFragmentManager().beginTransaction()
                .add(R.id.fl, new FragmentOne())
   				.add(R.id.fl, new FragmentTwo())
                .commit();
复制代码

Fragment 不管是不是全屏仍是一半的,执行生命周期都同样

执行结果:

E/FragmentOne: onAttach
E/FragmentOne: onCreate
E/FragmentTwo: onAttach()
E/FragmentTwo: onCreate()
E/FragmentOne: onCreateView
E/FragmentOne: onViewCreated
E/FragmentOne: onActivityCreated
E/FragmentOne: onStart
E/FragmentOne: onResume
E/FragmentTwo: onCreateView
E/FragmentTwo: onActivityCreated
E/FragmentTwo: onStart
E/FragmentTwo: onResume
复制代码

返回

E/FragmentOne: onPause
E/FragmentTwo: onPause
E/FragmentOne: onStop
E/FragmentTwo: onStop
E/FragmentOne: onDestroyView
E/FragmentOne: onDestroy
E/FragmentOne: onDetach()
E/FragmentTwo: onDestroyView
E/FragmentTwo: onDestroy
E/FragmentTwo: onDetach()
复制代码

onHiddenChanged() 和普通的生命周期没有关系,只是调用 hidden 的时候会调用而已。

经过上面 .add 的方式添加 Fragment 只是将 Fragment 添加到指定的布局中,以后再添加 Fragment 是互相不影响的,在布局上看 FrameLayout 有两个子View(FragmentOne、FragmentTwo) 相互重叠。

关于.addToBackStack() 例子

例子1

主 Activity 中一次启动两个 Fragment ,并将这个事务加入到回退栈中。

getSupportFragmentManager().beginTransaction()
        .add(R.id.fl, new FragmentOne())
        .add(R.id.fl, new FragmentTwo())
        .addToBackStack(null)
        .commit();
复制代码

这个时候按下返回键的结果是,从回退栈中弹出这个事务,意味这销毁这两个 Fragment

执行结果

Fragment 从 Activity 中脱离,留下 Activity

E/FragmentOne: onAttach
E/FragmentOne: onCreate
E/FragmentTwo: onAttach()
E/FragmentTwo: onCreate()
E/FragmentOne: onCreateView
E/FragmentOne: onViewCreated
E/FragmentOne: onActivityCreated
E/FragmentOne: onStart
E/FragmentOne: onResume
E/FragmentTwo: onCreateView
E/FragmentTwo: onActivityCreated
E/FragmentTwo: onStart
E/FragmentTwo: onResume
// 按下返回键
E/FragmentTwo: onPause
E/FragmentTwo: onStop
E/FragmentTwo: onDestroyView
E/FragmentTwo: onDestroy
E/FragmentTwo: onDetach()
E/FragmentOne: onPause
E/FragmentOne: onStop
E/FragmentOne: onDestroyView
E/FragmentOne: onDestroy
E/FragmentOne: onDetach()    
复制代码

假如没有 addToBackStack() 的时候,按下返回键,则直接退出 Activity 了。

例子2

在上面的基础上,在启动的 FragmentTwo 中添加方法

tvAdd.setOnClickListener((view1) -> {
            Log.e("add", "add");
            getFragmentManager().beginTransaction()
                    .add(R.id.fl, new FragmentThree())
                    .commit();
        });
复制代码

这个时候只是在 fl 中又添加了一个 FragmentThree ,而且这个事务没有加入到回退栈中,这个时候按下返回键,结果是:

页面没有发生任何改变,可是上一次保存在回退栈的事务被弹出了

E/FragmentTwo: onPause
 E/FragmentTwo: onStop
 E/FragmentTwo: onDestroyView
 E/FragmentTwo: onDestroy
 E/FragmentTwo: onDetach()
 E/FragmentOne: onPause
 E/FragmentOne: onStop
 E/FragmentOne: onDestroyView
 E/FragmentOne: onDestroy
 E/FragmentOne: onDetach()
复制代码

这个时候再按下返回键

Activity 就会被销毁。

例子3

在例子1的基础上,在添加 FragmentTwo 中添加方法

tvAdd.setOnClickListener((view1) -> {
    Log.e("add", "add");
    getFragmentManager().beginTransaction()
            .add(R.id.fl, new FragmentThree())
        // 添加了将此事务入栈
            .addToBackStack(null)
            .commit();
});
复制代码

这个时候再按下返回键,是将这个栈顶的事务退出,这个时候例子1 中的事务就处于栈顶了。页面显示的就是例子1中的页面了。

再次按下返回键,是把例子1中的事务弹出,这个时候留下的就只有 Activity 了,再次按下返回键,弹出 Activity。

与 Activity 通讯

  • Activity 中有 Fragment 的引用,能够直接操做 Fragment 中的方法
  • 每一个 Fragment 都有一个惟一的 TAG或者 ID 能够经过 getFragmentManager.findFragmentByTag() 或者 findFragmentById() 获取
  • Fragment 中经过 getActivity 获取当前绑定的 Activity 实例

Fragment 不该该直接操做其余的 Fragment。应该由管理者 Activity 来进行。

采用接口回调的形式

总结

凡是加入了回退栈 .addToBackStack(null) 以前加入的 Fragment 都不会被销毁。

好比:

Activity A 中

getSupportFragmentManager().beginTransaction()
        .add(R.id.fl, new FragmentOne())
        .add(R.id.fl, new FragmentTwo())
        .commit();
复制代码

FragmentTwo 中

getSupportFragmentManager().beginTransaction()
        .replace(R.id.fl, new FragmentThree())
    	.addToBackStack(null)
        .commit();
复制代码

请注意 Activity A 中是没有 addToBackStack 的 ,即便这样在 FragmentTweoreplaceFragmentOneFragmentTwo 也不会被销毁,而是走 onDestroyView() 方法。按下返回键后,恢复 FragmentOneFragmentTwoonCreateView 开始

若是没有 .addToBackStack(null) 的话,那么 FragmentOneFragmentTwo 就会被销毁了。而且按下返回键的时候,就销毁掉 Activity 了。

页面1 addTo

页面2 没有

E/FragmentThree: onAttach() E/FragmentThree: onCreate() E/FragmentTwo: onPause E/FragmentTwo: onStop E/FragmentTwo: onDestroyView E/FragmentOne: onPause E/FragmentOne: onStop E/FragmentOne: onDestroyView E/FragmentThree: onCreateView E/FragmentThree: onActivityCreated E/FragmentThree: onStart E/FragmentThree: onResume E/FragmentTwo: onDestroy E/FragmentTwo: onDetach() E/FragmentOne: onDestroy E/FragmentOne: onDetach()

相关文章
相关标签/搜索