想象 Android 系统是一个巨大的木偶剧场,FragmentManager 就是剧场的中央控制台,它通过复杂的线缆系统精确控制着每个木偶(Fragment)的一举一动。让我们揭开控制台的魔法面纱!
🎚️ 控制台核心结构
java
// 中央控制台的核心代码(简化版)
public class FragmentManager {
// 所有木偶的登记册
private ArrayList<Fragment> mFragments = new ArrayList<>();
// 待执行操作队列
private ArrayList<OpGenerator> mPendingActions = new ArrayList<>();
// 历史记录卷轴(回退栈)
private ArrayList<BackStackRecord> mBackStack;
// 当前木偶状态机
private int mCurState = Fragment.INITIALIZING;
// 魔法方法:推动状态变化
void moveToState(Fragment f, int newState) {
// 根据状态执行木偶的生命周期方法
switch(newState) {
case Fragment.ATTACHED:
f.onAttach(); // "连接舞台电源!"
break;
case Fragment.CREATED:
f.onCreate(); // "激活核心芯片!"
break;
// ...其他状态
}
}
}
🕹️ 木偶操作流程
1. 添加新木偶(添加 Fragment)
java
// 剧场管理员(Activity)的指令
getSupportFragmentManager().beginTransaction()
.add(R.id.puppet_spot, new PuppetFragment(), "puppet1")
.commit();
// 控制台内部执行:
public FragmentTransaction add(int containerId, Fragment fragment, String tag) {
// 创建操作记录
Op op = new Op(OP_ADD, fragment);
op.mContainerId = containerId;
op.mTag = tag;
addOp(op); // 加入操作队列
return this;
}
2. 执行操作(commit 魔法)
java
// 当调用 commit() 时
public int commit() {
return commitInternal(true);
}
private int commitInternal(boolean allowStateLoss) {
// 将操作加入待执行队列
mPendingActions.add(this);
// 安排在主线程执行
mManager.enqueueAction(this, allowStateLoss);
return mIndex;
}
🧩 状态机引擎
控制台的核心是状态机引擎,它精确控制每个木偶的生命周期状态:
java
// 状态机推动方法
void moveToState(Fragment f, int newState) {
// 状态升级路径
if (f.mState < newState) {
switch (f.mState) {
case Fragment.INITIALIZING:
if (newState >= Fragment.ATTACHED) {
attachFragment(f); // 连接舞台
}
case Fragment.ATTACHED:
if (newState >= Fragment.CREATED) {
f.performCreate(f.mSavedFragmentState); // 创建核心
}
// ... 其他状态升级
}
}
// 状态降级路径(如返回按钮)
else if (f.mState > newState) {
switch (f.mState) {
case Fragment.RESUMED:
if (newState < Fragment.RESUMED) {
f.performPause(); // 暂停表演
}
case Fragment.STARTED:
if (newState < Fragment.STARTED) {
f.performStop(); // 停止表演
}
// ... 其他状态降级
}
}
}
📜 历史卷轴(回退栈)
当操作被添加到回退栈:
java
// 添加回退记录
transaction.addToBackStack("puppet_show");
// 控制台内部:
public FragmentTransaction addToBackStack(String name) {
mAddToBackStack = true;
mName = name;
return this;
}
当用户按下返回键:
java
// 处理返回键
public boolean popBackStackImmediate() {
// 从栈顶取出记录
BackStackRecord bsr = mBackStack.remove(mBackStack.size()-1);
// 执行反向操作
bsr.popFromBackStack(true);
return true;
}
⚡ 状态同步魔法
控制台如何确保所有木偶状态一致?
java
// 执行待处理操作
void execPendingActions() {
while (true) {
// 1. 合并所有待执行操作
generateOpsForPendingActions(mTmpRecords, mTmpIsPop);
// 2. 按优先级排序
Collections.sort(mTmpRecords, mExecCommit);
// 3. 依次执行操作
for (BackStackRecord record : mTmpRecords) {
record.executeOps();
}
// 4. 更新所有木偶状态
moveToState(mCurState, true);
}
}
🧠 木偶的保存与恢复
当剧场遭遇风暴(配置变更):
java
// 保存状态
public void saveAllState() {
// 保存所有木偶状态
ArrayList<FragmentState> fragments = new ArrayList<>();
for (Fragment f : mFragments) {
FragmentState fs = new FragmentState(f);
fragments.add(fs);
}
// 保存回退栈
BackStackState[] backStack = saveBackStack();
// 打包成Bundle
FragmentManagerState fms = new FragmentManagerState();
fms.mActive = fragments;
fms.mBackStack = backStack;
return fms;
}
// 恢复状态
public void restoreAllState(Parcelable state) {
FragmentManagerState fms = (FragmentManagerState)state;
// 重建木偶列表
for (FragmentState fs : fms.mActive) {
Fragment f = fs.instantiate(...);
mFragments.add(f);
}
// 重建回退栈...
}
🎯 控制流程图解
text
操作请求 (add/remove/replace)
↓
创建 BackStackRecord
↓
加入 mPendingActions 队列
↓
主线程 Handler 触发执行
↓
execPendingActions() 批量处理
↓
executeOps() 执行具体操作
↓
moveToState() 更新状态
↓
调用 Fragment 生命周期方法
↓
更新视图层级
💡 控制台使用秘籍
-
线程安全法则:
java
// 所有操作必须在主线程 void updateFragment() { if (Thread.currentThread() != Looper.getMainLooper().getThread()) { throw new IllegalStateException("必须在主线程操作木偶!"); } } -
批量操作优化:
kotlin
// 使用 beginTransaction().setReorderingAllowed(true) supportFragmentManager.commit { setReorderingAllowed(true) replace<FragmentA>(R.id.container) add<FragmentB>(R.id.sidebar) // 系统会智能合并操作 } -
查找木偶的正确方式:
java
// 通过 ID 查找 Fragment puppet = getSupportFragmentManager().findFragmentById(R.id.puppet_spot); // 通过标签查找(适用于无视图的 Fragment) Fragment puppet = getSupportFragmentManager().findFragmentByTag("audio_player"); -
安全操作检查:
java
// 在操作前检查控制台状态 if (!getSupportFragmentManager().isStateSaved()) { // 安全执行事务 } else { // 状态已保存,操作将丢失 }
终极测验:当同时提交 10 个 Fragment 事务时,控制台如何优化性能?
答案:
- 将操作合并到单个消息循环处理
- 使用
setReorderingAllowed(true)跳过中间状态- 批量执行视图更新,减少布局次数
- 智能合并兼容操作(如多个 add 合并)
通过这个提线木偶控制台的揭秘,我们看到 FragmentManager 就像剧场的神经中枢,通过状态机引擎、操作队列和回退栈三大核心机制,精确控制着每个 Fragment 的生命周期。掌握这套控制系统的运作原理,你就能成为 Android 界面开发的王牌木偶师!