Fragment 源碼學習,從源碼理解 Fragment 生命周期

基于 support-fragment-26.0.0-alpha1

Fragment 的創建

Fragment 的使用離不開 FragmentActivity ,或者說 Fragment 必須依附于 FragmentActivity。

Fragment 可以在直接在 FragmentActivity 創建的時候,聲明在 xml 文件之中。也可以在 Activity 創建以后,動態的創建。

  1. 方式一

     <?xml version="1.0" encoding="utf-8"?>
     <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
     
         <fragment
            android:id="@+id/test_frament"
            class="xxx.xxx.xxx.xxFragment"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
     </LinearLayout>
    
  2. 方式二

     getSupportFragmentManager().beginTransaction().replace(R.id.fragment, new xxFragment()).commit();
    

這里有個問題?

Fragment 本身不是一個 View 的子類。
在方式二中我們知道我們 new 了一個 Fragment 交給 FragmentTransaction
那么!方式一是如何創建 Fragment的 ?

在前面閱讀LayoutInflater 源碼 我們可以得知,xml 里面聲明的 View 都是通過 LayoutInflater 創建。那么 FragmentActivity 如何通過 xml 創建 Fragment 呢?

FragmentActivity 從 xml 創建 Fragment

先看下 FragmentActivity 的繼承關系

fragment_01.png
onCreateView 方法創建 Fragment

在 BaseFragmentActivityApi14 中發現以下代碼

@Override
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
    final View v = dispatchFragmentsOnCreateView(parent, name, context, attrs);
    if (v == null) {
        return super.onCreateView(parent, name, context, attrs);
    }
    return v;
}

@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
    final View v = dispatchFragmentsOnCreateView(null, name, context, attrs);
    if (v == null) {
        return super.onCreateView(name, context, attrs);
    }
    return v;
}

abstract View dispatchFragmentsOnCreateView(View parent, String name,
        Context context, AttributeSet attrs);

這里看到 BaseFragmentActivityApi14 繼承了 onCreateView 方法,并且聲明了一個 dispatchFragmentsOnCreateView 方法。

FragmentActivity 實現了 dispatchFragmentsOnCreateView

@Override
final View dispatchFragmentsOnCreateView(View parent, String name, Context context,
        AttributeSet attrs) {
    return mFragments.onCreateView(parent, name, context, attrs);
}

最終 FragmentManager 中找到了 onCreateView 負責創建 Fragment

@Override
public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
    if (!"fragment".equals(name)) {
        return null;
    }

    ……
    if (fragment == null) {
        fragment = mContainer.instantiate(context, fname, null);
        ……
        addFragment(fragment, true);
        ……
    }……
    return fragment.mView;
}

FragmentContainer 中 instantiate 方法

public Fragment instantiate(Context context, String className, Bundle arguments) {
    return Fragment.instantiate(context, className, arguments);
}

然后又回到了 Fragment 中

public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) {
    try {
        Class<?> clazz = sClassMap.get(fname);
        ……
        Fragment f = (Fragment)clazz.newInstance();
        ……
        return f;
    } ……
}    

可以看出,最終還是用了反射創建了 Fragment。 并且返回 fragment.mView 給 onCreateView

誰調用 onCreateView ?

先看一段 LayoutInflater 中 createViewFromTag() 方法

try {
    View view;
    if (mFactory2 != null) {
        view = mFactory2.onCreateView(parent, name, context, attrs);
    } else if (mFactory != null) {
        view = mFactory.onCreateView(name, context, attrs);
    } else {
        view = null;
    }
    if (view == null && mPrivateFactory != null) {
        view = mPrivateFactory.onCreateView(parent, name, context, attrs);
    }
    if (view == null) {
        final Object lastContext = mConstructorArgs[0];
        mConstructorArgs[0] = context;
        try {
            if (-1 == name.indexOf('.')) {
                view = onCreateView(parent, name, attrs);
            } else {
                view = createView(name, null, attrs);
            }
        } finally {
            mConstructorArgs[0] = lastContext;
        }
    }
    return view;

LayoutInflater 源碼 我們講到 mFactory2、mFactory、mPrivateFactory 全部為 null ,其實并不嚴謹。因為 Activity 也是一個 Factory2 的實現。

在 Activity 的 attach() 方法調用了

final void attach(Context context, ActivityThread aThread,
        Instrumentation instr, IBinder token, int ident,
        Application application, Intent intent, ActivityInfo info,
        CharSequence title, Activity parent, String id,
        NonConfigurationInstances lastNonConfigurationInstances,
        Configuration config, String referrer, IVoiceInteractor voiceInteractor,
        Window window) {
    ……
    mWindow.getLayoutInflater().setPrivateFactory(this);
    ……
}

而 BaseFragmentActivityApi14 又一次重載了 Activity 實現的 Factory2. onCreateView 。并攔截 <fragment> 標簽交給 FragmentActivity 的 dispatchFragmentsOnCreateView() 方法。

總結一個簡單的 UML 圖

fragment_02.png

Fragment 執行生命周期

跟隨 FragmentActivity 生命周期

在 FragmentActivity 的 onCreate() 中

 protected void onCreate(@Nullable Bundle savedInstanceState) {
    mFragments.attachHost(null /*parent*/);

    super.onCreate(savedInstanceState);
    ……
    mFragments.dispatchCreate();
}

public void dispatchCreate() {
    mHost.mFragmentManager.dispatchCreate();
}

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

其中 moveToState(Fragment.CREATED, false) 會執行 Fragment 的 onCreate() 方法。

然后在 onStart() 方法中調用 mFragments.dispatchStart() ,執行 Fragment 的 onStart()方法 。

然后在 onResume() 是會調用 mHandler.sendEmptyMessage(MSG_RESUME_PENDING)

final Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_REALLY_STOPPED:
                if (mStopped) {
                    doReallyStop(false);
                }
                break;
            case MSG_RESUME_PENDING:
                onResumeFragments();
                mFragments.execPendingActions();
                break;
            default:
                super.handleMessage(msg);
        }
    }

};

接著會執行 onResumeFragments() -> mFragments.dispatchResume() , 執行 Fragment 的 onResume() 方法。

以此類推 Fragment 的生命周期跟隨 FragmentActivity 的生命周期依次執行。

在 FragmentActivity 中動態添加 Fragment

在 FragmentActivity 中動態添加 Fragment 需要獲得一個 FragmentTransaction

然后通過 FragmentTransaction.replace(R.id.fragment, new xxFragment()) 或者 FragmentTransaction.add(R.id.fragment, new xxFragment()) 添加一個創建的 Fragment 到 FragmentActivity(其實是 FragmentManager)

最后通過 FragmentTransaction.commit() 顯示 Fragment。

獲得 FragmentTransaction

獲得 FragmentTransaction 首先獲得 FragmentManager 。

public FragmentManager getSupportFragmentManager() {
    return mFragments.getSupportFragmentManager();
}

mFragments 是一個 FragmentController

final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

FragmentController 的所有方法,都是包裹這 HostCallbacks() 來實現的。HostCallbacks 是 FragmentHostCallback 的子類

public FragmentManager getSupportFragmentManager() {
    return mHost.getFragmentManagerImpl();
}

其中 mHost 就是 HostCallbacks 的實例。HostCallbacks 繼承 FragmentHostCallback

FragmentManagerImpl getFragmentManagerImpl() {
    return mFragmentManager;
}

在 FragmentHostCallback 中有成員變量

final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();

所以 FragmentTransaction 由 FragmentManagerImpl 創建。FragmentManagerImpl 又是 FragmentManager 的實例。

@Override
public FragmentTransaction beginTransaction() {
    return new BackStackRecord(this);
}

所以最終我們獲得的 FragmentTransaction 是一個 BackStackRecord 實例。

獲得 FragmentTransaction 的 add() 、replace()

這兩個方法都在 BackStackRecord 中 ,有很多 add()、replace() 方法,這里貼兩個重要的

@Override
public FragmentTransaction add(int containerViewId, Fragment fragment) {
    doAddOp(containerViewId, fragment, null, OP_ADD);
    return this;
}

@Override
public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) {
    if (containerViewId == 0) {
        throw new IllegalArgumentException("Must use non-zero containerViewId");
    }

    doAddOp(containerViewId, fragment, tag, OP_REPLACE);
    return this;
}

可以看出無論 add()、replace() 最終都調用 doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) 方法,只是 opcmd 值不同。

最終會添加一個 Op 對象

private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
    ……
    addOp(new Op(opcmd, fragment));
}

void addOp(Op op) {
    mOps.add(op);
    op.enterAnim = mEnterAnim;
    op.exitAnim = mExitAnim;
    op.popEnterAnim = mPopEnterAnim;
    op.popExitAnim = mPopExitAnim;
}
獲得 FragmentTransaction 的 commit()

commit() 同樣在 BackStackRecord 中實現。

@Override
public int commit() {
    return commitInternal(false);
}

然后執行

int commitInternal(boolean allowStateLoss) {
    ……
    mCommitted = true;
    if (mAddToBackStack) {
        mIndex = mManager.allocBackStackIndex(this);
    } else {
        mIndex = -1;
    }
    mManager.enqueueAction(this, allowStateLoss);
    return mIndex;
}

mIndex 是 BackStackRecord 在 FragmentManager 中保存的一個 ArrayList 的位置。

然后執行

public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
    if (!allowStateLoss) {
        checkStateLoss();
    }
    synchronized (this) {
        ……
        scheduleCommit();
    }
}

接著執行

private void scheduleCommit() {
    synchronized (this) {
        boolean postponeReady =
                mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
        boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
        if (postponeReady || pendingReady) {
            mHost.getHandler().removeCallbacks(mExecCommit);
            mHost.getHandler().post(mExecCommit);
        }
    }
}

mExecCommit 是一個 Runnable

Runnable mExecCommit = new Runnable() {
    @Override
    public void run() {
        execPendingActions();
    }
};

然后就快到關鍵方法

public boolean execPendingActions() {
    ensureExecReady(true);

    boolean didSomething = false;
    while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
        mExecutingActions = true;
        try {
            optimizeAndExecuteOps(mTmpRecords, mTmpIsPop);
        } finally {
            cleanupExec();
        }
        didSomething = true;
    }

    doPendingDeferredStart();

    return didSomething;
}

接著執行

private void optimizeAndExecuteOps(ArrayList<BackStackRecord> records,
        ArrayList<Boolean> isRecordPop) {
    ……
    int startIndex = 0;
    for (int recordNum = 0; recordNum < numRecords; recordNum++) {
            ……
            executeOpsTogether(records, isRecordPop, recordNum, optimizeEnd);
            ……
        }
    }
    ……
}

然后到了 executeOpsTogether

private void executeOpsTogether(ArrayList<BackStackRecord> records,
        ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
    ……
    if (!allowOptimization) {
        FragmentTransition.startTransitions(this, records, isRecordPop, startIndex, endIndex,
                false);
    }
    executeOps(records, isRecordPop, startIndex, endIndex);
    ……
}

其中 FragmentTransition.startTransitions 最終會執行 addToFirstInLastOut

然后執行 manager.moveToState(fragment, Fragment.CREATED, 0, 0, false);

在 moveToState 中,會執行 Fragment 的 onAttach() 方法

其中的 executeOps(records, isRecordPop, startIndex, endIndex) 之中執行 void executeOps()

mManager.moveToState(mManager.mCurState, true);

因為此時 Activity 已經是 Resume 狀態,所以 mManager.mCurState == RESUMED

然后 mManager.moveToState 會一次執行
Fragment.performCreateView()
Fragment.performActivityCreated()
Fragment.performStart()
Fragment.performResume()

通過上面可以發現 void moveToState(Fragment f, int newState, int transit, int transitionStyle,boolean keepActive) 是最關鍵的方法。Fragment 的各個狀態都是通過這個方法進行切換的。

void moveToState(Fragment f, int newState, int transit, int transitionStyle,
        boolean keepActive) {
    ……
    if (f.mState <= newState) { // Fragment 從后臺到顯示
        ……
        switch (f.mState) {
            case Fragment.INITIALIZING:
                if (newState > Fragment.INITIALIZING) {
                    ……
                    f.onAttach(mHost.getContext());
                    ……
                }

            case Fragment.CREATED:
                ……
                if (newState > Fragment.CREATED) {
                        ……
                        f.mView = f.performCreateView(f.getLayoutInflater(
                                f.mSavedFragmentState), container, f.mSavedFragmentState);
                        ……
                    }

                    f.performActivityCreated(f.mSavedFragmentState);
                    ……
                }
            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);
                    f.performStart();
                    dispatchOnFragmentStarted(f, false);
                }
            case Fragment.STARTED:
                if (newState > Fragment.STARTED) {
                    if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
                    f.performResume();
                    dispatchOnFragmentResumed(f, false);
                    f.mSavedFragmentState = null;
                    f.mSavedViewState = null;
                }
        }
    } else if (f.mState > newState) {// Fragment 從顯示到后臺
        switch (f.mState) {
            case Fragment.RESUMED:
                if (newState < Fragment.RESUMED) {
                    if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
                    f.performPause();
                    dispatchOnFragmentPaused(f, false);
                }
            case Fragment.STARTED:
                if (newState < Fragment.STARTED) {
                    if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
                    f.performStop();
                    dispatchOnFragmentStopped(f, false);
                }
            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) {
                    ……
                    f.performDestroyView();
                    dispatchOnFragmentViewDestroyed(f, false);
                    ……
                }
            case Fragment.CREATED:
                if (newState < Fragment.CREATED) {
                    ……
                }
        }
    }
    ……
}

參考資料

安卓基礎:Activity/Fragment 生命周期

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,488評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,034評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,327評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,554評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,337評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,883評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,114評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,625評論 1 332
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,555評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,737評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,973評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,615評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,343評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,699評論 2 370

推薦閱讀更多精彩內容