1. fragment 本質(zhì)
fragment 本質(zhì)上是 view 的容器和控制器,fragment 是 activity 的碎片散劫。
activity 是什么呢?activity 是四大組件之一,4大組件是 android 系統(tǒng)的組成部件,因?yàn)?LMK(Low Memery Killer)機(jī)制隧甚,4 大組件就是我們提供給用戶的功能的載體,4 大組件還是我們提供給用戶的功能的入口昼丑。Activity Service BroadcastReceiver ContentProvider呻逆,Activity 是帶用戶界面的這些功能的載體夸赫,Service 是不帶用戶界面的功能的載體菩帝。和 Service 比較,Activity 相當(dāng)于 MVC 中的 View茬腿。但我們把 Activity 剖析開來理解呼奢,Activity 承擔(dān)了 View 控件的容器和控制器功能。Activity 還承擔(dān)了 View 控件的數(shù)據(jù)的容器的功能切平。
fragment 除了不是系統(tǒng)組件外握础,擁有其他所有 Activity 的功能。fragment 的存在就是對(duì) activity 的功能進(jìn)行拆分悴品,降低 activity 的負(fù)擔(dān)禀综,減少 activity 中的代碼量简烘。
fragment 還有對(duì) fragment 中的 view 的狀態(tài)進(jìn)行保持的能力,需要保持的 view 必須設(shè)置 id定枷,否則不能保存 view 的狀態(tài)孤澎。
2. FragmentTransaction 操作
FragmentTransaction 的 add、remove欠窒、replace覆旭、hide、show 操作本質(zhì)上是對(duì) fragment 中的 view 樹進(jìn)行 add岖妄、remove型将、hide、show 操作
add: 是把 fragment 中的 view 樹添加到容器 viewgroup 中荐虐,相當(dāng)于 viewgroup.addview();
remove: 是把 fragment 中的 view 樹對(duì)象從容器 viewgroup 中移除七兜,相當(dāng)于 viewgroup.removeView();
replace: 是 add 操作和 remove 操作的合體,相當(dāng)于先 remove 掉 viewgroup 容器中所有的 fragment福扬,再添加新的
fragment 對(duì)象惊搏。
hide: 操作相當(dāng)于設(shè)置 fragment 對(duì)應(yīng)的 view 為 gone
show: 操作相當(dāng)于設(shè)置 fragment 對(duì)應(yīng)的 view 為 visible
3. FragmentTransaction 的 addToBackStack 功能
addToBackStack 是把該事務(wù)所有操作構(gòu)成的操作集合都添加到 FragmentManager 對(duì)象的后退任務(wù)棧中,作為任務(wù)棧中的一個(gè)元素忧换,當(dāng)我們按 back 鍵的時(shí)候進(jìn)行該操作集合構(gòu)成的元素進(jìn)行的逆向操作恬惯,一次彈出一個(gè)元素,主動(dòng)調(diào)用 FragmentManager.popBackStack 方法也可以進(jìn)行一個(gè)彈棧操作亚茬。
4. Fragment 操作原理
fragment 的 add 操作到底是怎么實(shí)現(xiàn)的酪耳?通過查看源碼,fragment 的 add 操作主要要做下面的事情:
- 通過 activity 獲取到 FragmentManager 對(duì)象刹缝,這里會(huì) new 一個(gè) FragmentManagerImpl 對(duì)象
- 通過 FragmentManager 開啟一個(gè)事務(wù)碗暗,這里會(huì) new 一個(gè) BackStackRecord 對(duì)象,一個(gè) BackStackRecord 也就是一個(gè)事務(wù)
- 通過 FragmentTransaction 執(zhí)行 add 操作梢夯,本質(zhì)上是 new 了一個(gè) Op 對(duì)象言疗,添加到了 BackStackRecord 內(nèi)部的隊(duì)列中(BackStackRecord 有一個(gè)隊(duì)列用來保存這次事務(wù)進(jìn)行的所有操作)
- 通過 FragmentTransaction 執(zhí)行 commit 方法,把 BackStackRecord 添加到 manager 的 Action 隊(duì)列中
- 主線程中處理 Action 中的 BackStackRecord颂砸,調(diào)用 BackStackRecord 的 run 方法
- BackStackRecord 的 run 方法處理 BackStackRecord 內(nèi)部的隊(duì)列中的 Op 對(duì)象噪奄,如果是 add 類型 Op,調(diào)用 Manager 的 addFragment
- 把 fragment 對(duì)象添加到 manager 的 mAdded 集合中人乓,修改 fragment 的狀態(tài)勤篮,執(zhí)行 fragment 的生命周期方法,把 fragment 中的 view 添加到 fragment 的容器 viewgroup 中
1. FragmentActivity.getSupportFragmentManager()
//FragmentActivity.java
final FragmentManagerImpl mFragments = new FragmentManagerImpl();
public FragmentManager getSupportFragmentManager() {
return mFragments;
}
FragmentActivity 的 fragmentManager 就是 FragmentManagerImpl 對(duì)象
2. FragmentManager.beginTransaction()
//FragmentManagerImpl.java
@Override
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
開始事務(wù)就是創(chuàng)建一個(gè) BackStackRecord 對(duì)象色罚,該對(duì)象用來表示一個(gè)fragment事務(wù)
3. FragmentTransaction.add()
//BackStackRecord.java
public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) {
doAddOp(containerViewId, fragment, tag, OP_ADD);
return this;
}
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
fragment.mFragmentManager = mManager;
if (tag != null) {
...
fragment.mTag = tag;
}
if (containerViewId != 0) {
...
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
//新建一個(gè) Op,添加到隊(duì)列中
Op op = new Op();
op.cmd = opcmd;
op.fragment = fragment;
addOp(op);
}
//添加 Op 到鏈表中
void addOp(Op op) {
if (mHead == null) {
mHead = mTail = op;
} else {
op.prev = mTail;
mTail.next = op;
mTail = op;
}
...
mNumOp++;
}
添加 Fragment 就是給 fragment 事務(wù)對(duì)象中Op對(duì)象鏈表中添加一個(gè)Op對(duì)象
4. FragmentTransaction.commit()
public int commit() {
return commitInternal(false);
}
int commitInternal(boolean allowStateLoss) {
...
//添加 transaction 到 manager 的隊(duì)列中
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
提交事務(wù)就是把事務(wù)對(duì)象添加到 FragmentManager 隊(duì)列中
5. FragmentManagerImpl.enqueueAction()
public void enqueueAction(Runnable action, boolean allowStateLoss) {
synchronized (this) {
...
if (mPendingActions == null) {
mPendingActions = new ArrayList<Runnable>();
}
mPendingActions.add(action);
if (mPendingActions.size() == 1) {
mActivity.mHandler.removeCallbacks(mExecCommit);
mActivity.mHandler.post(mExecCommit);
}
}
}
Runnable mExecCommit = new Runnable() {
@Override
public void run() {
execPendingActions();
}
/**
* Only call from main thread!
*/
public boolean execPendingActions() {
...
while (true) {
int numActions;
synchronized (this) {
...
numActions = mPendingActions.size();
if (mTmpActions == null || mTmpActions.length < numActions) {
mTmpActions = new Runnable[numActions];
}
mPendingActions.toArray(mTmpActions);
mPendingActions.clear();
mActivity.mHandler.removeCallbacks(mExecCommit);
}
mExecutingActions = true;
for (int i=0; i<numActions; i++) {
//執(zhí)行 pendding 中的 action.run碰缔,就是執(zhí)行事務(wù)
mTmpActions[i].run();
mTmpActions[i] = null;
}
...
}
...
return didSomething;
}
6. BackStackRecord.run()
public void run() {
...
bumpBackStackNesting(1);
Op op = mHead;
while (op != null) {
switch (op.cmd) {
case OP_ADD: {
Fragment f = op.fragment;
f.mNextAnim = op.enterAnim;
mManager.addFragment(f, false);
} break;
case OP_REPLACE: {
Fragment f = op.fragment;
if (mManager.mAdded != null) {
for (int i=0; i<mManager.mAdded.size(); i++) {
Fragment old = mManager.mAdded.get(i);
...
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;
}
op = op.next;
}
mManager.moveToState(mManager.mCurState, mTransition,
mTransitionStyle, true);
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
}
調(diào)用 FragmentManager 中的 add、remove戳护、show金抡、hide 等方法瀑焦,replace 方法是移除 mManager.mAdded 中的 fragment
7. FragmentManager.add()
public void addFragment(Fragment fragment, boolean moveToStateNow) {
if (mAdded == null) {
mAdded = new ArrayList<Fragment>();
}
if (DEBUG) Log.v(TAG, "add: " + fragment);
makeActive(fragment);
if (!fragment.mDetached) {
if (mAdded.contains(fragment)) {
throw new IllegalStateException("Fragment already added: " + fragment);
}
//添加到 mAddded 集合中
mAdded.add(fragment);
fragment.mAdded = true;
fragment.mRemoving = false;
if (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
if (moveToStateNow) {
moveToState(fragment);
}
}
}
moveToState(fragment) 方法會(huì)觸發(fā) fragment 的生命周期方法