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

相关推荐
2601_949833395 小时前
flutter_for_openharmony口腔护理app实战+预约管理实现
android·javascript·flutter
2603_949462108 小时前
Flutter for OpenHarmony社团管理App实战:预算管理实现
android·javascript·flutter
王泰虎9 小时前
安卓开发日记,因为JCenter 关闭导致加载不了三方库应该怎么办
android
2601_9495430113 小时前
Flutter for OpenHarmony垃圾分类指南App实战:主题配置实现
android·flutter
2601_9498333914 小时前
flutter_for_openharmony口腔护理app实战+知识实现
android·javascript·flutter
晚霞的不甘14 小时前
Flutter for OpenHarmony从基础到专业:深度解析新版番茄钟的倒计时优化
android·flutter·ui·正则表达式·前端框架·鸿蒙
鸟儿不吃草15 小时前
android的Retrofit请求https://192.168.43.73:8080/报错:Handshake failed
android·retrofit
Minilinux201815 小时前
Android音频系列(09)-AudioPolicyManager代码解析
android·音视频·apm·audiopolicy·音频策略
李子红了时15 小时前
【无标题】
android
Android系统攻城狮16 小时前
Android tinyalsa深度解析之pcm_close调用流程与实战(一百零四)
android·pcm·tinyalsa·音频进阶·音频性能实战·android hal