你真的了解Fragment的生命周期吗?

在基于上一篇关于Activity的生命周期的深入了解之后,我想大家应该开始意识到一个问题就是,虽然有些类,接口,方法平时经常使用,但是只是了解一个大概,当在面试的时候考官一深入去体察你的知识深度,你就hold不住了。那么在这篇文章中,我们开始针对Fragment的生命周期进行一些知识挖掘,我依然会带大家通过阅读源码的方式了解Fragment。

Fragment的生命周期

在这一节中,我相信大家作为开发者都应该对Fragment的生命周期有一个简单的了解了,并且能够随口说出生命周期的方法执行顺序,那么在这一节我也就不过多赘述。通过代码执行的结果来验证:
(1)Fragment首次展示时:
07-17 08:41:51.441 9232-9232/com.kanzhun.lifecycle D/FragmentA: onAttach
07-17 08:41:51.441 9232-9232/com.kanzhun.lifecycle D/FragmentA: onCreate
07-17 08:41:51.451 9232-9232/com.kanzhun.lifecycle D/FragmentA: onCreateView
07-17 08:41:51.461 9232-9232/com.kanzhun.lifecycle D/FragmentA: onViewCreated
07-17 08:41:51.461 9232-9232/com.kanzhun.lifecycle D/FragmentA: onActivityCreated
07-17 08:41:51.461 9232-9232/com.kanzhun.lifecycle D/FragmentA: onStart
07-17 08:41:51.461 9232-9232/com.kanzhun.lifecycle D/FragmentA: onResume
(2)Fragment进入后台或者锁屏时:
07-17 08:44:28.871 9232-9232/com.kanzhun.lifecycle D/FragmentA: onPause
07-17 08:44:29.241 9232-9232/com.kanzhun.lifecycle D/FragmentA: onStop
(3)Fragment从后台返回前台或者点亮屏幕时:
07-17 08:45:42.711 9232-9232/com.kanzhun.lifecycle D/FragmentA: onStart
07-17 08:45:42.711 9232-9232/com.kanzhun.lifecycle D/FragmentA: onResume
(4)销毁Fragment的时候:
07-17 08:46:40.291 9232-9232/com.kanzhun.lifecycle D/FragmentA: onPause
07-17 08:46:40.631 9232-9232/com.kanzhun.lifecycle D/FragmentA: onStop
07-17 08:46:40.631 9232-9232/com.kanzhun.lifecycle D/FragmentA: onDestroyView
07-17 08:46:40.631 9232-9232/com.kanzhun.lifecycle D/FragmentA: onDestroy
07-17 08:46:40.631 9232-9232/com.kanzhun.lifecycle D/FragmentA: onDetach
由此来看,我们通过日志的打印又重新对于Fragment的生命周期进行了一次简单的回顾。

addToBackStack()方法对于生命周期的影响

我在这里准备了一段代码:
public class FragmentLifecycleActivity extends FragmentActivity implements View.OnClickListener {

