当前位置: 首页 > news >正文

Fragment 生命周期怎么来的?

前言

Fragment对于 Android 开发人员来说一点都不陌生,由于差点儿不论什么一款 app 都大量使用 Fragment,所以 Fragment 的生命周期相信对于大家来说应该都非常清晰。但绝大部分人对于其生命周期都停留在表象,知道一个 Fragment 从创建到运行再到销毁所要经过的过程。但却不知道内部怎样实现。或许有人会这样说,给你一辆摩托车,你仅仅要会骑即可。不须要拆开来看它内部的组成结构;对于这种问题,我仅仅想说,编程不仅学开车,还要学会造车,而且通过了解实现原理。能够让我们更加清晰的理解 Fragment的生命周期。往往我们通过理解来掌握的东西,是不易忘记的。

Fragment 生命周期流程图

好了。来看以下流程图来回想一下 Fragment 的生命周期
这里写图片描写叙述

分析

要分析 Fragment 的生命周期,离不开这四个类

FragmentActivity.java
FragmentManager.java
Fragment.java
BackStackRecord.java

启动 app 首先启动的是FragmentActivity。我们就从它開始看起。在 onCreate()方法中

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //Fragment管理类绑定 Activity
        mFragments.attachActivity(this, mContainer, null);
        // Old versions of the platform didn't do this!
        if (getLayoutInflater().getFactory() == null) {
            getLayoutInflater().setFactory(this);
        }

        super.onCreate(savedInstanceState);

        NonConfigurationInstances nc = (NonConfigurationInstances)
                getLastNonConfigurationInstance();
        if (nc != null) {
            mAllLoaderManagers = nc.loaders;
        }
        if (savedInstanceState != null) {
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);

            mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
        }
        mFragments.dispatchCreate();
    }

这里的mFragments就是FragmentManager,onCreate 中主要做了两件事,一、把FragmentManager和 Activity绑定,二、 向 Fragment分发 OnCreate 方法mFragments.dispatchCreate();看到这里。不知道大家有没有疑问。这里就会运行 Fragment 的onAttach 和 onCreate 方法吗?答案显然是错误的。由于我们都知道我们在运行 add + commit的时候才会运行,那么这里的 attach 和 onCreate 做了什么事?进去看看

    public void attachActivity(FragmentActivity activity,
            FragmentContainer container, Fragment parent) {
        if (mActivity != null) throw new IllegalStateException("Already attached");
        mActivity = activity;
        mContainer = container;
        mParent = parent;
    }

以上代码,仅仅是对变量的赋值,所以不会触发 Fragment 中的方法。

    public void dispatchCreate() {
        mStateSaved = false;
        moveToState(Fragment.CREATED, false);
    }

