StateMachine

概念

Android 中层次状态机的实现。

普通的状态机在状态机数量太多时不好维护,层次状态机会对状态机进行分类 ------ 也可以理解为按树型对状态机进行管理。当有事件需要处理时,事件会由上至下一层层下发,结构更清晰。

StateMachine 由事件与状态两部分构成:状态以树的形式进行管理,事件会在树上进行分发。

使用

  1. 通过 addState() 添加不同状态,同时指定状态的父状态
  2. 使用 setInitialState() 设置状态机所处的初始状态
  3. 使用 start() 启动状态机
  4. 通过 sendMessage() 向状态机发送事件
  5. 每一个状态机通过 processMsg() 处理状态,当状态机进入/退出时,会调用 enter/exit

原理

属性

  • mStateInfo:存储所有状态的封装类 StateInfo。StateInfo 除了封装状态外,还记录状态的父状态,是否处于激活态

  • mTempStateStack:记录当前状态至根状态的路径。它是顺序存储:当前状态在第 0 号位,根状态在最后

  • mStateStack:与 mTempStateStack 作用类似,只不过它们顺序相反:根状态在第 0 号位,当前状态在最后。操作逻辑是先通过当前状态的 parent 属性往上遍历(遍历结果存储至 mTempStateStack 中,从下标为 0 开始存储),待遍历结束后再反向遍历 mTempStateStack 将结果存储至 mStateStack 中

start

StateMachine 内部所有操作逻辑都会转移至一个 HandlerThread 中。调用内部类(HandlerThread 的子类) 的 completeConstruction(),主要逻辑如下

setupInitialStateStack() 与 moveTempStateStackToStateStack() 的主要作用就是填充 mStateStack ------ 记录从根状态至当前状态的路径

sendMsg(SM_INIT_CMD) 会触发 invokeEnterMethods(),该方法才会执行真正的初始化逻辑:该方法就是遍历 mStateStack,然后调用每一个 State::enter() 方法

状态流转

StateMachine 的状态流转核心逻辑:当前 State 收到 msg 后,根据 msg 自己调用 transitionTo() 进行状态切换,而不是由统一状态管理类进行切换。示例如下:

java 复制代码
// 在 Msg 处理中调用 transitionTo() 进行状态切换
// 即由 State 根据 msg 自己作状态切换,而不是由统一的管理类进行切换
case(CMD_3):
    deferMessage(message);
    transitionTo(mP2);
    retVal = HANDLED;

因此,状态切换其实就是向 StateMachine 发一个 msg,核心逻辑在 handleMessage() 中,代码分两步:

第一步:从当前 State 往上遍历,依次调用每一个 State::processMessage() 方法,直到某一个 State::processMessage() 返回 true,该 State 即为能处理 msg 的 State。如果需要进行状态切换,此 State 就需要调用 transitionTo() 进行处理。

第二步:状态切换,即将状态切换至 transitionTo 指定的目标状态,主要逻辑在 performTransitions() 中

  • 根据 destState 填充 mTempStateStack: 存储 destState 至某一个祖先节点的路径。祖先节点是 destState 与 currentState 的最近的公共节点。StateMachine 以树结构管理所有 State,所以两个节点必然存在公共祖先节点,公共祖先节点及以上节点已经执行过 enter() 方法,在状态切换时不能再调用 enter()
  • 对公共祖先节点以下的节点执行 exit() 方法,直到当前节点
  • 从公共祖先节点(不含)至 destState 执行 enter() 方法
  • 处理 deferMessage() 消息。在状态切换过程中除了调用 transitionTo() 进行状态切换外,还可以通过 sendMessage/deferMessage() 给目标状态传递消息

状态切换是由某个 msg 触发的,因此状态切换的所有逻辑都运行在该 msg 对应的 handleMessage() 中。Message 又是通过 queue 进行管理,所以状态切换完后 queue 中的 message 都由新状态进行处理。

而 deferMessage() 会将 Msg 插入到 queue 队头,新状态会先处理 deferMessage() 发送的消息,然后再处理 sendMessage() 发送的消息。此即 deferMessage() 与 sendMessage() 的区别。

相关推荐
维克兜率天4 分钟前
【维克】统计套利建模:从因子到信号的完整流程
android·开发语言·python·算法·kotlin
hunterandroid15 分钟前
Room 数据库迁移与多表关联查询实战
android
吐了啊取名字太难26 分钟前
Android 相机 USB 连接别写在 Activity 里:锁屏、切页和后台传输怎么设计?
android·数码相机
hunterandroid1 小时前
Android ViewModel + LiveData 工程实践:配置变更、一次性事件与状态恢复
android
2501_915921432 小时前
iOS应用从开发到上架App Store的完整步骤详解
android·ios·小程序·https·uni-app·iphone·webview
HackTwoHub2 小时前
免 Root 安卓渗透工具 Stryker|把 Kali 装进手机!随身无线渗透工作站,内置 Nmap/Nuclei/Metasploit 全套武器库
android·linux·运维·人工智能·web安全·macos·智能手机
朱涛的自习室12 小时前
70 美金的 Beyond Compare,我让 Gemini 4 和 DeepSeek 造个开源免费版(Day 2)
android·前端·人工智能
.Bryce.17 小时前
在智能体中使用A2A工具:让大模型自己决定“该找谁帮忙“
android·java·服务器·redis·后端·agent·a2a
方舟小孩18 小时前
开源办公软件海豹办公 1.9.15 实战 从模板异常到 Android WebView 资源回归
android