    private FragmentManager fm;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fragment_lifecycle);

        findViewById(R.id.btn_fragmentA).setOnClickListener(this);
        findViewById(R.id.btn_fragmentB).setOnClickListener(this);

        fm = getSupportFragmentManager();


    }

    @Override
    public void onClick(View view) {
        FragmentTransaction ft = fm.beginTransaction();
        switch (view.getId()) {
            case R.id.btn_fragmentA:
                ft.replace(R.id.ll_container, FragmentA.getInstance(null));
                ft.addToBackStack(null);
                ft.commit();
                break;
            case R.id.btn_fragmentB:
                ft.replace(R.id.ll_container, FragmentB.getInstance(null));
                ft.addToBackStack(null);
                ft.commit();
                break;
            default:
                break;
        }
    }
}
在以上的代码中,我采取replace()的方式替换之前所存在的fragment,并且每次替换Fragment时都添加addToBackStack()方法,我们看看他对于生命周期有什么影响:
(1)首次启动FragmentA时,由于FragmentManager中没有存在FragmentA,所以FragmentA依然运行自己生命周期的方法:
07-17 09:03:38.441 26271-26271/com.kanzhun.lifecycle D/FragmentA: onAttach
07-17 09:03:38.441 26271-26271/com.kanzhun.lifecycle D/FragmentA: onCreate
07-17 09:03:38.441 26271-26271/com.kanzhun.lifecycle D/FragmentA: onCreateView
07-17 09:03:38.441 26271-26271/com.kanzhun.lifecycle D/FragmentA: onViewCreated
07-17 09:03:38.441 26271-26271/com.kanzhun.lifecycle D/FragmentA: onActivityCreated
07-17 09:03:38.441 26271-26271/com.kanzhun.lifecycle D/FragmentA: onStart
07-17 09:03:38.441 26271-26271/com.kanzhun.lifecycle D/FragmentA: onResume
(2)这时,点击fragmentB的按钮让FragmentB去替换FragmentA:
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentB: onAttach
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentB: onCreate
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentA: onPause
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentA: onStop
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentA: onDestroyView
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentB: onCreateView
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentB: onViewCreated
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentB: onActivityCreated
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentB: onStart
07-17 09:08:24.531 26271-26271/com.kanzhun.lifecycle D/FragmentB: onResume
在FragmentB启动之后,我们发现FragmentA虽然被替换并且运行了onDestroyView()方法,但是并没有运行onDestroy()和onDetach()方法。
(3)当我们这时按下返回键时:
07-17 09:14:12.221 26271-26271/com.kanzhun.lifecycle D/FragmentB: onPause
07-17 09:14:12.221 26271-26271/com.kanzhun.lifecycle D/FragmentB: onStop
07-17 09:14:12.221 26271-26271/com.kanzhun.lifecycle D/FragmentB: onDestroyView
07-17 09:14:12.221 26271-26271/com.kanzhun.lifecycle D/FragmentB: onDestroy
07-17 09:14:12.221 26271-26271/com.kanzhun.lifecycle D/FragmentB: onDetach
07-17 09:14:12.231 26271-26271/com.kanzhun.lifecycle D/FragmentA: onCreateView
07-17 09:14:12.231 26271-26271/com.kanzhun.lifecycle D/FragmentA: onViewCreated
07-17 09:14:12.231 26271-26271/com.kanzhun.lifecycle D/FragmentA: onActivityCreated
07-17 09:14:12.231 26271-26271/com.kanzhun.lifecycle D/FragmentA: onStart
07-17 09:14:12.231 26271-26271/com.kanzhun.lifecycle D/FragmentA: onResume
FragmentA被重新展现出来,我们发现此时FragmentB由于调用了onDestroy()和onDetach()方法已经完全被抛弃。FragmentA由于在FragmentManager的栈中依然存在,所以不需要调用onAttach()和onCreate()方法。

而对比没有添加addToBackStack()方法的结果,我们发现:
(1)栈中只会存在一个Fragment。
(2)FragmentB替换FragmentA的时候,FragmentA中的onDestroy()和onDetach()方法一定会被调用。

在源码中,我们找到了addToBackStack()的意义:
在每一次transaction执行commit()方法后,该次这对某fragment的transaction事件状态将会被记住。一旦这个fragment再次回到栈顶时,继续根据之前保留的transaction状态对fragment执行操作。
/**
     * Add this transaction to the back stack.  This means that the transaction
     * will be remembered after it is committed, and will reverse its operation
     * when later popped off the stack.
     *
     * @param name An optional name for this back stack state, or null.
     */
    public abstract FragmentTransaction addToBackStack(@Nullable String name);
 

hide()和show()对于生命周期的影响

接下来,我们改造一下代码,先把FragmentA和FragmentB通过add()的方式加入到FragmentManager中,之后再以show()和hide()的调用方式控制其显示还是隐藏。看看用这种方式对于Fragment的生命周期有什么影响。

