对StateMachine中例子进行逐步分析
其状态切换逻辑图如下:
mP1 mP2
/ \
mS2 mS1 <-InitState
mP1
/ \
s1 s2
/ \
s3 s4 <- startstate
/
s5 <- destate
// 从目标节点 s5 向上查找,找到s1是和s4 时共同父节点。
// 则从s4开始向上执行exit()方法。再从s3开始到s5 执行enter()方法。
class Hsm1 extends StateMachine {
public static final int CMD_1 = 1;
public static final int CMD_2 = 2;
public static final int CMD_3 = 3;
public static final int CMD_4 = 4;
public static final int CMD_5 = 5;
public static Hsm1 makeHsm1() {
log("makeHsm1 E");
Hsm1 sm = new Hsm1("hsm1");
sm.start();
log("makeHsm1 X");
return sm;
}
Hsm1(String name) {
super(name);
log("ctor E");
// Add states, use indentation to show hierarchy
addState(mP1);
addState(mS1, mP1);
addState(mS2, mP1);
addState(mP2);
// Set the initial state
setInitialState(mS1);
log("ctor X");
}
class P1 extends State {
@Override
public void enter() {
log("mP1.enter");
}
@Override
public boolean processMessage(Message message) {
boolean retVal;
log("mP1.processMessage what=" + message.what);
switch(message.what) {
case CMD_2:
// CMD_2 will arrive in mS2 before CMD_3
sendMessage(obtainMessage(CMD_3));
deferMessage(message);
transitionTo(mS2);
retVal = HANDLED;
break;
default:
// Any message we don't understand in this state invokes unhandledMessage
retVal = NOT_HANDLED;
break;
}
return retVal;
}
@Overrid
public void exit() {
log("mP1.exit");
}
}
class S1 extends State {
@Override
public void enter() {
log("mS1.enter");
}
@Override
public boolean processMessage(Message message) {
log("S1.processMessage what=" + message.what);
if (message.what == CMD_1) {
// Transition to ourself to show that enter/exit is called
transitionTo(mS1);
return HANDLED;
} else {
// Let parent process all other messages
return NOT_HANDLED;
}
}
@Override
public void exit() {
log("mS1.exit");
}
}
class S2 extends State {
@Override
public void enter() {
log("mS2.enter");
}
@Override
public boolean processMessage(Message message) {
boolean retVal;
log("mS2.processMessage what=" + message.what);
switch(message.what) {
case(CMD_2):
sendMessage(obtainMessage(CMD_4));
retVal = HANDLED;
break;
case(CMD_3):
deferMessage(message);
transitionTo(mP2);
retVal = HANDLED;
break;
default:
retVal = NOT_HANDLED;
break;
}
return retVal;
}
@Override
public void exit() {
log("mS2.exit");
}
}
class P2 extends State {
@Override
public void enter() {
log("mP2.enter");
sendMessage(obtainMessage(CMD_5));
}
@Override
public boolean processMessage(Message message) {
log("P2.processMessage what=" + message.what);
switch(message.what) {
case(CMD_3):
break;
case(CMD_4):
break;
case(CMD_5):
transitionToHaltingState();
break;
}
return HANDLED;
}
@Override
public void exit() {
log("mP2.exit");
}
}
@Override
void onHalting() {
log("halting");
synchronized (this) {
this.notifyAll();
}
}
P1 mP1 = new P1();
S1 mS1 = new S1();
S2 mS2 = new S2();
P2 mP2 = new P2();
}
想要使用状态机分三步,
1 继承StateMachine。2 添加状态。3 启动状态机。
class Hsm1 extends StateMachine {
public static Hsm1 makeHsm1() {
log("makeHsm1 E");
Hsm1 sm = new Hsm1("hsm1");
sm.start();
log("makeHsm1 X");
return sm;
}
Hsm1(String name) {
super(name);
log("ctor E");
// Add states, use indentation to show hierarchy
addState(mP1);
addState(mS1, mP1);
addState(mS2, mP1);
addState(mP2);
// Set the initial state
setInitialState(mS1);
log("ctor X");
}
...
}
public final void addState(State state) {
mSmHandler.addState(state, null);
}
private final StateInfo addState(State state, State parent) {
...
StateInfo parentStateInfo = null;
if (parent != null) {
parentStateInfo = mStateInfo.get(parent);
if (parentStateInfo == null) {
// Recursively add our parent as it's not been added yet.
parentStateInfo = addState(parent, null);
}
}
StateInfo stateInfo = mStateInfo.get(state);
if (stateInfo == null) {
stateInfo = new StateInfo();
mStateInfo.put(state, stateInfo);
}
...
stateInfo.state = state;
stateInfo.parentStateInfo = parentStateInfo;
stateInfo.active = false;
if (mDbg) mSm.log("addStateInternal: X stateInfo: " + stateInfo);
return stateInfo;
}
添加节点的时候,需要同时传入父节点。当没有父节点的时候,不执行递推查询。生成StateInfo和State进行映射。其实StateInfo就是一个链表。parentStateInfo是指向父节点的,active表明当前的节点是否被激活。
结合调用段的代码进行分析,
//没有传入父节点,则mP1就是根节点,并将其加入mStateInfo Map中并进行映射
//其StateInfo中的parentStateInfo为null,当前的节点并灭有被激活。
addState(mP1);
//传入mP1作为父节点,则从mStateInfo中取出的mP1的StateInfo
//mStateInfo没有mS1的StateInfo信息,初始其StateInfo将其加入mStateInfo
//其StateInfo中的parentStateInfo指向mP1,当前节点没有被激活
addState(mS1, mP1);
//同mS1 添加的分析步骤
addState(mS2, mP1);
//同mP1 添加的分析步骤
addState(mP2);
//设置初始化的节点指向mS1,其后的代码就是简单的赋值
setInitialState(mS1);
再所有的State添加完毕后,就需要启动状态机
public static Hsm1 makeHsm1() {
log("makeHsm1 E");
Hsm1 sm = new Hsm1("hsm1");
sm.start();
log("makeHsm1 X");
return sm;
}
//StateMachine.java
private final void completeConstruction() {
if (mDbg) mSm.log("completeConstruction: E");
/**
* Determine the maximum depth of the state hierarchy
* so we can allocate the state stacks.
*/
//查找最深的那个分支。换句话理解就是测量这颗树一共有多少度。
//然后会根据maxDepth 创建数组。做成类似于栈结构
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;
}
}
if (mDbg) mSm.log("completeConstruction: maxDepth=" + maxDepth);
//根据maxDepth创建数组,是保证能装下从根节点到子节点中所有的路径
mStateStack = new StateInfo[maxDepth];
mTempStateStack = new StateInfo[maxDepth];
//初始化State,做两步。1 从初始节点向上找到根节点。并将其放置在mTempStateStack
//2 将mTempStateStack倒序拷贝到mStateStack
setupInitialStateStack();
/** Sending SM_INIT_CMD message to invoke enter methods asynchronously */
sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj));
if (mDbg) mSm.log("completeConstruction: X");
}
//--- from completeConstruction()
private final void setupInitialStateStack() {
if (mDbg) {
mSm.log("setupInitialStateStack: E mInitialState=" + mInitialState.getName());
}
//拿到初始节点,(StateInfo是一个指向根节点的单向链表, curStateInfo就像是一个指针)
StateInfo curStateInfo = mStateInfo.get(mInitialState);
//当前的链表指向初始节点,然后向上一直到根节点。
//(mS1->mP1)因为根节点的parenStateInfo是null。
// mS1 curStateInfo != null mTempStateStackCount = 0;
// mP1 curStateInfo.parentStateInfo != null mTempStateStackCount = 1;
// null mP1.parentStateInfo == null mTempStateStackCount = 2;
for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) {
mTempStateStack[mTempStateStackCount] = curStateInfo;
curStateInfo = curStateInfo.parentStateInfo;
}
// Empty the StateStack
//记住此处将mStateStackTopIndex赋值为-1,因为后续的改变State也会用到此state
mStateStackTopIndex = -1;
//当前的mTempStateStack的顺序是 [mS1, mP1] 我们希望拿到顺序是[mP1, mS1]
moveTempStateStackToStateStack();
}
//--- from setupInitialStateStack()
private final int moveTempStateStackToStateStack() {
// startingIndex为0
int startingIndex = mStateStackTopIndex + 1;
// mTempStateStackCount = 2, i = 1;
int i = mTempStateStackCount - 1;
// j = 0;
int j = startingIndex;
while (i >= 0) { // i=1 ===> i=0 ===> i=-1(terminal)
if (mDbg) mSm.log("moveTempStackToStateStack: i=" + i + ",j=" + j);
mStateStack[j] = mTempStateStack[i];
j += 1;
i -= 1;
}
// j = 2, mStateStackTopIndex = 1;
mStateStackTopIndex = j - 1;
if (mDbg) {
mSm.log("moveTempStackToStateStack: X mStateStackTop=" + mStateStackTopIndex
+ ",startingIndex=" + startingIndex + ",Top="
+ mStateStack[mStateStackTopIndex].state.getName());
}
//起始还是为0
//为什么要返回这个了?是为了后面的在改变状态的是,从共同节点作为起点。
return startingIndex;
}
//--- from sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj));
// mSmHandlerObj是为了区分是状态机内部的消息,不是由外部进行驱动的。
// 且状态机的启动只能由内部启动
@Override
public final void handleMessage(Message msg) {
if (!mHasQuit) {
if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
mSm.onPreHandleMessage(msg);
}
if (mDbg) mSm.log("handleMessage: E msg.what=" + msg.what);
/** Save the current message */
mMsg = msg;
/** State that processed the message */
State msgProcessedState = null;
if (mIsConstructionCompleted || (mMsg.what == SM_QUIT_CMD)) {
/** Normal path */
msgProcessedState = processMsg(msg);
} else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)
&& (mMsg.obj == mSmHandlerObj)) {
/** Initial one time path. */
mIsConstructionCompleted = true;
invokeEnterMethods(0);
} else {
throw new RuntimeException("StateMachine.handleMessage: "
+ "The start method not called, received msg: " + msg);
}
performTransitions(msgProcessedState, msg);
// We need to check if mSm == null here as we could be quitting.
if (mDbg && mSm != null) mSm.log("handleMessage: X");
if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
mSm.onPostHandleMessage(msg);
}
}
}
//--- from handleMessage()
private final void invokeEnterMethods(int stateStackEnteringIndex) {
//此处mStateStackTopIndex = 1. 是在moveTempStateStackToStateStack方法中算出来的。
//stateStackEnteringIndex = 0; 此处就是从根节点向下进行初始化 [mP1, mS1]
//在调用state的enter()方法, 并将mStateInfo.active 置为 true
for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
if (stateStackEnteringIndex == mStateStackTopIndex) {
// Last enter state for transition
mTransitionInProgress = false;
}
if (mDbg) mSm.log("invokeEnterMethods: " + mStateStack[i].state.getName());
mStateStack[i].state.enter();
mStateStack[i].active = true;
}
mTransitionInProgress = false; // ensure flag set to false if no methods called
}
//--- from handleMessage()
//此方法是主要的处理方法
private void performTransitions(State msgProcessedState, Message msg) {
/**
* If transitionTo has been called, exit and then enter
* the appropriate states. We loop on this to allow
* enter and exit methods to use transitionTo.
*/
//orgState就是初始化节点
State orgState = mStateStack[mStateStackTopIndex].state;
...
// 当前mDestState为null, 此mDestState为状态迁移的
State destState = mDestState;
if (destState != null) {
/**
* Process the transitions including transitions in the enter/exit methods
*/
while (true) {
if (mDbg) mSm.log("handleMessage: new destination call exit/enter");
/**
* Determine the states to exit and enter and return the
* common ancestor state of the enter/exit states. Then
* invoke the exit methods then the enter methods.
*/
StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
// flag is cleared in invokeEnterMethods before entering the target state
mTransitionInProgress = true;
invokeExitMethods(commonStateInfo);
int stateStackEnteringIndex = moveTempStateStackToStateStack();
invokeEnterMethods(stateStackEnteringIndex);
/**
* Since we have transitioned to a new state we need to have
* any deferred messages moved to the front of the message queue
* so they will be processed before any other messages in the
* message queue.
*/
moveDeferredMessageAtFrontOfQueue();
if (destState != mDestState) {
// A new mDestState so continue looping
destState = mDestState;
} else {
// No change in mDestState so we're done
break;
}
}
mDestState = null;
}
/**
* After processing all transitions check and
* see if the last transition was to quit or halt.
*/
if (destState != null) {
if (destState == mQuittingState) {
/**
* Call onQuitting to let subclasses cleanup.
*/
mSm.onQuitting();
cleanupAfterQuitting();
} else if (destState == mHaltingState) {
/**
* Call onHalting() if we've transitioned to the halting
* state. All subsequent messages will be processed in
* in the halting state which invokes haltedProcessMessage(msg);
*/
mSm.onHalting();
}
}
}
执行输出的Log:
D/hsm1 ( 1999): makeHsm1 E
D/hsm1 ( 1999): ctor E
D/hsm1 ( 1999): ctor X
D/hsm1 ( 1999): mP1.enter
D/hsm1 ( 1999): mS1.enter
D/hsm1 ( 1999): makeHsm1 X
分析完初始化流程,执行测试案例。
Hsm1 hsm = makeHsm1();
synchronize(hsm) {
//1
hsm.sendMessage(obtainMessage(hsm.CMD_1));
//2
hsm.sendMessage(obtainMessage(hsm.CMD_2));
try {
// wait for the messages to be handled
hsm.wait();
} catch (InterruptedException e) {
loge("exception while waiting " + e.getMessage());
}
}
@Override
public final void handleMessage(Message msg) {
if (!mHasQuit) {
if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
//onPreHandleMessage是个空方法。子类可以自己实现
mSm.onPreHandleMessage(msg);
}
//在初始化完成后mIsConstructionCompleted = true;
if (mIsConstructionCompleted || (mMsg.what == SM_QUIT_CMD)) {
/** Normal path */
msgProcessedState = processMsg(msg);
}
...
//再执行完S1.processMessage后,当前的mDestState为mS1
performTransitions(msgProcessedState, msg);
// We need to check if mSm == null here as we could be quitting.
if (mDbg && mSm != null) mSm.log("handleMessage: X");
if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
mSm.onPostHandleMessage(msg);
}
}
}
//--- from handleMessage
private final State processMsg(Message msg) {
//从初始状态开始
StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
if (mDbg) {
mSm.log("processMsg: " + curStateInfo.state.getName());
}
if (isQuit(msg)) {
transitionTo(mQuittingState);
} else {
//从初始节点调用processMessage方法。
//如果当前节点可以处理跳过,如果当前节点不可处理。则调用父节点的processMessage方法
//如果一直迭代到根节点还是无法处理此msg。则调用unhandleMessage.表示无法处理此msg
while (!curStateInfo.state.processMessage(msg)) {
/**
* Not processed
*/
curStateInfo = curStateInfo.parentStateInfo;
if (curStateInfo == null) {
/**
* No parents left so it's not handled
*/
mSm.unhandledMessage(msg);
break;
}
if (mDbg) {
mSm.log("processMsg: " + curStateInfo.state.getName());
}
}
}
return (curStateInfo != null) ? curStateInfo.state : null;
}
上面的代码会执行到初始节点的processMessage方法,而初始节点的是mS1。我接着分析一下S1的代码。
class S1 extends State {
@Override
public void enter() {
log("mS1.enter");
}
@Override
public boolean processMessage(Message message) {
log("S1.processMessage what=" + message.what);
if (message.what == CMD_1) {
//设置状态机的mDestState 为mS1
transitionTo(mS1);
// 返回true
return HANDLED;
} else {
// Let parent process all other messages
return NOT_HANDLED;
}
}
@Override
public void exit() {
log("mS1.exit");
}
}
//StateMachine.java
private final void transitionTo(IState destState) {
if (mTransitionInProgress) {
Log.wtf(mSm.mName, "transitionTo called while transition already in progress to " +
mDestState + ", new target state=" + destState);
}
mDestState = (State) destState;
if (mDbg) mSm.log("transitionTo: destState=" + mDestState.getName());
}
S1中的方法中只是将状态机的mDestState设置为mS1, 接下来我们在回到hanldMessage方法中。顺着逻辑执行performTransitions()
private void performTransitions(State msgProcessedState, Message msg) {
/**
* If transitionTo has been called, exit and then enter
* the appropriate states. We loop on this to allow
* enter and exit methods to use transitionTo.
*/
//此处为mS1
State orgState = mStateStack[mStateStackTopIndex].state;
...
//destState 为 mS1
State destState = mDestState;
if (destState != null) {
/**
* Process the transitions including transitions in the enter/exit methods
*/
while (true) {
if (mDbg) mSm.log("handleMessage: new destination call exit/enter");
/**
* Determine the states to exit and enter and return the
* common ancestor state of the enter/exit states. Then
* invoke the exit methods then the enter methods.
*/
//从目标节点向查找跟当前节点共同的父节点。
StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
// flag is cleared in invokeEnterMethods before entering the target state
mTransitionInProgress = true;
//从当前节点一直共同的父节点(不包含共同的父节点),执行exit()方法
invokeExitMethods(commonStateInfo);
int stateStackEnteringIndex = moveTempStateStackToStateStack();
// 从共同的父节点一直到目标节点(不包含共同的父节点),执行enter方法
invokeEnterMethods(stateStackEnteringIndex);
/**
* Since we have transitioned to a new state we need to have
* any deferred messages moved to the front of the message queue
* so they will be processed before any other messages in the
* message queue.
*/
//会将mDefer队列中的消息加到MessageQueue的头部。并清空
moveDeferredMessageAtFrontOfQueue();
if (destState != mDestState) {
// A new mDestState so continue looping
destState = mDestState;
} else {
// No change in mDestState so we're done
break;
}
}
mDestState = null;
}
/**
* After processing all transitions check and
* see if the last transition was to quit or halt.
*/
if (destState != null) {
if (destState == mQuittingState) {
/**
* Call onQuitting to let subclasses cleanup.
*/
mSm.onQuitting();
cleanupAfterQuitting();
} else if (destState == mHaltingState) {
/**
* Call onHalting() if we've transitioned to the halting
* state. All subsequent messages will be processed in
* in the halting state which invokes haltedProcessMessage(msg);
*/
mSm.onHalting();
}
}
}
//--- from performTransitions
// p1
// / \
// ^ s0 s1
// | / \ \
// ^ s3 s4 s5
// | / \
// destState -> s6 s7 <- currentState
// 如果当前节点是s7 则[P1, s0, s4, s7]为激活的节点(ative = true),
// 现在目标节点是s6,从s6往上一直查到s0为激活节点。
private final StateInfo setupTempStateStackWithStatesToEnter(State destState) {
/**
* Search up the parent list of the destination state for an active
* state. Use a do while() loop as the destState must always be entered
* even if it is active. This can happen if we are exiting/entering
* the current state.
*/
mTempStateStackCount = 0;
StateInfo curStateInfo = mStateInfo.get(destState);
do {
mTempStateStack[mTempStateStackCount++] = curStateInfo;
curStateInfo = curStateInfo.parentStateInfo;
} while ((curStateInfo != null) && !curStateInfo.active);
if (mDbg) {
mSm.log("setupTempStateStackWithStatesToEnter: X mTempStateStackCount="
+ mTempStateStackCount + ",curStateInfo: " + curStateInfo);
}
return curStateInfo;
}
//--- from performTransitions
// p1
// / \
// commonStateInfo -> s0 s1
// / \ \
// s3 s4 s5
// / \ ^
// destState -> s6 s7 <- currentState |
// 从s7开始一直到s0为止,一路上的节点需要执行exit()方法,
// 同时mStateStackTopIndex会向上移动,直到指向s0.
/**
* Call the exit method for each state from the top of stack
* up to the common ancestor state.
*/
private final void invokeExitMethods(StateInfo commonStateInfo) {
while ((mStateStackTopIndex >= 0)
&& (mStateStack[mStateStackTopIndex] != commonStateInfo)) {
State curState = mStateStack[mStateStackTopIndex].state;
if (mDbg) mSm.log("invokeExitMethods: " + curState.getName());
curState.exit();
mStateStack[mStateStackTopIndex].active = false;
mStateStackTopIndex -= 1;
}
}
//--- from performTransitions
// mStateEnterTopIndex p1
// \ / \
// commonStateInfo -> s0 s1
// / \ \
// s3 s4 s5
// / \
// destState -> s6 s7
// 从mStateEnterTopIndex向下一直到s6执行enter()方法。
/**
* Invoke the enter method starting at the entering index to top of state stack
*/
private final void invokeEnterMethods(int stateStackEnteringIndex) {
for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
if (stateStackEnteringIndex == mStateStackTopIndex) {
// Last enter state for transition
mTransitionInProgress = false;
}
if (mDbg) mSm.log("invokeEnterMethods: " + mStateStack[i].state.getName());
mStateStack[i].state.enter();
mStateStack[i].active = true;
}
mTransitionInProgress = false; // ensure flag set to false if no methods called
}
Hsm1 hsm = makeHsm1();
synchronize(hsm) {
//1 这个执行完毕,状态机的mDestState = mS1;
hsm.sendMessage(obtainMessage(hsm.CMD_1));
//2 目前执行到这个位置。
hsm.sendMessage(obtainMessage(hsm.CMD_2));
try {
// wait for the messages to be handled
hsm.wait();
} catch (InterruptedException e) {
loge("exception while waiting " + e.getMessage());
}
}
//根据前面的分析,会走到StateMachine的handleMessage,先执行S1.processMessage发现无法处理
//交付给P1.processMessage进行处理。所以接下来分析P1的代码。
class P1 extends State {
@Override public void enter() {
log("mP1.enter");
}
@Override
public boolean processMessage(Message message) {
boolean retVal;
log("mP1.processMessage what=" + message.what);
switch(message.what) {
case CMD_2:
// CMD_2 will arrive in mS2 before CMD_3
//将CMD_3加到消息队列中
sendMessage(obtainMessage(CMD_3));
//将message(msg=CMD_2)加到defer队列中
deferMessage(message);
//将mDestState设置为mS2。
transitionTo(mS2);
retVal = HANDLED;
break;
default:
// Any message we don't understand in this state invokes unhandledMessage
retVal = NOT_HANDLED;
break;
}
return retVal;
}
@Override
public void exit() {
log("mP1.exit");
}
}
//--- from handleMessage
//将调用deferMessage的消息加到MessageQueue队列之前。
private final void moveDeferredMessageAtFrontOfQueue() {
/**
* The oldest messages on the deferred list must be at
* the front of the queue so start at the back, which
* as the most resent message and end with the oldest
* messages at the front of the queue.
*/
for (int i = mDeferredMessages.size() - 1; i >= 0; i--) {
Message curMsg = mDeferredMessages.get(i);
if (mDbg) mSm.log("moveDeferredMessageAtFrontOfQueue; what=" + curMsg.what);
sendMessageAtFrontOfQueue(curMsg);
}
mDeferredMessages.clear();
}
以上执行是 hsm.sendMessage(obtainMessage(hsm.CMD_1)); 的流程,执行往后输出的log的如下:
D/hsm1 ( 1999): mS1.processMessage what=1
D/hsm1 ( 1999): mS1.exit
D/hsm1 ( 1999): mS1.enter
后面的代码 hsm.sendMessage(obtainMessage(hsm.CMD_2)); 也是走相同的流程,只不过需要结合不同的State中processMessage代码进行分析。
综上整体的状态机流程如下: