- Activity 是如何與 Fragment 關聯,如何操作 fragment 的?
- Fragment 的本質是一個 View 嗎?
前言
Activity 和 Fragment 密不可分, 分析 Fragment 必須去從 Activity 的生命週期著手去分析其中和 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
複製程式碼
Activity 通過 FragmentController
類管理 Fragment。FragmentController
的例項在成員變數中例項化,所以當 Activity
被例項化的時候,FragmentController
就被例項化了。
public class FragmentActivity {
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
// ...
}
複製程式碼
那麼 Activity
在哪裡被例項化的?
Activit 的例項化
例項 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
例項。
HostCallbacks
是 FragmentActivity
的內部類,是 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
呼叫的是第二個構造,將 mActivity
、mContext
賦值為 Activity
的例項,mHandler
賦值為 Activity
中的 mHandler
,mWindowAnimations
直接賦值 0。
這裡的 mHandler
也是在 Activty
被例項化的時候例項化,看程式碼是處理 Fragment
的 stop
和 resume
狀態的。具體怎麼處理的後面再看,這裡先了解傳入的 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 的初始化
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 被例項化的時候,FragmentController
、HostCallbacks
、FragmentManagerImpl
都會被例項化。然後再通過我們前面說到的 attach()
將他們關聯,讓 FragmentManagerImpl
例項持有 HostCallbacks
例項。
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
應該表示的是開始建立,還沒建立好。
事務操作
接著我們會在 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 個問題。
- Activity 是如何與 Fragment 關聯,如何操作 fragment 的?
Activiy 通過 FragmentManager 得到事務的實現類 BackStackRecord,它將 Fragment 封裝成一個 Ops,提交給 FragmentManager 處理。如果是非同步提交,就通過 Handler 傳送 Runnable 任務,FragmentManager 拿到任務後,先處理 Ops 狀態,然後呼叫 moveToState() 方法根據狀態呼叫 Fragment 對應的生命週期方法,從而達到 Fragment 的新增、佈局的替換隱藏等。
- Fragment 的本質是一個 View 嗎?
本質上是一個對 View 的封裝,它持有 view, containerView, fragmentManager, childFragmentManager 等資訊。