Fragment 源碼學(xué)習(xí),從源碼理解 Fragment 生命周期

基于 support-fragment-26.0.0-alpha1

Fragment 的創(chuàng)建

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

Fragment 可以在直接在 FragmentActivity 創(chuàng)建的時(shí)候垢夹,聲明在 xml 文件之中。也可以在 Activity 創(chuàng)建以后墓塌,動(dòng)態(tài)的創(chuàng)建桩皿。

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

這里有個(gè)問題?

Fragment 本身不是一個(gè) View 的子類衡楞。
在方式二中我們知道我們 new 了一個(gè) Fragment 交給 FragmentTransaction
那么!方式一是如何創(chuàng)建 Fragment的 敦姻?

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

FragmentActivity 從 xml 創(chuàng)建 Fragment

先看下 FragmentActivity 的繼承關(guān)系

fragment_01.png
onCreateView 方法創(chuàng)建 Fragment

在 BaseFragmentActivityApi14 中發(fā)現(xiàn)以下代碼

@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 方法,并且聲明了一個(gè) dispatchFragmentsOnCreateView 方法暖呕。

FragmentActivity 實(shí)現(xiàn)了 dispatchFragmentsOnCreateView

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

最終 FragmentManager 中找到了 onCreateView 負(fù)責(zé)創(chuàng)建 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;
    } ……
}    

可以看出,最終還是用了反射創(chuàng)建了 Fragment兑凿。 并且返回 fragment.mView 給 onCreateView

誰(shuí)調(diào)用 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 ,其實(shí)并不嚴(yán)謹(jǐn)拗秘。因?yàn)?Activity 也是一個(gè) Factory2 的實(shí)現(xiàn)圣絮。

在 Activity 的 attach() 方法調(diào)用了

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 實(shí)現(xiàn)的 Factory2. onCreateView 。并攔截 <fragment> 標(biāo)簽交給 FragmentActivity 的 dispatchFragmentsOnCreateView() 方法雕旨。

總結(jié)一個(gè)簡(jiǎn)單的 UML 圖

fragment_02.png

Fragment 執(zhí)行生命周期

跟隨 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) 會(huì)執(zhí)行 Fragment 的 onCreate() 方法扮匠。

然后在 onStart() 方法中調(diào)用 mFragments.dispatchStart() ,執(zhí)行 Fragment 的 onStart()方法 凡涩。

然后在 onResume() 是會(huì)調(diào)用 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);
        }
    }

};

接著會(huì)執(zhí)行 onResumeFragments() -> mFragments.dispatchResume() , 執(zhí)行 Fragment 的 onResume() 方法棒搜。

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

在 FragmentActivity 中動(dòng)態(tài)添加 Fragment

在 FragmentActivity 中動(dòng)態(tài)添加 Fragment 需要獲得一個(gè) FragmentTransaction

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

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

獲得 FragmentTransaction

獲得 FragmentTransaction 首先獲得 FragmentManager 力麸。

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

mFragments 是一個(gè) FragmentController

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

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

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

其中 mHost 就是 HostCallbacks 的實(shí)例末盔。HostCallbacks 繼承 FragmentHostCallback

FragmentManagerImpl getFragmentManagerImpl() {
    return mFragmentManager;
}

在 FragmentHostCallback 中有成員變量

final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();

所以 FragmentTransaction 由 FragmentManagerImpl 創(chuàng)建。FragmentManagerImpl 又是 FragmentManager 的實(shí)例座慰。

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

所以最終我們獲得的 FragmentTransaction 是一個(gè) BackStackRecord 實(shí)例陨舱。

獲得 FragmentTransaction 的 add() 、replace()

這兩個(gè)方法都在 BackStackRecord 中 版仔,有很多 add()游盲、replace() 方法,這里貼兩個(gè)重要的

@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() 最終都調(diào)用 doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) 方法益缎,只是 opcmd 值不同。

最終會(huì)添加一個(gè) Op 對(duì)象

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 中實(shí)現(xiàn)然想。

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

然后執(zhí)行

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

mIndex 是 BackStackRecord 在 FragmentManager 中保存的一個(gè) ArrayList 的位置莺奔。

然后執(zhí)行

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

接著執(zhí)行

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 是一個(gè) Runnable

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

然后就快到關(guān)鍵方法

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;
}

接著執(zhí)行

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 最終會(huì)執(zhí)行 addToFirstInLastOut

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

在 moveToState 中,會(huì)執(zhí)行 Fragment 的 onAttach() 方法

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

mManager.moveToState(mManager.mCurState, true);

因?yàn)榇藭r(shí) Activity 已經(jīng)是 Resume 狀態(tài)变泄,所以 mManager.mCurState == RESUMED

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

通過上面可以發(fā)現(xiàn) void moveToState(Fragment f, int newState, int transit, int transitionStyle,boolean keepActive) 是最關(guān)鍵的方法令哟。Fragment 的各個(gè)狀態(tài)都是通過這個(gè)方法進(jìn)行切換的。

void moveToState(Fragment f, int newState, int transit, int transitionStyle,
        boolean keepActive) {
    ……
    if (f.mState <= newState) { // Fragment 從后臺(tái)到顯示
        ……
        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 從顯示到后臺(tái)
        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) {
                    ……
                }
        }
    }
    ……
}

參考資料

安卓基礎(chǔ):Activity/Fragment 生命周期

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末妨蛹,一起剝皮案震驚了整個(gè)濱河市屏富,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蛙卤,老刑警劉巖狠半,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異颤难,居然都是意外死亡神年,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門行嗤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瘤袖,“玉大人,你說我怎么就攤上這事昂验∥娴校” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵既琴,是天一觀的道長(zhǎng)占婉。 經(jīng)常有香客問我,道長(zhǎng)甫恩,這世上最難降的妖魔是什么逆济? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上奖慌,老公的妹妹穿的比我還像新娘抛虫。我一直安慰自己,他們只是感情好简僧,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布建椰。 她就那樣靜靜地躺著,像睡著了一般岛马。 火紅的嫁衣襯著肌膚如雪棉姐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天啦逆,我揣著相機(jī)與錄音伞矩,去河邊找鬼。 笑死夏志,一個(gè)胖子當(dāng)著我的面吹牛乃坤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播沟蔑,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼侥袜,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了溉贿?” 一聲冷哼從身側(cè)響起枫吧,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎宇色,沒想到半個(gè)月后九杂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宣蠕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年例隆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抢蚀。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡镀层,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出皿曲,到底是詐尸還是另有隱情唱逢,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布屋休,位于F島的核電站坞古,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏劫樟。R本人自食惡果不足惜痪枫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一织堂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧奶陈,春花似錦易阳、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至声搁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捕发,已是汗流浹背疏旨。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留扎酷,地道東北人檐涝。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像法挨,于是被迫代替她去往敵國(guó)和親谁榜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容