FragmentManager 监听 Activity 生命周期:提线木偶剧场的信号系统

12 阅读3分钟

想象 Android 系统是一个神奇的木偶剧场

  • 🏰 Activity 是舞台本身
  • 🎭 Fragment 是舞台上的提线木偶
  • 🎛️ FragmentManager 是中央控制台
  • 📡 LifecycleOwner 是舞台的信号发射塔

让我们揭开中央控制台如何监听舞台信号的神秘面纱!

📡 信号连接系统

java

// 舞台(Activity)启动时
public class MainActivity extends AppCompatActivity {
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // 秘密:控制台自动连接信号塔
        getSupportFragmentManager().attachController(
            new FragmentController(this), // 控制器
            new FragmentHostCallback<>(this), // 宿主回调
            this // 生命周期信号塔
        );
    }
}

// 控制台内部连接代码
void attachController(FragmentController controller, 
                     FragmentHostCallback host,
                     LifecycleOwner lifecycleOwner) {
    
    // 1. 绑定舞台信号塔
    mLifecycleOwner = lifecycleOwner;
    
    // 2. 注册生命周期监听器
    lifecycleOwner.getLifecycle().addObserver(new LifecycleObserver() {
        @State(Lifecycle.State.ON_CREATE)
        void onCreate() {
            dispatchStateChange(Fragment.CREATED);
        }
        
        @State(Lifecycle.State.ON_START)
        void onStart() {
            dispatchStateChange(Fragment.STARTED);
        }
        
        // ... 其他状态监听
    });
}

📶 信号传递机制

当舞台状态变化时:

java

// 信号塔核心(LifecycleRegistry)
public class ComponentActivity extends Activity implements LifecycleOwner {
    private LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);
    
    protected void onCreate(Bundle s) {
        super.onCreate(s);
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
    }
    
    protected void onStart() {
        super.onStart();
        lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
    }
    
    // ... 其他生命周期
}

控制台接收信号后的处理:

java

// FragmentManager 的状态分发
void dispatchStateChange(int nextState) {
    // 1. 更新控制台自身状态
    mCurState = nextState;
    
    // 2. 通知所有木偶更新状态
    for (Fragment fragment : mFragments) {
        moveFragmentToExpectedState(fragment);
    }
    
    // 3. 执行待处理操作
    execPendingActions();
}

🧩 状态同步流程图解

text

舞台状态变化 → 信号塔广播 → 控制台接收 → 更新木偶状态
(Activity)     (Lifecycle)   (FragmentManager)  (Fragment)

具体信号转换表:

舞台信号 (Activity)控制台接收事件木偶状态 (Fragment)
onCreate()ON_CREATECREATED
onStart()ON_STARTSTARTED
onResume()ON_RESUMERESUMED
onPause()ON_PAUSESTARTED
onStop()ON_STOPCREATED
onDestroy()ON_DESTROYINITIALIZING

⚙️ 木偶状态更新引擎

控制台如何精确更新每个木偶的状态:

java

void moveFragmentToExpectedState(Fragment f) {
    // 计算目标状态
    int targetState = Math.min(f.getMaxState(), mCurState);
    
    // 状态升级路径
    if (f.mState < targetState) {
        switch (f.mState) {
            case Fragment.INITIALIZING:
                if (targetState >= Fragment.ATTACHED) {
                    f.onAttach(f.mHost.getContext()); // 连接舞台
                }
            case Fragment.ATTACHED:
                if (targetState >= Fragment.CREATED) {
                    f.performCreate(f.mSavedFragmentState); // 创建核心
                }
            // ... 其他状态升级
        }
    }
    // 状态降级路径
    else if (f.mState > targetState) {
        switch (f.mState) {
            case Fragment.RESUMED:
                if (targetState < Fragment.RESUMED) {
                    f.performPause(); // 暂停表演
                }
            // ... 其他状态降级
        }
    }
}

🌪️ 处理特殊场景

场景1:舞台旋转重建

java

// 舞台保存状态时
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    
    // 控制台保存木偶状态
    FragmentManagerState fms = saveAllState();
    outState.putParcelable("android:support:fragments", fms);
}

// 重建舞台时
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    if (savedInstanceState != null) {
        // 控制台恢复木偶状态
        FragmentManagerState fms = savedInstanceState.getParcelable("android:support:fragments");
        getSupportFragmentManager().restoreSaveState(fms);
    }
}

场景2:后台返回前台

java

// 舞台从后台返回
protected void onStart() {
    super.onStart(); // 发送ON_START信号
    
    // 控制台内部:
    // 1. 检查需要恢复的Fragment
    // 2. 调用moveToState(Fragment.STARTED)
    // 3. 触发Fragment的onStart()
}

🔌 信号中断处理

当控制台失去信号连接时:

java

// 舞台销毁时
protected void onDestroy() {
    super.onDestroy();
    
    // 控制台断开连接
    getSupportFragmentManager().dispatchDestroy();
}

// 控制台内部
void dispatchDestroy() {
    // 1. 停止监听信号
    mLifecycleOwner.getLifecycle().removeObserver(this);
    
    // 2. 销毁所有木偶
    for (Fragment f : mFragments) {
        moveFragmentToExpectedState(f, Fragment.INITIALIZING);
        f.onDetach(); // 切断提线
    }
    
    // 3. 清理资源
    mFragments.clear();
}

💡 控制台监听技巧

  1. 精确状态匹配

java

// 检查当前舞台状态
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
    // 安全更新Fragment
}
  1. 避免信号干扰

kotlin

// 在正确时机提交事务
lifecycleScope.launch {
    // 等待舞台准备就绪
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        // 安全执行Fragment操作
        commitFragmentTransaction()
    }
}
  1. 处理信号丢失

java

public void onViewCreated(View view, Bundle s) {
    super.onViewCreated(view, s);
    
    // 检查舞台是否有效
    if (getActivity() == null || isRemoving()) {
        return; // 安全退出
    }
    // 正常初始化
}

🎯 监听系统全景图

text

 舞台 (Activity)
     │
     ▼
 信号发射塔 (LifecycleOwner)
     │
     ▼
 信号接收器 (LifecycleObserver)
     │
     ▼
 中央控制台 (FragmentManager)
     │
     ├─▶ 木偶A (Fragment)
     ├─▶ 木偶B (Fragment)
     └─▶ 木偶C (Fragment)

终极测验:当舞台进入后台(onStop)后立即旋转屏幕,控制台如何处理?

答案

  1. 首先收到 ON_STOP 信号,将木偶状态降级到 CREATED
  2. 收到配置变更信号,保存木偶状态到 Bundle
  3. 销毁当前舞台和信号连接
  4. 创建新舞台,重新连接信号
  5. 从 Bundle 恢复木偶状态
  6. 根据新舞台状态更新木偶

通过这套精密的信号监听系统,FragmentManager 实现了与 Activity 生命周期的完美同步,确保每个 Fragment 木偶都能在正确的时机表演正确的动作!