Fragment 原始碼解析

wenchieh發表於2017-12-13

Fragment 原始碼解析
分析原始碼前我自己想了幾個問題,帶著目的去看。

  1. Activity 是如何與 Fragment 關聯,如何操作 fragment 的?
  2. Fragment 的本質是一個 View 嗎?

前言

Activity 和 Fragment 密不可分, 分析 Fragment 必須去從 Activity 的生命週期著手去分析其中和 Fragment 的關聯。

Fragment 原始碼解析

我們在 Activity 操作 Fragment 通過如下程式碼:

    getSupportFragmentManager()
        .beginTransaction()
        .add(R.id.container, new MyFragment())
        .commit();
複製程式碼

檢視原始碼可以發現 getSupportFragmentManager() 內部通過 FragmentController 操作。

這個 FragmentController 類是負責控制 Fragment 的。

它的內部持有一個 FragmentHostCallback,所有的核心操作都間接交給了這個類,這個 FragmentHostCallback 類才是重點。而且它的命名是 mHost,它才是最主要的操作者。FragmentController 只是箇中間物件。

// Fragment 可以寄生在任何物件上,讓 fragment 寄存在自己身上需要實現 FragmentHostCallback 類,實現裡面的一些方法 。 
public abstract class FragmentHostCallback<E> extends FragmentContainer
複製程式碼

Fragment 原始碼解析

Activity 通過 FragmentController 類管理 Fragment。FragmentController 的例項在成員變數中例項化,所以當 Activity 被例項化的時候,FragmentController 就被例項化了。

public class FragmentActivity {
    final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
// ...
}
複製程式碼

那麼 Activity 在哪裡被例項化的?

Activit 的例項化

Activity 的啟動過程

例項 Activity 的過程發生在 ActivityThread 中的 performLaunchActivity() 中的這段程式碼。

//  通過 Instrumentation 的 newActivity 方法使用類載入器建立 Activity 物件
activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
activity.attach();                
/**-------------------------------------------------------*/                
// newActivity() 方法內部呼叫了 Activity 的無參例項:

Activity activity = (Activity)clazz.newInstance();

複製程式碼

在 Activity 例項化之後會立刻呼叫 Activity#attach(),這個方法內部會呼叫mFragments.attachHost(null /*parent*/);

public void attachHost(Fragment parent) {
    mHost.mFragmentManager.attachController(
        mHost, mHost /*container*/, parent);
}
複製程式碼
// 第一個引數是宿主;
// 第二引數是容器,FragmentHostCallback 繼承於 FragmentContainer 也代表容器;
// 第三個引數是父類 Fragment
public void attachController(FragmentHostCallback host,
            FragmentContainer container, Fragment parent) {
        // 宿主只能有一個
        if (mHost != null) throw new IllegalStateException("Already attached");
        mHost = host;
        mContainer = container;
        mParent = parent;
}
複製程式碼

這個方法最終將宿主物件和控制器中的 FragmentManager 關聯,內部就是進行賦值。
為什麼裡面傳的是 null?註釋寫了 parent。應該是傳入的父類 fragment,而由 Activity 建立的 fragment 沒有父類,所以是 null。

FragmentController 的初始化

    final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
複製程式碼
public static final FragmentController createController(FragmentHostCallback<?> callbacks) {
        return new FragmentController(callbacks);
}
複製程式碼

createController() 方法中傳入了一個 HostCallbacks 例項。

HostCallbacksFragmentActivity 的內部類,是 FragmentHostCallback 的實現類。

HostCallbacks 的初始化

在建構函式中呼叫父類的建構函式,將當前的 Activity 例項傳進去:

public HostCallbacks() {
    super(FragmentActivity.this /*fragmentActivity*/);
}
複製程式碼

父類 FragmentHostCallback 有 3 個構造方法:

public FragmentHostCallback(Context context, Handler handler, int windowAnimations) {
    this(context instanceof Activity ? (Activity) context : null, context, handler, windowAnimations);
}

FragmentHostCallback(FragmentActivity activity) {
    this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);
}

FragmentHostCallback(Activity activity, Context context, Handler handler,
    int windowAnimations) {
    mActivity = activity;
    mContext = context;
    mHandler = handler;
    mWindowAnimations = windowAnimations;
}
複製程式碼

HostCallbacks 呼叫的是第二個構造,將 mActivitymContext 賦值為 Activity 的例項,mHandler 賦值為 Activity 中的 mHandlermWindowAnimations 直接賦值 0。

這裡的 mHandler 也是在 Activty 被例項化的時候例項化,看程式碼是處理 Fragmentstopresume 狀態的。具體怎麼處理的後面再看,這裡先了解傳入的 mHandler 在哪裡初始化的。

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);
        }
    }
};
複製程式碼

FragmentHostCallback 的成員變數

// Actvity
private final Activity mActivity;

// 上下文
final Context mContext;

// 在 Activity 中例項化的 handler,負責處理 fragment 的生命週期,內部執行具體的事務
private final Handler mHandler;

// window 的動畫
final int mWindowAnimations;

// 在成員變數中直接例項化了 FragmentManagerImpl
final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();

// loaderManager 的集合, loadMangaer 通過 Fragment#getLoaderManager() 獲取,最終是由 FragmentHostCallback#getLoaderManager() 獲取。
/** The loader managers for individual fragments [i.e. Fragment#getLoaderManager()] */
private SimpleArrayMap<String, LoaderManager> mAllLoaderManagers;

// 標記 fragmentLoader 是否應該儲存 fragment 的狀態
/** Whether or not fragment loaders should retain their state */
private boolean mRetainLoaders;

// fragment 宿主的 loaderManager,通過 Activity#getLoaderManager() 獲取, 最終是由 FragmentHostCallback#getLoaderManagerImpl() 獲取。
/** The loader manger for the fragment host [i.e. Activity#getLoaderManager()] */
private LoaderManagerImpl mLoaderManager;

// 檢查 loaderManager 是否為空
private boolean mCheckedForLoaderManager;

// 宿主的 loaderManager 是否開始載入
/** Whether or not the fragment host loader manager was started */
private boolean mLoadersStarted;

複製程式碼

根據註釋和區域性程式碼初步瞭解一下這些變數的含義,有個大概的印象。可以看到內部有一個 loader manager 的存在。宿主有一個單獨的載入器,以 "(root)" 為鍵存入了 SimpleArrayMap<String, LoaderManager> 集合中。 每個 fragment 也對應有一個自己的 loader manager。 這個 load manager 是幹啥的,現在還不知道,後面再看。

FragmentManagerImpl 的初始化

Fragment 原始碼解析

FragmentManager、FragmentManagerState、FragmentManagerImpl 三個類共存於 FragmentManager.java 檔案下,它們是同級的關係,而不是內部類的關係。

我們平常操作 fragment 所呼叫的 getSupportFragmentManager() 返回的就是 FragmentManager 物件。顧名思義,它是 fragment 的管理者,負責新增、刪除、替換 fragment 等一些操作。

FragmentManager 是一個抽象類,定義了操作 fragment 的一系列方法,如開啟事務、進棧、彈棧等。除此之外,有一個 BackStackEntry 介面和一個 FragmentLifecycleCallbacks 生命週期回撥。

public abstract class FragmentManager {

    public abstract FragmentTransaction beginTransaction();
    public abstract boolean executePendingTransactions();
    public abstract Fragment findFragmentById(@IdRes int id);
    public abstract Fragment findFragmentByTag(String tag);
    public abstract void popBackStack();
    public abstract boolean popBackStackImmediate();
    // .....
  
  
    // 當呼叫 FragmentTransaction#addToBackStack(String) 時,將放入回退棧的 frament 的資訊存起來。用於以後檢索。
    public interface BackStackEntry {
        public int getId();
        public String getName();
        @StringRes public int getBreadCrumbTitleRes();
        @StringRes public int getBreadCrumbShortTitleRes();
        public CharSequence getBreadCrumbTitle();
        public CharSequence getBreadCrumbShortTitle();
    }

    // 回退棧內容改變時的監聽介面
    public interface OnBackStackChangedListener {
        public void onBackStackChanged();
      
    }
    