首先,将Fragment的添加方式进行改造:
@Override
    public void onClick(View view) {
        FragmentTransaction ft = fm.beginTransaction();
        switch (view.getId()) {
            case R.id.btn_fragmentA:
                hideAllFragments(ft);
                if (fragmentA == null) {
                    fragmentA = FragmentA.getInstance(null);
                    ft.add(R.id.ll_container, fragmentA);
                    ft.addToBackStack(null);
                } else {
                    ft.show(fragmentA);
                }
                ft.commit();
                break;
            case R.id.btn_fragmentB:
                hideAllFragments(ft);
                if (fragmentB == null) {
                    fragmentB = FragmentB.getInstance(null);
                    ft.add(R.id.ll_container, fragmentB);
                    ft.addToBackStack(null);
                } else {
                    ft.show(fragmentB);
                }
                ft.commit();
                break;
            default:
                break;
        }
    }
如果Fragment已经被加入到FragmentManager了,我们需要在该fragment显示之前,先隐藏所有的Fragment。
private void hideAllFragments(FragmentTransaction ft) {
        List<Fragment> fragments = fm.getFragments();
        if (fragments == null || fragments.size() <= 0) return;
        for (Fragment f : fragments) {
            if (f == null) continue;
            ft.hide(f);
        }
    }

运行代码之后,我们可以看到如下结果:
(1)点击FragmentA将FragmentA添加到FragmentManager时,FragmentA会调用自己的生命周期如下方法。
07-17 18:47:58.179 16467-16467/com.kanzhun.lifecycle D/FragmentA: onAttach
07-17 18:47:58.189 16467-16467/com.kanzhun.lifecycle D/FragmentA: onCreate
07-17 18:47:58.189 16467-16467/com.kanzhun.lifecycle D/FragmentA: onCreateView
07-17 18:47:58.189 16467-16467/com.kanzhun.lifecycle D/FragmentA: onViewCreated
07-17 18:47:58.189 16467-16467/com.kanzhun.lifecycle D/FragmentA: onActivityCreated
07-17 18:47:58.189 16467-16467/com.kanzhun.lifecycle D/FragmentA: onStart
07-17 18:47:58.189 16467-16467/com.kanzhun.lifecycle D/FragmentA: onResume
(2)点击FragmentB再将FragmentB添加到FragmentManager时,FragmentB也会调用自己的生命周期如下方法。
07-17 18:49:37.169 16467-16467/com.kanzhun.lifecycle D/FragmentB: onAttach
07-17 18:49:37.169 16467-16467/com.kanzhun.lifecycle D/FragmentB: onCreate
07-17 18:49:37.169 16467-16467/com.kanzhun.lifecycle D/FragmentB: onCreateView
07-17 18:49:37.169 16467-16467/com.kanzhun.lifecycle D/FragmentB: onViewCreated
07-17 18:49:37.169 16467-16467/com.kanzhun.lifecycle D/FragmentB: onActivityCreated
07-17 18:49:37.169 16467-16467/com.kanzhun.lifecycle D/FragmentB: onStart
07-17 18:49:37.169 16467-16467/com.kanzhun.lifecycle D/FragmentB: onResume
(3)再次点击A、B之后,则不再有生命周期方法的调用。
(4)点击返回键:
1> 如果在add()调用前添加了addToBackStack()方法,那么会将两个fragment依次pop出栈。最后添加进FragmentManager的Fragment最先出栈。
2> 如果在add()时没有调用addToBackStack()方法,那么点击一次返回键,会将两个fragment全部移除出栈。
这两种方式的移除都会调用onDestroy()和onDetach()方法。

通过代码我们可以得出结论: 一旦Fragment被添加之后,hide()和show()方法的调用不会引起Fragment生命周期方法的调用。

小结:

通过以上的代码分析,我们可以看出了解Fragment的生命周期有助于我们去选择合适的方式去构建我们的工程。由于现在Fragment使用起来更加灵活,我们也可以通过Fragment去打造更简单的并且更好维护的工程体系,来帮助我们完成复杂的业务逻辑。









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值