StateMachine使用及源码解读

简介

StateMachine 类位于 Android 源码中的,路径是frameworks/base/core/java/com/android/internal/util/StateMachine.java,从路径名可以看出,这是一个工具类,该类对状态机进行了封装,方便使用。

使用的时候只需要将StateMachine、State、IState拷贝到工程中即可。

使用

实现自己的状态只需要继承State类,实现processMessage方法即可

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);
  }
}
复制代码

创建自己的MyStateMachine类,继承自StateMachine。初始化自定义状态,将状态add进去,调用setInitialState和start即可。

public class MyStateMachine extends StateMachine{
      private BaseState mBaseState = new BaseState();
      private AState mAState = new AState();
      private BState mBState = new BState();
      private CState mCState = new CState();
      
      public NewStateMachine(String name) {
        super(name);
        addState(mAState, mBaseState);
        addState(mBState, mAState);
        addState(mCState, mBaseState);
        setInitialState(mBaseState);
        start();
      }
}
复制代码

源码解读

StateMachine构造方法

// 重写SmHandler的handleMessage方法
private SmHandler mSmHandler;
// 内部其实是一个HandlerThread
private HandlerThread mSmThread;

protected StateMachine(String name) {
    mSmThread = new HandlerThread(name);
    mSmThread.start();
    Looper looper = mSmThread.getLooper();
    initStateMachine(name, looper);
}

private void initStateMachine(String name, Looper looper) {
    mName = name;
    mSmHandler = new SmHandler(looper, this);
}
复制代码

SmHandler

private static class SmHandler extends Handler{
    // 管理当前活跃的状态栈
    private StateInfo mStateStack[];
    // Halting状态
    private HaltingState mHaltingState = new HaltingState();
    // Quiting状态
    private QuittingState mQuittingState = new QuittingState();
    
    // map,存储State和StateInfo的对应表
    private HashMap<State, StateInfo> mStateInfo = new HashMap<State, StateInfo>();
    // 初始状态
    private State mInitialState;
    // 目标状态
    private State mDestState;
    
    private SmHandler(Looper looper, StateMachine sm) {
      super(looper);
      mSm = sm;
      // 默认将HaltingState和QuittingState加入状态机
      addState(mHaltingState, null);
      addState(mQuittingState, null);
    }
}
复制代码

QuittingState

/**
 * State entered when a valid quit message is handled.
 */
private class QuittingState extends State {
  @Override
  public boolean processMessage(Message msg) {
    // 所有消息都不作处理
    return NOT_HANDLED;
  }
}
复制代码

HaltingState

/**
 * State entered when transitionToHaltingState is called.
 */
private class HaltingState extends State {
  @Override
  public boolean processMessage(Message msg) {
    // 和quitting的不同在于,可以处理消息,所有的消息都调用haltedProcessMessage
    mSm.haltedProcessMessage(msg);
    return true;
  }
}
复制代码

StateMachine#start

public void start() {
    // mSmHandler有可能为空,如果调用了quit,会被置空。如果调用了quit,statemachine的很多资源会被释放,调用start无法再次开启
    if (mSmHandler == null) return;
    // 初始化一些参数
    mSmHandler.completeConstruction();
}
  
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;
    }
  }
  // 根据深度来初始化StateStack和TempStateStack
  mStateStack = new StateInfo[maxDepth];
  mTempStateStack = new StateInfo[maxDepth];
  setupInitialStateStack();
  // 发送SM_INIT_CMD message,异步调用enter方法 
  sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj));
}
复制代码

SmHandler#setupInitialStateStack

// 收到SM_INIT_CMD消息后,转移到初始状态
private final void setupInitialStateStack() {
  StateInfo curStateInfo = mStateInfo.get(mInitialState);
  // 将初始状态及其所有父状态加入tempStack
  for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) {
    mTempStateStack[mTempStateStackCount] = curStateInfo;
    curStateInfo = curStateInfo.parentStateInfo;
  }
  // 清空StateStack
  mStateStackTopIndex = -1;
  // 将tempStateStack移动到StateStack
  moveTempStateStackToStateStack();
}
复制代码

SmHandler#addState

private final StateInfo addState(State state, State parent) {
  StateInfo parentStateInfo = null;
  if (parent != null) {
    parentStateInfo = mStateInfo.get(parent);
    if (parentStateInfo == null) {
      // 如果parent未添加,手动添加
      parentStateInfo = addState(parent, null);
    }
  }
  StateInfo stateInfo = mStateInfo.get(state);
  if (stateInfo == null) {
    // 创建StateInfo,添加到map中
    stateInfo = new StateInfo();
    mStateInfo.put(state, stateInfo);
  }
  // 重复指定不一样的parent,抛异常
  if ((stateInfo.parentStateInfo != null) &&
      (stateInfo.parentStateInfo != parentStateInfo)) {
    throw new RuntimeException("state already added");
  }
  // stateInfo保存了当前状态、父状态、是否active
  stateInfo.state = state;
  stateInfo.parentStateInfo = parentStateInfo;
  // 调用enter后,active为true,exit后,active为false
  stateInfo.active = false;
  return stateInfo;
}
复制代码