貌似触发了 Fragment 中的 onCreate方法,继续看看。

    void moveToState(int newState, int transit, int transitStyle, boolean always) {
        //...省略部分代码
        mCurState = newState;
        if (mActive != null) {
            boolean loadersRunning = false;
            for (int i=0; i<mActive.size(); i++) {
                Fragment f = mActive.get(i);
                if (f != null) {
                    moveToState(f, newState, transit, transitStyle, false);
                    if (f.mLoaderManager != null) {
                        loadersRunning |= f.mLoaderManager.hasRunningLoaders();
                    }
                }
            }
         //...省略部分代码
    }

这里有个一推断if (mActive != null),由于我们眼下还没有地方初始化它,所以这里显然不成立,所以 dispatchCreate 方法也没有触发Fragment 中的不论什么方法,可是这里有一个须要注意

mCurState = newState;

也就是说当前状态变成了 Fragment.CREATED

FragmentActivity 中的其它方法如 onStart、onResume 都跟 onCreate 方法一样。都没有触发 Fragment 中的方法,
但mCurState 确发生了改变,变成了最后一个状态的值—> Fragment.RESUMED;

此时 Activity 已经启动了, FragmentManager中的mCurState也已经是Fragment.RESUMED,我们都知道,当我们通过FragmentManager.beginTransaction().add().commit()这时才是正在启动一个 Fragment。通过跟踪代码,commit终于调用的代码例如以下

    public void run() {
      //....省略非常多代码
        while (op != null) {
            switch (op.cmd) {
                case OP_ADD: {
                    //add 会走这里
                    Fragment f = op.fragment;
                    f.mNextAnim = enterAnim;
                    mManager.addFragment(f, false);
                } break;
                case OP_REPLACE: {
                   //...省略
                } break;
                case OP_REMOVE: {
                    //...省略
                } break;
                case OP_HIDE: {
                   //...省略
                } break;
                case OP_SHOW: {
                   //...省略
                } break;
                case OP_DETACH: {
                   //...省略
                } break;
                case OP_ATTACH: {
                   //...省略
                } break;
                default: {
                 //...省略
                }
            }

            op = op.next;
        }
        //最后会去改变状态,这里就是整个生命周期运行的关键代码
        mManager.moveToState(mManager.mCurState, transition, transitionStyle, true);

        if (mAddToBackStack) {
            mManager.addBackStackState(this);
        }
    }

上面代码非常长,省略了部分代码,仅显示关键代码,当我们在 add 和 commit 之后,Fragment 会运行mManager.addFragment(f, false);这种方法

        if (mAvailIndices == null || mAvailIndices.size() <= 0) {
            if (mActive == null) {
                mActive = new ArrayList<Fragment>();
            }
            f.setIndex(mActive.size(), mParent);
            mActive.add(f);

        } else {
            //...省略
        }

我们在前面就已经讲过了这个if (mActive == null) ,它是在这里初始化的,所以当我们再次运行

moveToState(int newState, int transit, int transitStyle, boolean always)

的时候,这里是能够通过的,在 commit 之后就有这样一段代码

//最后会去改变状态,这里就是整个生命周期运行的关键代码
mManager.moveToState(mManager.mCurState, transition, transitionStyle, true);

还记得mCurState的状态是什么吗?没错,就是我们前面分析的
mCurState = Fragment.RESUMED;
接下来就来看看 他是怎么moveToState

    void moveToState(Fragment f, int newState, int transit, int transitionStyle,
            boolean keepActive) {
    //...省略
        if (f.mState < newState) {
        //...省略
            }
            switch (f.mState) {
                case Fragment.INITIALIZING:
                //...省略
                    f.mCalled = false;
                    f.onAttach(mActivity);
                //...省略
                    if (f.mParentFragment == null) {
                        mActivity.onAttachFragment(f);
                    }

                    if (!f.mRetaining) {
                        f.performCreate(f.mSavedFragmentState);
                    }
                    f.mRetaining = false;
    //...省略
                    }
                case Fragment.CREATED:
                    if (newState > Fragment.CREATED) {
                        if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
                        if (!f.mFromLayout) {
                            ViewGroup container = null;
                            if (f.mContainerId != 0) {
                                container = (ViewGroup)mContainer.findViewById(f.mContainerId);
                                if (container == null && !f.mRestored) {
                                    throwException(new IllegalArgumentException(
                                            "No view found for id 0x"
                                            + Integer.toHexString(f.mContainerId) + " ("
                                            + f.getResources().getResourceName(f.mContainerId)
                                            + ") for fragment " + f));
                                }
                            }
                            f.mContainer = container;
                            f.mView = f.performCreateView(f.getLayoutInflater(
                                    f.mSavedFragmentState), container, f.mSavedFragmentState);
                            if (f.mView != null) {
                                f.mInnerView = f.mView;
                                f.mView = NoSaveStateFrameLayout.wrap(f.mView);
                                if (container != null) {
                                    Animation anim = loadAnimation(f, transit, true,
                                            transitionStyle);
                                    if (anim != null) {
                                        f.mView.startAnimation(anim);
                                    }
                                    container.addView(f.mView);
                                }
                                if (f.mHidden) f.mView.setVisibility(View.GONE);
                                f.onViewCreated(f.mView, f.mSavedFragmentState);
                            } else {
                                f.mInnerView = null;
                            }
                        }

                        f.performActivityCreated(f.mSavedFragmentState);
                        if (f.mView != null) {
                            f.restoreViewState(f.mSavedFragmentState);
                        }
                        f.mSavedFragmentState = null;
                    }
                case Fragment.ACTIVITY_CREATED:
                case Fragment.STOPPED:
                    if (newState > Fragment.STOPPED) {
                        if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
                        f.performStart();
                    }
                case Fragment.STARTED:
                    if (newState > Fragment.STARTED) {
                        if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
                        f.mResumed = true;
                        f.performResume();
                        f.mSavedFragmentState = null;
                        f.mSavedViewState = null;
                    }
            }
        } else if (f.mState > newState) {
            switch (f.mState) {
                case Fragment.RESUMED:
                    if (newState < Fragment.RESUMED) {
                        if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
                        f.performPause();
                        f.mResumed = false;
                    }
                case Fragment.STARTED:
                    if (newState < Fragment.STARTED) {
                        if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
                        f.performStop();
                    }
                case Fragment.STOPPED:
                    if (newState < Fragment.STOPPED) {
                        if (DEBUG) Log.v(TAG, "movefrom STOPPED: " + f);
                        f.performReallyStop();
                    }
                case Fragment.ACTIVITY_CREATED:
                    if (newState < Fragment.ACTIVITY_CREATED) {
                        if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
                        if (f.mView != null) {
                            // Need to save the current view state if not
                            // done already.
                            if (!mActivity.isFinishing() && f.mSavedViewState == null) {
                                saveFragmentViewState(f);
                            }
                        }
                        f.performDestroyView();
                        if (f.mView != null && f.mContainer != null) {
                            Animation anim = null;
                            if (mCurState > Fragment.INITIALIZING && !mDestroyed) {
                                anim = loadAnimation(f, transit, false,
                                        transitionStyle);
                            }
                            if (anim != null) {
                                final Fragment fragment = f;
                                f.mAnimatingAway = f.mView;
                                f.mStateAfterAnimating = newState;
                                anim.setAnimationListener(new AnimationListener() {
                                    @Override
                                    public void onAnimationEnd(Animation animation) {
                                        if (fragment.mAnimatingAway != null) {
                                            fragment.mAnimatingAway = null;
                                            moveToState(fragment, fragment.mStateAfterAnimating,
                                                    0, 0, false);
                                        }
                                    }
                                    @Override
                                    public void onAnimationRepeat(Animation animation) {
                                    }
                                    @Override
                                    public void onAnimationStart(Animation animation) {
                                    }
                                });
                                f.mView.startAnimation(anim);
                            }
                            f.mContainer.removeView(f.mView);
                        }
                        f.mContainer = null;
                        f.mView = null;
                        f.mInnerView = null;
                    }
                case Fragment.CREATED:
                    if (newState < Fragment.CREATED) {
                        if (mDestroyed) {
                            if (f.mAnimatingAway != null) {
                                // The fragment's containing activity is
                                // being destroyed, but this fragment is
                                // currently animating away.  Stop the
                                // animation right now -- it is not needed,
                                // and we can't wait any more on destroying
                                // the fragment.
                                View v = f.mAnimatingAway;
                                f.mAnimatingAway = null;
                                v.clearAnimation();
                            }
                        }
                        if (f.mAnimatingAway != null) {
                            // We are waiting for the fragment's view to finish
                            // animating away.  Just make a note of the state
                            // the fragment now should move to once the animation
                            // is done.
                            f.mStateAfterAnimating = newState;
                            newState = Fragment.CREATED;
                        } else {
                            if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
                            if (!f.mRetaining) {
                                f.performDestroy();
                            }

                            f.mCalled = false;
                            f.onDetach();
                            if (!f.mCalled) {
                                throw new SuperNotCalledException("Fragment " + f
                                        + " did not call through to super.onDetach()");
                            }
                            if (!keepActive) {
                                if (!f.mRetaining) {
                                    makeInactive(f);
                                } else {
                                    f.mActivity = null;
                                    f.mParentFragment = null;
                                    f.mFragmentManager = null;
                                    f.mChildFragmentManager = null;
                                }
                            }
                        }
                    }
            }
        }

        f.mState = newState;
    }

