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. 状态机堆栈的建立和状态切换

          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的实现。



      

0 0
原创粉丝点击