• 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 等方法。

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

  • 相关阅读:
    自定义Listview
    android ListView嵌套GridView显示不全问题
    Android-Universal-Image-Loader 图片异步加载类库的使用(超详细配置)
    android service被系统回收的解决方法
    android Activity基类通用方法
    用 FragmentManager 替换时使用 GoogleMaps 崩溃 app
    Gulp 从0开始
    面试题 之 全排列
    面试题之 query转为obj
    this .运算符 和 [] 运算符
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/8616337.html
Copyright © 2020-2023  润新知