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

相关推荐
千里马学框架3 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台3 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone3 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc3 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo3 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077003 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼3 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone3 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen3 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone3 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui