Fragment源碼分析

概述

Fragment表示 Activity 中的行爲或用戶界面部分。您能夠將多個 Fragment 組合在一個 Activity 中來構建多窗格 UI,以及在多個 Activity 中重複使用某個 Fragment。您能夠將 Fragment 視爲 Activity 的模塊化組成部分,它具備本身的生命週期,能接收本身的輸入事件,而且您能夠在 Activity 運行時添加或移除 Fragment。 Fragment 必須始終嵌入在 Activity 中,其生命週期直接受宿主 Activity 生命週期的影響。 例如,當 Activity 暫停時,其中的全部 Fragment 也會暫停;當 Activity 被銷燬時,全部 Fragment 也會被銷燬。 不過,當 Activity 正在運行(處於已恢復生命週期狀態)時,您能夠獨立操縱每一個 Fragment,如添加或移除它們。 當您執行此類 Fragment 事務時,您也能夠將其添加到由 Activity 管理的返回棧 — Activity 中的每一個返回棧條目都是一條已發生 Fragment 事務的記錄。 返回棧讓用戶能夠經過按返回按鈕撤消 Fragment 事務(後退)。java

當您將 Fragment 做爲 Activity 佈局的一部分添加時,它存在於 Activity 視圖層次結構的某個 ViewGroup 內部,而且 Fragment 會定義其本身的視圖佈局。您能夠經過在 Activity 的佈局文件中聲明Fragment,將其做爲 <fragment> 元素插入您的 Activity 佈局中,或者經過將其添加到某個現有 ViewGroup,利用應用代碼進行插入。不過,Fragment 並不是必須成爲 Activity 佈局的一部分;您還能夠將沒有本身 UI 的 Fragment 用做 Activity 的不可見工做線程。ide

本文將經過分析源碼,對 Fragment 的建立、銷燬以及生命週期作一個更深刻的認識。模塊化

建議讀者在看這篇文章的時候,先看下Fragment事務管理源碼分析,對Fragment管理類先有一個比較清楚的認識。源碼分析

分析入口

/** * 構造並顯示Fragment * * @param containerViewId 容器控件id * @param clz Fragment類 */
    protected void showFragment(@IdRes int containerViewId, Class<? extends Fragment> clz) {
        FragmentManager fm = getFragmentManager();
        FragmentTransaction ft = fm.beginTransaction();//開始事務管理
        try {
            Fragment f = clz.newInstance();
            ft.add(containerViewId, f, clz.getName());//添加操做
            ft.commit();//提交事務
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
複製代碼

上面的代碼就是動態地往containerViewId裏添加一個Fragment並讓它顯示出來,能夠看到,這個涉及到Fragment的事務管理,詳細能夠參考Fragment事務管理源碼分析,這裏就再也不闡述了。佈局

代碼分析

BackStackRecord#run

調用了commit以後,真正執行的地方是在BackStackRecord的run方法:動畫

public void run() {
    
        ......
        
        if (mManager.mCurState >= Fragment.CREATED) {
            SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
            SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
            calculateFragments(firstOutFragments, lastInFragments);
            beginTransition(firstOutFragments, lastInFragments, false);
        }
        //遍歷鏈表,根據cmd事務類型依次處理事務
        Op op = mHead;
        while (op != null) {
            switch (op.cmd) {
                case OP_ADD: {
                    //添加一個新的Fragment
                    Fragment f = op.fragment;
                    f.mNextAnim = op.enterAnim;
                    mManager.addFragment(f, false);
                }
                break;
                case OP_REPLACE: {
                    Fragment f = op.fragment;
                    int containerId = f.mContainerId;
                    if (mManager.mAdded != null) {
                        for (int i = mManager.mAdded.size() - 1; i >= 0; i--) {
                            Fragment old = mManager.mAdded.get(i);
                            if (old.mContainerId == containerId) {
                                if (old == f) {
                                    op.fragment = f = null;
                                } else {
                                    if (op.removed == null) {
                                        op.removed = new ArrayList<Fragment>();
                                    }
                                    op.removed.add(old);
                                    old.mNextAnim = op.exitAnim;
                                    if (mAddToBackStack) {
                                        old.mBackStackNesting += 1;
                                    }
                                    mManager.removeFragment(old, mTransition, mTransitionStyle);
                                }
                            }
                        }
                    }
                    if (f != null) {
                        f.mNextAnim = op.enterAnim;
                        mManager.addFragment(f, false);
                    }
                }
                break;
                case OP_REMOVE: {
                    Fragment f = op.fragment;
                    f.mNextAnim = op.exitAnim;
                    mManager.removeFragment(f, mTransition, mTransitionStyle);
                }
                break;
                case OP_HIDE: {
                    Fragment f = op.fragment;
                    f.mNextAnim = op.exitAnim;
                    mManager.hideFragment(f, mTransition, mTransitionStyle);
                }
                break;
                case OP_SHOW: {
                    Fragment f = op.fragment;
                    f.mNextAnim = op.enterAnim;
                    mManager.showFragment(f, mTransition, mTransitionStyle);
                }
                break;
                case OP_DETACH: {
                    Fragment f = op.fragment;
                    f.mNextAnim = op.exitAnim;
                    mManager.detachFragment(f, mTransition, mTransitionStyle);
                }
                break;
                case OP_ATTACH: {
                    Fragment f = op.fragment;
                    f.mNextAnim = op.enterAnim;
                    mManager.attachFragment(f, mTransition, mTransitionStyle);
                }
                break;
                default: {
                    throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
                }
            }

            op = op.next;
        }

        mManager.moveToState(mManager.mCurState, mTransition,
                mTransitionStyle, true);

        if (mAddToBackStack) {
            mManager.addBackStackState(this);
        }
    }
複製代碼

由於咱們調用的是add操做,因此執行的代碼片斷是:this

case OP_ADD: {
        Fragment f = op.fragment;
        f.mNextAnim = op.enterAnim;
        mManager.addFragment(f, false);
    }
    break;
複製代碼

參數解釋:spa

  • op.fragment:showFragment中建立的Fragment實例,而且如今Fragment的mTag、mFragmentId、mContainerId已被初始化過了
  • op.enterAnim:入場動畫,能夠先無論
  • mManager:FragmentManagerImpl實例

FragmentManagerImpl#addFragment

public void addFragment(Fragment fragment, boolean moveToStateNow) {
        //已添加的Fragment列表
        if (mAdded == null) {
            mAdded = new ArrayList<Fragment>();
        }

        //設置Fragment的mIndex,並把Fragment添加到mActive列表
        makeActive(fragment);
        
        //判斷是否被detach。默認爲false
        if (!fragment.mDetached) {
            if (mAdded.contains(fragment)) {
                throw new IllegalStateException("Fragment already added: " + fragment);
            }
            //把Fragment添加到mAdded列表
            mAdded.add(fragment);
            //設置Fragment標記位
            fragment.mAdded = true;
            fragment.mRemoving = false;
            //判斷是否須要刷新菜單
            if (fragment.mHasMenu && fragment.mMenuVisible) {
                mNeedMenuInvalidate = true;
            }
            //在此次分析中moveToStateNow爲false,moveToState方法在本方法外層方法中調用
            if (moveToStateNow) {
                moveToState(fragment);
            }
        }
    }
複製代碼

addFragment裏面把Fragment加入mActive和mAdded列表,而且設置標記爲fragment.mAdded爲true,fragment.mRemoving爲false。 執行完ADD操做後,執行moveToState,moveToState顧名思義,就是把Fragment變爲某種狀態.net

//mManager.mCurState的狀態很重要,咱們下面會分析它如今處於什麼狀態
    mManager.moveToState(mManager.mCurState, mTransition,
            mTransitionStyle, true);

    //添加本次操做到回退棧中
    if (mAddToBackStack) {
        mManager.addBackStackState(this);
    }
複製代碼

Fragment狀態

咱們知道Fragment的生命週期是依賴於Activity的,好比Activity處於onResume,那麼Fragment也會處於onResume狀態,這裏的參數mManager.mCurState對應的狀態有:線程

static final int INVALID_STATE = -1;   // Invalid state used as a null value.
    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.
複製代碼

mCurState的初始狀態是Fragment.INITIALIZING,那麼在BackStackRecord中調用moveToState的時候,mCurState是什麼值呢?它是會受Activity生命週期影響而變化的,咱們來看下FragmentActivity的代碼

@SuppressWarnings("deprecation")
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        //綁定FragmentManager
        mFragments.attachHost(null /*parent*/);
        
        super.onCreate(savedInstanceState);
        ... ...
        
        //分發Fragment的create事件
        mFragments.dispatchCreate();
    }
複製代碼
public void dispatchCreate() {
        mHost.mFragmentManager.dispatchCreate();
    }
    
    public void dispatchCreate() {
        mStateSaved = false;
        //注意這裏設置了新的state
        moveToState(Fragment.CREATED, false);
    }
    
    void moveToState(int newState, boolean always) {
        moveToState(newState, 0, 0, always);
    }
    
    void moveToState(int newState, int transit, int transitStyle, boolean always) {
        
        ... ...
        //給mCurState賦值
        mCurState = newState;
        ... ...
    }
複製代碼

在onCreate中把mCurState變爲Fragment.CREATED狀態了,Activity的其餘生命週期方法回調的時候,也會改變這個狀態,大體整理以下:

  • onCreate:Fragment.CREATED
  • onStart:Fragment.ACTIVITY_CREATED-->Fragment.STARTED (Fragment.ACTIVITY_CREATED只會在Activity建立以後觸發一次,Fragment.STARTED每次onStart的時候都會觸發)
  • onResume:Fragment.RESUMED
  • onPause:Fragment.STARTED
  • onStop:Fragment.STOPPED
  • onDestroy:Fragment.INITIALIZING

下面是一張狀態遷移圖:

2019-9-2-11-22-55.png

因此隨着Activity生命週期的推動,Activity內全部Fragment的生命週期也會跟着推動。從Activity建立到顯示出來,最後會處於onResume狀態,那麼咱們此次就直接分析當前Activity處於onResume調用以後的情形好了。因此假定如今mCurState爲Fragment.RESUMED

讓咱們繼續跟蹤FragmentManagerImpl

FragmentManagerImpl#moveToState

void moveToState(int newState, int transit, int transitStyle, boolean always) {
        if (mHost == null && newState != Fragment.INITIALIZING) {
            throw new IllegalStateException("No activity");
        }

        if (!always && mCurState == newState) {
            return;
        }

        mCurState = newState;
        if (mActive != null) {
            boolean loadersRunning = false;
            //遍歷全部Active狀態的Fragment,改變全部Fragment的狀態
            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 (!loadersRunning) {
                startPendingDeferredFragments();
            }

            //讓Activity刷新Menu
            if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
                mHost.onInvalidateOptionsMenu();
                mNeedMenuInvalidate = false;
            }
        }
    }