    // frgment 的生命週期回撥
    public abstract static class FragmentLifecycleCallbacks {
        public void onFragmentPreAttached(FragmentManager fm, Fragment f, Context context) {
        }

        public void onFragmentAttached(FragmentManager fm, Fragment f, Context context) {
        }

        public void onFragmentCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
        }

        public void onFragmentActivityCreated(FragmentManager fm, Fragment f,
        Bundle savedInstanceState) {
        }

        public void onFragmentViewCreated(FragmentManager fm, Fragment f, View v,
        Bundle savedInstanceState) {
        }
        // ...
  }
 }
複製程式碼

FragmentManager 的具體實現是 FragmentManagerImpl 具體內部的實現,現在先不深入看了。現在先把主要的流程走通,後面再看具體的細節。

final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
複製程式碼

FragmentMangerImpl 在 FragmentHostCallback() 的成員變數中被例項化。所以 Activity 被例項化的時候,FragmentControllerHostCallbacksFragmentManagerImpl 都會被例項化。然後再通過我們前面說到的 attach() 將他們關聯,讓 FragmentManagerImpl 例項持有 HostCallbacks 例項。

Fragment 原始碼解析

Activity 的 onCreate()

Activity 的生命週期從 onCreate 開始, 在 Activity 例項化後,FragmentManager 就可以被使用來操作 fragment,即我們常用的 getFragmentManager().beginTransaction().add() 等操作。 這些操作都是在 Activity 的 onCreate 完成的。

Activity 的 onCreate() 發生在哪裡?

onCreate() 也發生在 ActivityThread 中的 performLaunchActivity() 中:

mInstrumentation.callActivityOnCreate(activity, r.state);
複製程式碼
// Instrumentation
public void callActivityOnCreate(Activity activity, Bundle icicle) {
        prePerformCreate(activity);
        activity.performCreate(icicle);
        postPerformCreate(activity);
}
複製程式碼
// Activity
  final void performCreate(Bundle icicle) {
        restoreHasCurrentPermissionRequest(icicle);
        onCreate(icicle);
        mActivityTransitionState.readState(icicle);
        performCreateCommon();
    }
複製程式碼
protected void onCreate(@Nullable Bundle savedInstanceState) {
    // ...
    
    mFragments.dispatchCreate();
}

複製程式碼
 final void performCreateCommon() {
    // ...
    mFragments.dispatchActivityCreated();
    // ...    
}
複製程式碼

最終在 Activity 的 onCreate 呼叫了 FragmentController#dispatchCreate(),接著在 performCreateCommon() 中呼叫了 FragmentController#dispatchActivityCreated()

public void dispatchCreate() {
    mHost.mFragmentManager.dispatchCreate();
}
public void dispatchActivityCreated() {
    mHost.mFragmentManager.dispatchActivityCreated();
}
複製程式碼

這兩個方法都是呼叫的 HostCallback 例項中的 FragmentManagerImpl 例項的方法。

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

public void dispatchActivityCreated() {
    mStateSaved = false;
    mExecutingActions = true;
    moveToState(Fragment.ACTIVITY_CREATED, false);
    mExecutingActions = false;
}
複製程式碼

看到這裡結合原始碼註釋我們知道這倆方法通過 moveToState() 去更新 Fragment 的 狀態。並且用 mExecutingActions 標記事務是否在進行。 用 mStateSaved 標記狀態是否儲存了。

void moveToState(int newState, boolean always) {
        // 狀態沒變且沒有設定必須更新就結束
        if (!always && newState == mCurState) {
            return;
        }
        // 更新當前狀態
        mCurState = newState;
        
        // ...
    }
複製程式碼

這個方法有 2 個引數,第一個引數是即將更新的狀態,第二個參數列示是否更新所有 fragment 的狀態。

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.

int mState = INITIALIZING;
複製程式碼

Fragment 的狀態有上面幾種。預設是 INITIALIZING。

這裡我有個地方有點疑惑:Activity onCreate() 的時候給 FragmentManager 通知更新 CREATED 狀態,此時應該還沒有建立任何 fragment,為啥是個 CREATED。看到後面又有個 STOPPED,表示建立完成,還沒開始的狀態。那麼 CREATED 應該表示的是開始建立,還沒建立好。

