简介
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));
}
复制代码
例子:
有如下状态图
当我们调用start()方法,进而会调用SmHandler#completeConstruction(),该方法首先会初始化2个状态栈
接着发送一个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的主要工作逻辑如下:
- 调用SmHandler#setupTempStateStackWithStatesToEnter方法找到目的状态与当前初始状态S5(mStateStack的栈顶元素)的公共祖先即P1。方法是先将目的状态S4入栈,然后根据S4往上回溯,如果节点未被激活则入栈,直到找到一个处于激活状态的节点,该节点即是目的状态与当前初始状态的公共祖先。
- 调用SmHandler#invokeExitMethods(commonStateInfo)方法,退出旧的状态,mStateStack依次出栈调用State.exit()方法,直到公共祖先P1
- 将mTempStateStack整合至mStateStack
- 调用SmHandler# invokeEnterMethods方法,从公共节点之上依次调用State.enter方法,直到栈顶