複製代碼

設置最新的mCurState狀態,經過上面的分析,咱們知道newState等於Fragment.RESUMED。遍歷mActive列表中保存的Fragment,改變Fragment狀態,這裏又調用了一個moveToState方法,這個方法就是真正回調Fragment生命週期的地方

void moveToState(Fragment f, int newState, int transit, int transitionStyle, boolean keepActive) {

        // Fragments被detach或Fragment沒有添加到mAdded列表的話,設置目標Fragment的新狀態爲CREATED狀態,這次分析中不會進入這個分支
        if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
            newState = Fragment.CREATED;
        }
        //這次分析中f.mRemoving爲false
        if (f.mRemoving && newState > f.mState) {
            // While removing a fragment, we can't change it to a higher state.
            newState = f.mState;
        }
        // 是否延時啓動
        if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
            newState = Fragment.STOPPED;
        }
        
        if (f.mState < newState) {
            //這次命中的分支
            ......
            
            //根據Fragment當前的狀態,選擇case的分支。須要注意的是,這裏的switch case是沒有break語句的。這種設計可讓Fragment把自身的狀態依次推動到目標狀態
            switch (f.mState) {
                case Fragment.INITIALIZING:
                    if (f.mSavedFragmentState != null) {
                        ......
                    }
                    f.mHost = mHost;
                    //mParent是在FragmentActivity的onCreate方法中調用attachHost傳進來的,傳進來的是空值
                    f.mParentFragment = mParent;
                    f.mFragmentManager = mParent != null
                            ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
                    f.mCalled = false;
                    //【Fragment生命週期】onAttach回調,裏面會把mCalled設置爲true
                    f.onAttach(mHost.getContext());
                    if (!f.mCalled) {
                        throw new SuperNotCalledException("Fragment " + f
                                + " did not call through to super.onAttach()");
                    }
                    
                    if (f.mParentFragment == null) {
                        //讓Activity能夠監聽到Fragment的attach
                        mHost.onAttachFragment(f);
                    } else {
                        f.mParentFragment.onAttachFragment(f);
                    }

                    //f.mRetaining默認爲false
                    if (!f.mRetaining) {
                        //關鍵代碼,內部會調用【Fragment生命週期】onCreate
                        f.performCreate(f.mSavedFragmentState);
                    } else {
                        f.restoreChildFragmentState(f.mSavedFragmentState, true);
                        f.mState = Fragment.CREATED;
                    }
                    f.mRetaining = false;
                    
                    //Fragment是否認義在Layout文件的<fragment>標籤中的,本次栗子爲代碼動態添加Fragment,因此爲false
                    if (f.mFromLayout) {
                        // For fragments that are part of the content view
                        // layout, we need to instantiate the view immediately
                        // and the inflater will take care of adding it.
                        f.mView = f.performCreateView(f.getLayoutInflater(
                                f.mSavedFragmentState), null, f.mSavedFragmentState);
                        if (f.mView != null) {
                            f.mView.setSaveFromParentEnabled(false);
                            if (f.mHidden) f.mView.setVisibility(View.GONE);
                            f.onViewCreated(f.mView, f.mSavedFragmentState);
                        }
                    }
                    //注意,這裏沒有break
                case Fragment.CREATED:
                    if (newState > Fragment.CREATED) {
                        if (!f.mFromLayout) {
                            //開始建立Fragment的view
                            ViewGroup container = null;
                            if (f.mContainerId != 0) {
                                if (f.mContainerId == View.NO_ID) {
                                    throwException(new IllegalArgumentException(""));
                                }
                                
                                //調用Activity的findViewById方法查找控件
                                container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
                                if (container == null && !f.mRestored) {
                                    ......
                                }
                            }
                            f.mContainer = container;
                            //關鍵代碼,內部會調用【Fragment生命週期】onCreateView,並返回Fragment中new出的視圖
                            f.mView = f.performCreateView(f.getLayoutInflater(
                                    f.mSavedFragmentState), container, f.mSavedFragmentState);
                            if (f.mView != null) {
                                f.mView.setSaveFromParentEnabled(false);
                                if (container != null) {
                                    //設置入場動畫
                                    Animator anim = loadAnimator(f, transit, true,
                                            transitionStyle);
                                    if (anim != null) {
                                        anim.setTarget(f.mView);
                                        setHWLayerAnimListenerIfAlpha(f.mView, anim);
                                        anim.start();
                                    }
                                    //把Fragment的view加入到父控件
                                    container.addView(f.mView);
                                }
                                if (f.mHidden) f.mView.setVisibility(View.GONE);
                                
                                //【Fragment生命週期】onViewCreated回調
                                f.onViewCreated(f.mView, f.mSavedFragmentState);
                            }
                        }
                        
                        //關鍵代碼,內部會調用【Fragment生命週期】onActivityCreated
                        f.performActivityCreated(f.mSavedFragmentState);
                        if (f.mView != null) {
                            f.restoreViewState(f.mSavedFragmentState);
                        }
                        f.mSavedFragmentState = null;
                    }
                case Fragment.ACTIVITY_CREATED:
                    if (newState > Fragment.ACTIVITY_CREATED) {
                        f.mState = Fragment.STOPPED;
                    }
                case Fragment.STOPPED:
                    if (newState > Fragment.STOPPED) {
                        if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
                        //關鍵代碼,內部會調用【Fragment生命週期】onStart
                        f.performStart();
                    }
                case Fragment.STARTED:
                    if (newState > Fragment.STARTED) {
                        //關鍵代碼,內部會調用【Fragment生命週期】onResume
                        f.performResume();
                        // Get rid of this in case we saved it and never needed it.
                        f.mSavedFragmentState = null;
                        f.mSavedViewState = null;
                    }
            }
        } else if (f.mState > newState) {
            //state降級處理
            ......
        }
        
        if (f.mState != newState) {
            f.mState = newState;
        }
    }