SmHandler#handleMessage

@Override
public final void handleMessage(Message msg) {
  mMsg = msg;
  if (mIsConstructionCompleted) {
    // 已经初始化完之后的常规路径
    processMsg(msg);
  } else if (!mIsConstructionCompleted &&
      (mMsg.what == SM_INIT_CMD) && (mMsg.obj == mSmHandlerObj)) {
    // 未初始化完的路径,调用enter
    mIsConstructionCompleted = true;
    invokeEnterMethods(0);
  } else {
    throw new RuntimeException("StateMachine.handleMessage: " +
        "The start method not called, received msg: " + msg);
  }
  // 执行transitions
  performTransitions();
}
复制代码

SmHandler#processMsg

private final void processMsg(Message msg) {
  StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
  if (isQuit(msg)) {
    // 如果是退出msg,转移到退出状态
    transitionTo(mQuittingState);
  } else {
    // 循环遍历父状态,看是否能处理
    while (!curStateInfo.state.processMessage(msg)) {
      curStateInfo = curStateInfo.parentStateInfo;
      if (curStateInfo == null) {
        // 如果没有状态可以处理,调用此处
        mSm.unhandledMessage(msg);
        break;
      }
    }
  }
}
复制代码

SmHandler#transitionTo

private final void transitionTo(IState destState) {
  // 只改变mDestState,具体的执行在performTransitions中
  mDestState = (State) destState;
}
复制代码

SmHandler#performTransitions

private void performTransitions() {
  State destState = null;
  while (mDestState != null) {
    destState = mDestState;
    mDestState = null;
    // 找到目标状态非active的父状态,将链路中父状态放入tempStack中。返回目标状态与当前状态的公共祖先
    StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
    // 将stateStack中,公共祖先之前的状态出栈并调用exit
    invokeExitMethods(commonStateInfo);
    // 将tempStack中的状态入栈到StateStack
    int stateStackEnteringIndex = moveTempStateStackToStateStack();
    // 调用新入栈的state的enter回调
    invokeEnterMethods(stateStackEnteringIndex);
    // 将defer message移动到消息队列最前面
    // defer message的意思是,将消息保存在列表中,状态转移后将消息放置到队列最前面,优先被处理
    moveDeferredMessageAtFrontOfQueue();
  }
  // 处理quiting和Haling状态
  if (destState != null) {
    if (destState == mQuittingState) {
      mSm.onQuitting();
      cleanupAfterQuitting();
    } else if (destState == mHaltingState) {
      haltedProcessMessage(msg);
      mSm.onHalting();
    }
  }
}
复制代码

StateMachine#quit

protected final void quit() {
    // mSmHandler can be null if the state machine is already stopped.
    if (mSmHandler == null) return;
    mSmHandler.quit();
}
  
private final void quit() {
    // 会继续处理队列中的message
    sendMessage(obtainMessage(SM_QUIT_CMD, mSmHandlerObj));
}

private final void quitNow() {
     // 不会继续处理队列中的message
     sendMessageAtFrontOfQueue(obtainMessage(SM_QUIT_CMD, mSmHandhttp://note.youdao.com/s/GbM9ADTZlerObj));
}
复制代码

例子:
有如下状态图

image.png

当我们调用start()方法,进而会调用SmHandler#completeConstruction(),该方法首先会初始化2个状态栈

image.png

接着发送一个SM_INIT_CMD消息,当SmHandler#handleMessage(),处理这个初始化消息时,会调用SmHandler#invokeEnterMethods(0),依次从mStateStack的栈底(因为传入参数为0)到栈顶调用对应State.enter()方法,即enter方法的调用顺序为P0->P1->S2->S5,并将State.active设置为true,表示已经激活。

假设我们调用StateMachine#transitionTo(S4),设置S4为目的状态,performTransitions的主要工作逻辑如下:

  1. 调用SmHandler#setupTempStateStackWithStatesToEnter方法找到目的状态与当前初始状态S5(mStateStack的栈顶元素)的公共祖先即P1。方法是先将目的状态S4入栈,然后根据S4往上回溯,如果节点未被激活则入栈,直到找到一个处于激活状态的节点,该节点即是目的状态与当前初始状态的公共祖先。

image.png

  1. 调用SmHandler#invokeExitMethods(commonStateInfo)方法,退出旧的状态,mStateStack依次出栈调用State.exit()方法,直到公共祖先P1

image.png

  1. 将mTempStateStack整合至mStateStack

image.png

  1. 调用SmHandler# invokeEnterMethods方法,从公共节点之上依次调用State.enter方法,直到栈顶
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享