3、WifiController 状态机:状态机设计模式、WifiController 的 7 种状态、状态切换逻辑
好,我们接着聊 WifiController。上一章我们把 WifiStateMachine 的内部状态梳理了一遍,那 WifiController 又是什么?
简单说,WifiController 是 Wi-Fi 开关的总闸。它不关心你连上了哪个 AP、信号强不强,它只关心一件事:Wi-Fi 功能现在是开着的,还是关着的?
我个人习惯把 WifiController 比作「房子的总电闸」,而 WifiStateMachine 是「房间里各个电器的开关」。总电闸没合上,房间里灯再亮也没用。
3.1 状态机设计模式:为什么 Android 这么爱用?
你想想看,Wi-Fi 的开关状态切换,其实是一个典型的有限状态机问题。用户点一下开关,系统要判断当前在什么状态,然后决定下一步做什么。
用 if-else 写当然也行,但 Wi-Fi 服务涉及异步消息、超时、外部事件(比如飞行模式、热点开启),状态一多,if-else 就变成一团乱麻。
状态机设计模式的核心思想就三个:
- 状态:系统当前处于什么阶段
- 事件:发生了什么(用户操作、系统广播、超时)
- 转移:当前状态 + 事件 → 下一个状态
Android 的 StateMachine 框架把这三件事封装得很好。你只需要继承 State,重写 processMessage(),框架自动帮你做状态切换。
3.2 WifiController 的 7 种状态
WifiController 定义了 7 种状态,我按「从关到开」的顺序列出来:
| 状态名 | 含义 | 典型触发事件 |
|---|---|---|
ApStaDisabledState |
Wi-Fi 和热点都关闭 | 开机、用户关闭 Wi-Fi |
StaDisabledWithScanState |
Wi-Fi 关闭,但允许扫描 | 位置服务请求扫描 |
DeviceActiveState |
Wi-Fi 开启,正常工作 | 用户打开 Wi-Fi |
ConnectivityState |
已连接或正在连接 | 扫描到网络后自动连接 |
ScanOnlyState |
仅扫描,不连接 | 设置中开启「仅扫描」模式 |
SoftApState |
热点模式 | 用户开启热点 |
EcmState |
以太网共享模式 | USB 网络共享 |
嗯,这里要注意:这 7 种状态不是平级的。它们有父子层级关系。比如 DeviceActiveState 是父状态,ConnectivityState 和 ScanOnlyState 是它的子状态。
为什么要这么设计?因为父状态可以处理「公共事件」。比如飞行模式开启时,不管你在 ConnectivityState 还是 ScanOnlyState,父状态 DeviceActiveState 统一拦截处理,子状态不用重复写代码。
3.3 状态切换逻辑:一张图说清楚
我画了一张状态切换图,你看完就明白了:
3.4 核心切换逻辑源码解读
我们来看一段 WifiController 中 ApStaDisabledState 的处理逻辑:
class ApStaDisabledState extends State {
@Override
public boolean processMessage(Message msg) {
switch (msg.what) {
case WifiController.CMD_WIFI_TOGGLED:
// 用户打开了 Wi-Fi
transitionTo(mDeviceActiveState);
return HANDLED;
case WifiController.CMD_SCAN:
// 位置服务请求扫描
transitionTo(mStaDisabledWithScanState);
return HANDLED;
case WifiController.CMD_AP_START:
// 用户开启热点
transitionTo(mSoftApState);
return HANDLED;
default:
return NOT_HANDLED;
}
}
}
这段代码很直白。收到 CMD_WIFI_TOGGLED 就去 DeviceActiveState,收到 CMD_SCAN 就去 StaDisabledWithScanState。
但有个细节:为什么热点开启不经过 DeviceActiveState? 因为热点和 Wi-Fi 不能同时开(硬件限制)。所以从 ApStaDisabledState 直接跳到 SoftApState,跳过了 Wi-Fi 的初始化流程。
SoftApWithScanState。这让我深刻体会到:状态机的设计决定了系统的能力边界。
3.5 状态切换的「隐形规则」
除了显式的 transitionTo(),WifiController 还有几条隐形的切换规则:
- 飞行模式:不管当前在哪个状态,收到飞行模式广播,一律回到
ApStaDisabledState - Wi-Fi 开关冲突:如果当前在
SoftApState,用户打开 Wi-Fi,系统会先关闭热点,再进入DeviceActiveState - 超时保护:某些状态(如连接中)如果长时间没有进展,会回退到上一个稳定状态
这些规则在代码里分散在各个状态的处理逻辑中。我建议你阅读源码时,重点关注 processMessage() 中那些 NOT_HANDLED 的分支——它们往往会被父状态或默认状态拦截处理。
3.6 小结
WifiController 的状态机,说白了就是一套「Wi-Fi 开关的有限状态机」。7 种状态覆盖了 Wi-Fi 的所有工作模式,父子状态的设计减少了重复代码。
我个人觉得,理解 WifiController 的关键不在于记住每个状态的名字,而在于理解状态切换的触发条件和约束。比如「为什么热点和 Wi-Fi 不能共存」「为什么扫描状态可以独立存在」——这些问题的答案,都在状态机的设计里。
公众号:蓝海资料掘金营,微信deep3321