Fragment 原始碼解析

事務操作

接著我們會在 Activity 中的 onCreate() 建立執行 fragment 的事務。 getFragmentManager() 前面已經看過,現在來看 beginTransaction()

// FragmentManagerImpl 
public FragmentTransaction beginTransaction() {
    return new BackStackRecord(this);
}
複製程式碼
// BackStackState
final class BackStackRecord extends FragmentTransaction implements
        FragmentManager.BackStackEntry, FragmentManagerImpl.OpGenerator {
    static final String TAG = FragmentManagerImpl.TAG;
    static final boolean SUPPORTS_TRANSITIONS = Build.VERSION.SDK_INT >= 21;

    final FragmentManagerImpl mManager;
    
    // 表示一系列操作
    static final int OP_NULL = 0;
    static final int OP_ADD = 1;
    static final int OP_REPLACE = 2;
    static final int OP_REMOVE = 3;
    static final int OP_HIDE = 4;
    static final int OP_SHOW = 5;
    static final int OP_DETACH = 6;
    static final int OP_ATTACH = 7;
    static final int OP_SET_PRIMARY_NAV = 8;
    static final int OP_UNSET_PRIMARY_NAV = 9;
    
    // 雙連結串列的節點
    static final class Op {
        // 執行的操作(新增/刪除。。。)
        int cmd;
        Fragment fragment;
        
        // 進棧動畫
        int enterAnim;
        int exitAnim;
        
        // 出棧動畫
        int popEnterAnim;
        int popExitAnim;

        Op() {
        }
        
        Op(int cmd, Fragment fragment) {
            this.cmd = cmd;
            this.fragment = fragment;
        }
    }
    
    // ...
}
複製程式碼

BackStackRecord 繼承 FragmentTransation 抽象類,同時實現 BackStackEntry 和 OpGenerator 介面。我們在程式裡要進行 add,remove,replace 等等操作時,用的是 FragmentTransation 型別,其實這個例項是 BackStackRecord 物件。

BackStackRecord 是用於儲存使用者一次提交的操作行為,一次提交併不是一種變化,而是一系列的變化,是一組 add、replace、remove 變化的集合。每一次的變化,即是一次操作,用 Op 類來表示。在 BackStackRecord 裡儲存了一個雙向連結串列 (mHead, mTail),用於儲存一組操作。Op 類中的 cmd 表示操作型別(如 add,replace,remove 等等)

例如:


    getSupportFragmentManager()
        .beginTransaction()
        .add(R.id.container, new MyFragment())
        .hide(R.id.container,fragment2)
        .replace(R.id.container,fragment3)
        .commit();
複製程式碼

最終通過 commit() 方法提交一些列操作。

BackStackRecord

BackStackRecord 實現了操作 fragment 的所有事務,每個方法內部都是由 doAddOp 實現的。

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

    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;
    }
        @Override
    public FragmentTransaction remove(Fragment fragment) {
        addOp(new Op(OP_REMOVE, fragment));

        return this;
    }

    @Override
    public FragmentTransaction hide(Fragment fragment) {
        addOp(new Op(OP_HIDE, fragment));

        return this;
    }

    @Override
    public FragmentTransaction show(Fragment fragment) {
        addOp(new Op(OP_SHOW, fragment));

        return this;
    }

    @Override
    public FragmentTransaction detach(Fragment fragment) {
        addOp(new Op(OP_DETACH, fragment));

        return this;
    }

    @Override
    public FragmentTransaction attach(Fragment fragment) {
        addOp(new Op(OP_ATTACH, fragment));

        return this;
    }

複製程式碼
 private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
 
    // ...
    // 將 manager 賦值給 fragment
    fragment.mFragmentManager = mManager;
    
    // 設定 containerViewId
    if (containerViewId != 0) {
      fragment.mContainerId = fragment.mFragmentId = containerViewId;
    }
    // ...
    // 將這個事務物件加到 ArrayList 中
    addOp(new Op(opcmd, fragment));
  }

複製程式碼