複製代碼

這段代碼邏輯仍是比較長,我把註釋寫在代碼裏了。能夠看到,這個代碼寫得很巧妙,經過switch case控制,能夠一層一層地把Fragment的生命週期推動下去,好比當前fragnemt的state是Fragment.STARTED,那麼它就只會執行performResume,若是Fragment的狀態是Fragment.INITIALIZING,那麼就會從switch的最開始依次執行下來,把Fragment的生命週期onAttach-->onResume依次調用。 簡要說明下上面的代碼:

  • mHost是FragmentHostCallback抽象類的實例,它的實現類是Activity的HostCallbacks
  • mParent爲null
  • mHost.getContext()獲取的context就是宿主Activity實例
  • Fragment中建立的View會自動經過container.addView(f.mView)添加到父控件中

不少Fragment的生命週期是經過Fragment的performXxx()方法去調用的,好比:

void performCreate(Bundle savedInstanceState) {
        ......
        onCreate(savedInstanceState);
        ......
    }

    View performCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        ......
        return onCreateView(inflater, container, savedInstanceState);
    }

    void performActivityCreated(Bundle savedInstanceState) {
        ......
        onActivityCreated(savedInstanceState);
        ......
    }

    void performStart() {
        ......
        onStart();
        ......
    }

    void performResume() {
        ......
        onResume();
        ......
    }
複製代碼

Fragment狀態的降級操做

有些童鞋們可能會有疑問,上面只分析到了onAttach->onResume生命週期的回調,那onPause、onDestroy等方法又是何時執行的呢?咱們再看下剛纔的代碼

if (f.mState < newState) {
        ......
    } else if (f.mState > newState) {
        //state降級處理
        ......
    }
複製代碼

答案就是在else if分支裏面,好比當Acivity鎖屏的時候,就Activity生命週期會自動回調onPause,從而觸發dispatchPause,在裏面調用moveToState(Fragment.STARTED, false); 因爲Fragment當前的狀態是RESUMED狀態,大於newState,因此就會走else if的分支,觸發相應的生命週期方法。else if分支的邏輯和state升級的差很少,這裏就再進行分析了

生命週期

2019-9-2-11-26-16.png
最後,放張官網上公佈的Fragment生命週期圖,經過代碼分析,咱們發現代碼的中生命週期的調用順序和圖中確實是一致的

總結

本文大體地從源碼的角度分析了Fragment建立、生命週期回調的過程,若是讀者對Fragment的removereplacehidedetachattach等操做有興趣的話,能夠自行分析,核心代碼主要在BackStackRecord類的run方法以及FragmentManagerImpl的moveToState方法中。

相關文章
相關標籤/搜索