Android StateMachine 分析
来源:互联网 发布:ipad房屋设计软件 编辑:程序博客网 时间:2024/05/20 06:22
State模式允许一个对象在期内部状态改变时改变其行为模式,State 模式是将对象的状态封装成一个对象,是在不同的状态下执行不同的操作。Android系统通过StateMachine 是State模式的一种应用,其实现的相当精妙。本文对StateMachine做个深入分析,介绍其实现机制。
首先通过一个例子来引入问题,假如我们有6个状态S1、S2、S3、S4、S5、S6。其中:1、每个状态对某些消息都要做不同的处理;2、S1是S2的父状态,S2是S3的父状态,S3是S4的父,S1是S5的父状态,S5是S6的父状态;3、初始状态是S4;4、在运行过程中,收到某个消息时状态机有S4转到S3。如下图:
图1:状态结构图
图1显示了个状态的关系,在解析Android StateMachine如何管理State之前,先介绍State。
State:
public class State implements IState { protected State() { } @Override public void enter() { } @Override public void exit() { } @Override public boolean processMessage(Message msg) { return false; } @Override public String getName() { String name = getClass().getName(); int lastDollar = name.lastIndexOf('$'); return name.substring(lastDollar + 1); }}State 作为状态基类,StateMachine 管理的state都需要从此继承下来。重写几个重要方法,enter表示进入该状态的调用,exit是退出该状态会调用,processMessage是当前状态下处理消息的函数。如果当前状态处理后返回false表明还需要父状态处理,如图1中示例,如果状态S4处理消息后返回false表明还需要其父状态S2处理,直到递归到根状态。通过这样的机制为设计状态机的各种状态提供了便利,对于一些公共消息可以放到公共状态上来处理,后面会介绍其实现的机制。
在Android Handler机制博文中介绍了Android线程处理消息的一种方式,在StateMachine中,核心也是采用了类似的机制来管理states。StateMachine通过一独立线程来完成三个功能
- 建立树型状态层次结构
- 状态机状态堆栈的建立并管理状态切换
- 分发消息
以上三个功能均有mSmHandler来完成,mSmHandler类继承于Handler,下面来分析其如何完成以上三个功能。
1. 建立树形结构层次
StateMachine 提供AddState方法来添加状态到状态机中,函数如下:
protected final void addState(State state, State parent) { mSmHandler.addState(state, parent); }这里其实调用的是mSmHandler的addState 方法,再网下跟踪
private final StateInfo addState(State state, State parent) { // 获取当前状态父状态信息 StateInfo parentStateInfo = null; if (parent != null) { parentStateInfo = mStateInfo.get(parent); if (parentStateInfo == null) { // 当父状态未添加进来时,递归添加进来. parentStateInfo = addState(parent, null); } } // 判断状态信息是否添加到树形结构中 StateInfo stateInfo = mStateInfo.get(state); if (stateInfo == null) { stateInfo = new StateInfo(); mStateInfo.put(state, stateInfo); } // Validate that we aren't adding the same state in two different hierarchies. if ((stateInfo.parentStateInfo != null) && (stateInfo.parentStateInfo != parentStateInfo)) { throw new RuntimeException("state already added"); } stateInfo.state = state; stateInfo.parentStateInfo = parentStateInfo; stateInfo.active = false; if (mDbg) Log.d(TAG, "addStateInternal: X stateInfo: " + stateInfo); return stateInfo; }
在StateMachine类中,StateInfo就是一个包装State的树节点,每一个状态对应一个状态信息StateInfo,通过HashMaps存储下来
private HashMap<State, StateInfo> mStateInfo =new HashMap<State, StateInfo>();因此图1所的示状态构成可以通过以下流程来实现:
addState(S1,null);addState(S2,S1);addState(S3,S2);addState(S4,S2);addState(S5,S1);addState(S6,S5);
2.1 状态机堆栈建立
StateMachine 通过两个结构来建立和切换状态堆栈, mStateStack[] 及 mTempStateStack[]。建立堆栈API如下:
private final void completeConstruction() { // 计算堆栈深度,状态个数 int maxDepth = 0; for (StateInfo si : mStateInfo.values()) { int depth = 0; for (StateInfo i = si; i != null; depth++) { i = i.parentStateInfo; } if (maxDepth < depth) { maxDepth = depth; } } // 建立两个栈 mStateStack = new StateInfo[maxDepth]; mTempStateStack = new StateInfo[maxDepth]; //根据初始状态构建父子关系栈 setupInitialStateStack(); // 激活对应状态,并调用State的entry方法表明进入当前状态 mIsConstructionCompleted = true; mMsg = obtainMessage(SM_INIT_CMD); invokeEnterMethods(0); //如果需要将做状态切换,在后面会介绍 performTransitions(); }在来分析setUpInitialStateStack()的实现。
private final void setupInitialStateStack() { // 根据初始状态建立临时栈,如本文开始提出的初始状态为S4,那么临时栈存储的状态为:S4->S2->S1 StateInfo curStateInfo = mStateInfo.get(mInitialState); for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) { mTempStateStack[mTempStateStackCount] = curStateInfo; curStateInfo = curStateInfo.parentStateInfo; } // Empty the StateStack mStateStackTopIndex = -1; // 将临时栈数据反过来存到state 栈中,即S1->S2->S4 来保持堆栈先进后出的机制 moveTempStateStackToStateStack(); }2.2 状态切换
SateMachine 提供的方法是:
protected final void transitionTo(IState destState) { mSmHandler.transitionTo(destState); }mSmHandler 提供的方法是:
private final void transitionTo(IState destState) { mDestState = (State) destState; }从中可以看出mSmHandler只是记录了一下切换到的目的状态,真正的切换实现在performTransitions 中。
private void performTransitions() { State destState = null; while (mDestState != null) { destState = mDestState; mDestState = null; //当前状态切换了存在于mStateStack中的State需要改变 //仍然按照链式父子关系来存储 //先从当前状态S4找到 最近的被激活的parent状态S4 //未被激活的全部保存起来(S3) 返回S3 StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState); invokeExitMethods(commonStateInfo); // 将临时栈的state修改到State栈中 int stateStackEnteringIndex = moveTempStateStackToStateStack(); invokeEnterMethods(stateStackEnteringIndex); } }mTempStateStack 原来的数据是: S4-S2-S1;mStateStack状态切换前是:S1-S2-S4 栈顶是2状态切换到S3后,mTempStateStack的数据是:S3-S2-S1;mStateStack状态是S1-S2-S3。
3. 消息分发
mSmHandler实际是一Handler对象,消息处理函数在handleMessage方法中。
public final void handleMessage(Message msg) { //处理当前消息到state中去处理 processMsg(msg); //消息处理完毕状态切换 更新mStateStack performTransitions();}
private final void processMsg(Message msg){ //派发消息到state中去处理 StateInfo curStateInfo = mStateStack[mStateStackTopIndex]; while (!curStateInfo.state.processMessage(msg)) { //当前状态mDestState 未处理该消息,交给其parent state处理 curStateInfo = curStateInfo.parentStateInfo; if (curStateInfo == null){ //此消息未被当前层次状态链处理 } }}
SateMachine 通过堆栈来管理State一是方便状态切换,二是实现消息的链式处理,功能强大。除此之外,SateMachine还提供处理完消息记录功能及延时消息处理功能,
在这里就不再介绍了。参考方法deferMessage,ProcessedMessages的实现。
- Android StateMachine分析
- Android StateMachine 分析
- Android蓝牙源码分析——StateMachine状态机
- Swift StateMachine源码分析
- StateMachine 源码流程分析
- android状态机机制StateMachine
- android状态机机制StateMachine
- android状态机statemachine详解
- Android StateMachine和AsyncChannel
- android状态机statemachine详解
- android状态机机制StateMachine
- Android StateMachine和AsyncChannel
- Android StateMachine和AsyncChannel
- android状态机机制StateMachine
- android状态机statemachine详解
- Android StateMachine和AsyncChannel
- Android StateMachine和AsyncChannel
- android状态机statemachine详解
- ubuntu下安装gvim以及插件
- 配置ssh公钥访问oschina
- UVM::sequence_item的定义
- 线性规划与网络流24题の7 试题库问题(二分图匹配)
- Linux初次使用
- Android StateMachine 分析
- 使用接插件需要注意的问题
- 40个容易上瘾的HTML5网页游戏,总有一款适合你
- 积累2014-08-27 16:50:35
- uva 11898 - Killer Problem(暴力)
- jquery的初步总结
- DSP6000的上电及供电
- TIM_G etCapture2(TIM2)计算周期
- 8086架构的CPU的内存访问机制以及内存对齐(memory alignment)