提交事務

常用的提交事務, 一種是將所有事物放入事務佇列,輪詢執行。另一種是立刻執行,從方法命名也可以看出來。看看它們內部是如何提交的。而立刻提交是不允許加入回退棧的。

    @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;
    }
    
     public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
        // 檢查狀態
        if (!allowStateLoss) {
            checkStateLoss();
        }
        synchronized (this) {
            if (mDestroyed || mHost == null) {
                throw new IllegalStateException("Activity has been destroyed");
            }
            if (mPendingActions == null) {
                mPendingActions = new ArrayList<>();
            }
            
            mPendingActions.add(action);
            scheduleCommit();
        }
    }
    
    // 將事務交通過 handler post 執行
      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 做的事:
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;
    }
複製程式碼
    
    // 這裡進行了優化和執行事務的操作,執行事務是由 executeOpsTogether 完成
    private void optimizeAndExecuteOps(ArrayList<BackStackRecord> records,
            ArrayList<Boolean> isRecordPop) {
       // ... 
        

        final int numRecords = records.size();
        int startIndex = 0;
        // 遍歷所有的事務
        for (int recordNum = 0; recordNum < numRecords; recordNum++) {
            // 標記優化
            final boolean canOptimize = records.get(recordNum).mAllowOptimization;
            if (!canOptimize) {
                // ..
                if (startIndex != recordNum) {
                    executeOpsTogether(records, isRecordPop, startIndex, recordNum);
                }
                
                executeOpsTogether(records, isRecordPop, recordNum, optimizeEnd);
                // ...
            }
        }
        if (startIndex != numRecords) {
            executeOpsTogether(records, isRecordPop, startIndex, numRecords);
        }
    }

    
    // 這裡發現執行事務由 executeOps 方法來執行的
   private void executeOpsTogether(ArrayList<BackStackRecord> records,
            ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
        final boolean allowOptimization = records.get(startIndex).mAllowOptimization;
        // ... 
       

       // ...
        executeOps(records, isRecordPop, startIndex, endIndex);

        // ...

        if (postponeIndex != startIndex && allowOptimization) {
            // need to run something now
            FragmentTransition.startTransitions(this, records, isRecordPop, startIndex,
                    postponeIndex, true);
            moveToState(mCurState, true);
        }

        // ..
        if (addToBackStack) {
            reportBackStackChanged();
        }
    }
    
    
複製程式碼
    // 最終判斷執行 executeOps 還是 executePopOps
   private static void executeOps(ArrayList<BackStackRecord> records,
            ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
        for (int i = startIndex; i < endIndex; i++) {
            final BackStackRecord record = records.get(i);
            final boolean isPop = isRecordPop.get(i);
            if (isPop) {
                record.bumpBackStackNesting(-1);
                // Only execute the add operations at the end of
                // all transactions.
                boolean moveToState = i == (endIndex - 1);
                record.executePopOps(moveToState);
            } else {
                record.bumpBackStackNesting(1);
                record.executeOps();
            }
        }
    }
複製程式碼

這裡通過 fragmentManager 來操作

void executeOps() {
        final int numOps = mOps.size();
        for (int opNum = 0; opNum < numOps; opNum++) {
            final Op op = mOps.get(opNum);
            final Fragment f = op.fragment;
            if (f != null) {
                f.setNextTransition(mTransition, mTransitionStyle);
            }
            switch (op.cmd) {
                case OP_ADD:
                    f.setNextAnim(op.enterAnim);
                    mManager.addFragment(f, false);
                    break;
                case OP_REMOVE:
                    f.setNextAnim(op.exitAnim);
                    mManager.removeFragment(f);
                    break;
                case OP_HIDE:
                    f.setNextAnim(op.exitAnim);
                    mManager.hideFragment(f);
                    break;
                // ...
                
            }
        }
        // ...
    }
複製程式碼

最後呼叫 movetToState()

 public void addFragment(Fragment fragment, boolean moveToStateNow) {
        if (mAdded == null) {
            mAdded = new ArrayList<Fragment>();
        }
        makeActive(fragment);
        if (!fragment.mDetached) {
            // ...
            mAdded.add(fragment);
            fragment.mAdded = true;
            fragment.mRemoving = false;
            if (fragment.mView == null) {
                fragment.mHiddenChanged = false;
            }
            if (fragment.mHasMenu && fragment.mMenuVisible) {
                mNeedMenuInvalidate = true;
            }
            if (moveToStateNow) {
                moveToState(fragment);
            }
        }
    }
複製程式碼

這一段的程式碼特別長,根據狀態呼叫對應的生命週期, 在新增的時候把 View 新增進父佈局。通過 View.GONE/VISIBLE 顯示隱藏 Fragment。

    void moveToState(Fragment f, int newState, int transit, int transitionStyle,
            boolean keepActive) {
    if (f.mState <= newState) {
            // ...
            switch (f.mState) {
                case Fragment.INITIALIZING:
                    // OnFragmentPreAttached
                    dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
                    // 呼叫 fragment 的 onAttach
                    f.onAttach(mHost.getContext());
                    
                    // 回撥宿主的 onAttachFragment
                    mHost.onAttachFragment(f);
                    
                    dispatchOnFragmentAttached(f,     mHost.getContext(), false);
                    // 執行 fragment 的 onCreate
                    f.performCreate(f.mSavedFragmentState);

                    dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);

                // ...
                case Fragment.CREATED:
                    f.mContainer = container;
                    // fragmenr 執行 onCreateView 建立 View
                    f.mView = f.performCreateView(f.getLayoutInflater(
                                    f.mSavedFragmentState), container, f.mSavedFragmentState);
                                    
                    if (container != null) {
                        // 加入父佈局
                        container.addView(f.mView);
                    }
                    // 設定 View 的 GONE VISIBLE 來控制 hide,show
                    if (f.mHidden) {
                        f.mView.setVisibility(View.GONE);
                    }
                    
                    // onViewCreated
                    f.onViewCreated(f.mView, f.mSavedFragmentState);
                    
                    // 回撥
                    dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,false);
                       
                    // onActivityCreated   
                    f.performActivityCreated(f.mSavedFragmentState);

                // ...
                case Fragment.ACTIVITY_CREATED:
                //...
                case Fragment.STOPPED:
                // ..
                    // onStart
                    f.performStart();

                    dispatchOnFragmentStarted(f, false);

                case Fragment.STARTED:
                    // ...
                    // onResume
                    f.performResume();
                    dispatchOnFragmentResumed(f, false);

            }
        } else if (f.mState > newState) {
            switch (f.mState) {
                case Fragment.RESUMED:
                    // onPause
                    f.performPause();
                    dispatchOnFragmentPaused(f, false);

                // ..
                case Fragment.STARTED:
                    // onStop
                    f.performStop();
                    dispatchOnFragmentStopped(f, false);
                // ...
                case Fragment.STOPPED:
                    f.performReallyStop();
                    // ...    
                case Fragment.ACTIVITY_CREATED:
                    // ..
                    // onDestroyView
                    f.performDestroyView();
                    dispatchOnFragmentViewDestroyed(f, false);

                case Fragment.CREATED:
                    // onDestory
                    f.performDestroy();
                    // onDetach
                    f.performDetach();


                // ...
            }
        }
    }

複製程式碼

總結

回到最初疑惑的 2 個問題。

  1. Activity 是如何與 Fragment 關聯,如何操作 fragment 的?

Activiy 通過 FragmentManager 得到事務的實現類 BackStackRecord,它將 Fragment 封裝成一個 Ops,提交給 FragmentManager 處理。如果是非同步提交,就通過 Handler 傳送 Runnable 任務,FragmentManager 拿到任務後,先處理 Ops 狀態,然後呼叫 moveToState() 方法根據狀態呼叫 Fragment 對應的生命週期方法,從而達到 Fragment 的新增、佈局的替換隱藏等。

  1. Fragment 的本質是一個 View 嗎?

本質上是一個對 View 的封裝,它持有 view, containerView, fragmentManager, childFragmentManager 等資訊。

參考

通過原始碼解析 Fragment 啟動過程

Fragment FragmentManager FragmentTransaction 深入理解

相關文章