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() 的区别。

相关推荐
Kapaseker19 分钟前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95271 小时前
Andorid Google 登录接入文档
android
黄林晴3 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab15 小时前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿18 小时前
Android MediaPlayer 笔记
android
Jony_18 小时前
Android 启动优化方案
android
阿巴斯甜18 小时前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇18 小时前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android
_小马快跑_1 天前
Kotlin | 从SparseArray、ArrayMap的set操作符看类型检查的不同
android