代码非常多,也比較乱,这里我来简单分析一下,首先的知道这几种状态值的大小

    static final int INITIALIZING = 0;     // Not yet created.
    static final int CREATED = 1;          // Created.
    static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
    static final int STOPPED = 3;          // Fully created, not started.
    static final int STARTED = 4;          // Created and started, not resumed.
    static final int RESUMED = 5;          // Created started and resumed.

如今是f.mState = Fragment.INITIALIZING。newState = RESUMED;
所以if (f.mState < newState)成立。特别注意在上面的代码中每个 case 语句后面都没有 break 关键字。
所以简化以后的代码是:

switch (f.mState) {
   case Fragment.INITIALIZING:
       f.onAttach(mActivity);
        if (f.mParentFragment == null) {
             mActivity.onAttachFragment(f);
        }
        f (!f.mRetaining) {   
            f.performCreate(f.mSavedFragmentState);                      
        }

   case Fragment.CREATED:
       f.performCreateView(...)   
       f.onViewCreated(...)  
       f.performActivityCreated(...);     
       f.restoreViewState(...)
   case Fragment.ACTIVITY_CREATED:
   case Fragment.STOPPED:
       f.performStart();
   case Fragment.STARTED:
       f.performResume();

以上就是 Fragment 启动的全过程。看完启动。再来看看 Fragment 销毁的过程运行 remove().commit()之后会运行例如以下代码

 case OP_REMOVE: {
    Fragment f = op.fragment;
    f.mNextAnim = exitAnim;
    mManager.removeFragment(f, transition, transitionStyle);
} break;
    public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
        if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
        final boolean inactive = !fragment.isInBackStack();
        if (!fragment.mDetached || inactive) {
            if (mAdded != null) {
                mAdded.remove(fragment);
            }
            if (fragment.mHasMenu && fragment.mMenuVisible) {
                mNeedMenuInvalidate = true;
            }
            fragment.mAdded = false;
            fragment.mRemoving = true;
            moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
                    transition, transitionStyle, false);
        }
    }

