1. 程式人生 > >Fragment 生命週期怎麼來的?

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()

總結:

仔細分析就會發現整個生命週期其實很簡單,簡單來講,就是 addView 和 removeView 的過程,只是在其中加入了其他類似 Activity 的 onStart 等方法。最後大家可以結合原始碼再看一遍!