能够看到最后一句。就是改变状态的调用,而且把newState 变为
Fragment.INITIALIZING或者Fragment.CREATED。如果当前 Fragment 在前台台运行。则为Fragment.INITIALIZING,我们如果当前值为Fragment.INITIALIZING。也就是当前运行的 Fragment 为我们所要移除的 Fragment。
由于if (f.mState < newState)不成立了,所以将会运行以下代码

else if (f.mState > newState) {
    switch (f.mState) {
    case Fragment.RESUMED:
    f.performPause();
    case Fragment.STARTED:
    f.performStop();
    case Fragment.STOPPED:
    f.performReallyStop();
    case Fragment.ACTIVITY_CREATED:
    saveFragmentViewState(f);
    f.performDestroyView();
    case Fragment.CREATED:
    f.performDestroy();
    f.onDetach();

千万不要被Fragment.CREATED这种命名给疑惑了,。尽管这里写的是Fragment.CREATED,但它运行的确实performDestroy()

总结:

细致分析就会发现整个生命周期事实上非常easy。简单来讲,就是 addView 和 removeView 的过程,仅仅是在当中增加了其它相似 Activity 的 onStart 等方法。

最后大家能够结合源代码再看一遍!

相关文章:

  • Redis和Memcache和MongoDB简介及区别分析(整理)
  • ubuntu16.4安装最新版wine3.0
  • c++中局部变量初始化的问题
  • WordCount
  • 外卖也智能!美团骑手智能助手的技术与实践
  • 【协议转换和消息路由】camel-spring-boot-starter 实践
  • 坑货!阿里奇门中心
  • [ssh]如何设计ARM板上多用户key登录系统
  • 71. Simplify Path
  • numpy 数组运算
  • Java 选择排序selection sort
  • 磁盘管理
  • 利用SCVMM 2012 R2来管理Azure虚拟机
  • AlphaGo告诉我们人工智能成功的五大秘诀,AI下一个风口在哪里?
  • 互联网面临新挑战,区块链经济将兴起
  • Angular2开发踩坑系列-生产环境编译
  • angular组件开发
  • CEF与代理
  • Docker入门(二) - Dockerfile
  • express + mock 让前后台并行开发
  • Fastjson的基本使用方法大全
  • Linux Process Manage
  • Sublime text 3 3103 注册码
  • tab.js分享及浏览器兼容性问题汇总
  • ucore操作系统实验笔记 - 重新理解中断
  • 动手做个聊天室,前端工程师百无聊赖的人生
  • 翻译--Thinking in React
  • 坑!为什么View.startAnimation不起作用?
  • 腾讯视频格式如何转换成mp4 将下载的qlv文件转换成mp4的方法
  • 小程序测试方案初探
  • 如何在招聘中考核.NET架构师
  • #ubuntu# #git# repository git config --global --add safe.directory
  • $var=htmlencode(“‘);alert(‘2“); 的个人理解
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (ros//EnvironmentVariables)ros环境变量
  • (二)斐波那契Fabonacci函数
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (九)One-Wire总线-DS18B20
  • (论文阅读31/100)Stacked hourglass networks for human pose estimation
  • (三分钟)速览传统边缘检测算子
  • (四)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
  • (转)es进行聚合操作时提示Fielddata is disabled on text fields by default
  • (转)甲方乙方——赵民谈找工作
  • **CI中自动类加载的用法总结
  • .chm格式文件如何阅读
  • .halo勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET Conf 2023 回顾 – 庆祝社区、创新和 .NET 8 的发布
  • .Net core 6.0 升8.0
  • .net core IResultFilter 的 OnResultExecuted和OnResultExecuting的区别
  • .net core webapi Startup 注入ConfigurePrimaryHttpMessageHandler
  • .Net 访问电子邮箱-LumiSoft.Net,好用
  • .NET 应用架构指导 V2 学习笔记(一) 软件架构的关键原则
  • .net中我喜欢的两种验证码
  • [ Linux ] Linux信号概述 信号的产生
  • [ vulhub漏洞复现篇 ] AppWeb认证绕过漏洞(CVE-2018-8715)