2018年01月06日14:33:58,西安下了三天的大雪了,上班上学上街都不方便,索性在家看看代码吧,已经好久没有更新博客了,是因为之前的笔记本配置实在跟不上了,2018年元旦,狠下心来新买了一个某米的笔记本,除了存储256G不够使用(单单下载一套Android代码,编译的时候就没有空间了,可怜的只剩下40M了,只是中通快递很不给力,扩展的硬盘还在路上。。。。。)废话不多说了,下面进入正题
此次关于StateMachine,我打算从下面几点来学习:
- StateMachine中的常用方法介绍
- StateMachine结论
- StateMachine栗子
- StateMachine源码解析
StateMachine是Android中基于Handler消息机制封装的一个针对不同状态不同消息可以做出不同的处理行为的一个实现机制,一个继承自StateMachine的状态机,可以有在至少一个或者多个状态,并且需要设置初始状态,此时通过obtainMessage和sendMessage获取和发送的消息,默认就由当前的初始状态首先处理。
StateMachine中的常用方法介绍
addState 添加当前状态到状态树中
可以看到addState由两个重载,一个参数的是添加当前状态树的根节点,两个参数的是添加当前的状态,并且指定其父状态
setInitialState 指定当前状态树的初始状态
transitionTo 从当前状态切换到目的状态(需要注意的是,并不是立即切换的,这个后面看源码可以证明这一点)
deferMessage 暂时将当前消息保存到消息队列的顶端, 一旦切换到新的状态,首先处理该消息
sendMessageAtFrontOfQueue
发送一个消息到需要处理的消息队列的顶部,我们知道当前接受到的消息首先放到一个队列里,之后从队列里首先取出顶部的消息来处理,所以sendMessageAtFrontOfQueue方法就是确保当前
发送的消息首先得以执行
另外每一个状态都是继承自 State的,所以还需要重点关注下 State的方法
enter 每次进入当前状态的时候执行的
exit 每次退出当前状态的时候执行的
processMessage 当前状态处理消息的方法
getName 获取当前状态的名称
StateMachine结论
StateMachine的构建过程
使用addState来构建一个StateMachine的树结构,另外通过setInitialState方法设置指定初始状态,之后通过start来启动该StateMachine,从根状态到初始状态路径下的的所有状态的enter方法首先得以执行,如下:
mP1
/ \
mS2 mS1 ----> initial state
ms1为初始状态,则当前StateMachine执行enter的顺序为
mP1#enter---> mS1#enter
此时向当前StateMachine发来的消息由mS1#processMessage执行
消息处理
- 当前StateMachine初始化完成以后,通过obtainMessage和sendMessage获取和发送消息,收到消息以后,首先是当前所处状态的processMessage执行,以上例子,就是ms1,另外ms1也可以通过transitionTo切换到新的状态,
需要注意的是,transitionTo并不能立刻切换到新状态 - 如果当前的所处的状态机不能处理消息,则在processMessage方法返回false,此时由其父状态来处理
- 通过transitionTo切换到新的状态机时候,沿着当前的状态机到需要切换到的目的状态机的共同父状态依次的exit方法,然后顺着共同父亲状态依次执行新的状态机的enter方法(需要注意的是,公共父状态的enter和exit方法不会执行)
- 如果想要停止状态机,可以调用quit或者abort方法,从而进入QuittingState,并在下一次处理时,退出HandlerThread线程,清理内部各个对象。
如下栗子:
mP0
/ \
mP1 mS0
/ \
mS2 mS1
/ \ \
mS3 mS4 mS5 ---> initial state
对于上面的状态机启动以后,当前处于激活的状态有:mP0,mP1,mS1,mS5 由于初始状态是mS5,所以发过来的消息,首先由mS5处理,假如mS5和他的父状态都不能处理该消息,则依次返回false,依次执行下面状态机的processMessage
mS5–>mS1–>mP1–>mP0
还是上面的状态机,假如当前状态机mS5返回true并且处理了消息,并且调用transitionTo(mS4)切换到新的mS4状态,此时会依次执行如下方法:mS5.exit()–>mS1.exit()–>mS2.enter()–>mS4.enter(), 此时处于激活的状态如下:
mP0,mP1,mS2,mS4,由于当前的状态是mS4,所以此时发过来的消息由mS4来处理
StateMachine栗子(一)
class HelloWorld extends StateMachine {
HelloWorld(String name) {
super(name);
addState(mState1);
setInitialState(mState1);
}
public static HelloWorld makeHelloWorld() {
HelloWorld hw = new HelloWorld("hw");
hw.start();
return hw;
}
class State1 extends State {
Override
public boolean processMessage(Message message) {
log("Hello World");
return HANDLED;
}
}
State1 mState1 = new State1();
}
void testHelloWorld() {
HelloWorld hw = makeHelloWorld();
hw.sendMessage(hw.obtainMessage());
}
上面的demo中,在调用hw.start以后,状态树中只有一个mState1,并且初始状态也是mState1
此时打印如下:
Hello World
StateMachine栗子(二)
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");
// 构造状态树
addState(mP1);
addState(mS1, mP1);
addState(mS2, mP1);
addState(mP2);
// 设置初始状态
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;
}
Override
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();
}
============================================
// 下面是测试代码
Hsm1 hsm = makeHsm1();
synchronize(hsm) {
hsm.sendMessage(obtainMessage(hsm.CMD_1));
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());
}
}
上面的代码构造出的状态树如下,mS1为初始状态
mP1 mP2
/ \
mS1 mS2
消息的处理分析
下面一步一步分析消息的处理:
Hsm1 hsm = makeHsm1(); // 构造状态树
==================================
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");
// 构造状态树
addState(mP1);
addState(mS1, mP1);
addState(mS2, mP1);
addState(mP2);
// 设置初始状态, 此时等到当前状态机start以后,会执行从根状态到初始状态的所有enter方法
setInitialState(mS1);
log("ctor X");
}
打印如下:
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
上面构建树的动作完成以后,处于激活状态的状态如下:
mP1 和 mS1
- 发送CMD_1消息
hsm.sendMessage(obtainMessage(hsm.CMD_1)); // 发送CMD_1消息
===========================================
由于当前所处的状态就是初始状态mS1,所以CMD_1由其来处理, 因为mS1已经处于激活状态,所以其enter方法将不会执行,直接由processMessage来处理消息
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;
}
}
上面mS1对于CMD_1消息处理,又切换到了当前状态,所以又会走一次其exit和enter方法:
D/hsm1 ( 1999): mS1.processMessage what=1
D/hsm1 ( 1999): mS1.exit
D/hsm1 ( 1999): mS1.enter
- 发送CMD_2消息
hsm.sendMessage(obtainMessage(hsm.CMD_2));
=============================================
上面CMD_1消息处理完成以后,当前状态还处于mS1, 所以对于CMD_2消息,还是由当前状态mS1来处理,可以看到mS1无法处理CMD_2消息,所以由其父状态来处理
下面是P1处理消息的方法
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;
}
可以看到在P1状态机中处理CMD_2消息,会先将当前CMD_2消息defer出去,同时send了一个CMD_3消息, 并且切换到了mS2状态, 这里需要重点注意当切换到了mS2以后,会首先处理之前defer出的消息,之后才会处理send过来的消息,另外由于切换状态到了mS2,又由于mS2之前没有启动过,所以会优先执行mS1的exit方法和mS2的enter方法,所以log打印如下:
// 由当前mS1无法处理CMD_2消息所以由其父状态mP1处理
D/hsm1 ( 1999): mS1.processMessage what=2
D/hsm1 ( 1999): mP1.processMessage what=2
// 由于切换到了mS2,所以依次执行 mS1.exit和mS2.enter 方法
D/hsm1 ( 1999): mS1.exit
D/hsm1 ( 1999): mS2.enter
下面S2处理消息:
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;
}
上一步,在P1状态中,defer了CMD_2消息,并且send了一个CMD_3消息,此时log如下:
// 首先处理CMD_2, sendMessage(obtainMessage(CMD_4));
D/hsm1 ( 1999): mS2.processMessage what=2
// 再处理CMD_3消息, deferMessage(CMD_3); transitionTo(mP2);
D/hsm1 ( 1999): mS2.processMessage what=3
同样的道理,切换到mP2状态, 由于mP2和mS2处于不同的树中,因此需要完全退出当前的状态树,同时进入新的状态树的mP2的状态树中,此时log如下:
D/hsm1 ( 1999): mS2.exit
D/hsm1 ( 1999): mP1.exit
D/hsm1 ( 1999): mP2.enter
P2状态处理消息如下:
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;
}
此时log如下:
D/hsm1 ( 1999): mP2.processMessage what=3 // 首先处理CMD_3
D/hsm1 ( 1999): mP2.processMessage what=4 // 再处理CMD_4消息
D/hsm1 ( 1999): mP2.processMessage what=5
D/hsm1 ( 1999): mP2.exit
D/hsm1 ( 1999): halting
StateMachine源码解析
到现在为止,我们已经知道了自己继承自StateMachine的一个状态机的构造过程和发送消息,的处理流程,如下:
super(name) // 调用父类的构造方法
addState(父状态)
addState(子状态,父状态)
setInitialState(初始状态)
hm.start() //启动状态机
hsm.sendMessage(obtainMessage(hsm.CMD_1)); // 发送消息
那么源码的分析当然也是跟着这个走的
StateMachine初始化
StateMachine初始化构造HandlerThread开启消息循环的初始化
在我们自己的状态机的构造方法里,都要调用super(name)来调用父类的构造方法,在这里会提前完成一些handler,和handlerThread的消息循环的初始化
上面可以看出其实在StateMachine内部消息驱动也是通过handler和HandlerThread来实现的,其内部由一个mSmHandler继承自Handler用来分发传递过来的消息
构造状态树addState
构造状态树addState
private HashMap<State, StateInfo> mStateInfo = new HashMap<State, StateInfo>();
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;
return stateInfo;
}
以上可以看出,系统添加状态的时候,会将所有状态添加到一个mStateInfo MAP集合中去,并且确保当前的父状态由于于子状态提前添加到状态树中去。
设置初始状态setInitialState
设置初始状态setInitialState
private final void setInitialState(State initialState) {
mInitialState = initialState;
}
上面设定初始状态比较简单,只是暂时指定了当前的initialState为初始状态
启动状态机start
启动状态机start
以上其实并不是真正的构造完当前的状态树,而是先临时将当前的状态和其父状态的关系通过mStateInfo集合保存起来,设定初始状态也是一样,先通过mInitialState属性来保存当前的初始状态是哪一个而已,真正构造起来整个状态树其实是在启动当前状态机start的时候完成的
completeConstruction
completeConstruction计算当前所有树最深的深度,根据该深度构造两个相同大小的数组,将从根状态开始,从父状态到初始状态的所有状态保存到mStateStack数组中,最终发送*SM_INIT_CMD消息,依次执行mStateStack数组中的状态的enter方法
private final void completeConstruction() {
int maxDepth = 0;
// 遍历addState时候加入mStateInfo的所有状态
Iterator i$ = this.mStateInfo.values().iterator();
while(i$.hasNext()) {
StateMachine.SmHandler.StateInfo si = (StateMachine.SmHandler.StateInfo)i$.next();
int depth = 0;
// 计算出当前树中的最深层次数
for(StateMachine.SmHandler.StateInfo i = si; i != null; ++depth) {
i = i.parentStateInfo;
}
// 由于可能存在多个状态树,最终取层次最深的树的深度作为最终深度
if(maxDepth < depth) {
maxDepth = depth;
}
}
// 根据当前状态机最深层次深度构造两个数组
this.mStateStack = new StateMachine.SmHandler.StateInfo[maxDepth];
this.mTempStateStack = new StateMachine.SmHandler.StateInfo[maxDepth];
this.setupInitialStateStack(); // 构造状态树
this.sendMessageAtFrontOfQueue(this.obtainMessage(SM_INIT_CMD, mSmHandlerObj));
}
setupInitialStateStack
保存添加初始状态和其父状态到mTempStateStack数组
private final void setupInitialStateStack() {
// 获取到当前的初始状态对应的StateInfo
StateMachine.SmHandler.StateInfo curStateInfo = (StateMachine.SmHandler.StateInfo)this.mStateInfo.get(this.mInitialState);
// 填充临时的mTempStateStack数组,保存当前处于激活状态的所有状态,初始状态索引从0开始,后面依次是其父状态
for(this.mTempStateStackCount = 0; curStateInfo != null; ++this.mTempStateStackCount) {
this.mTempStateStack[this.mTempStateStackCount] = curStateInfo;
curStateInfo = curStateInfo.parentStateInfo;
}
this.mStateStackTopIndex = -1;
this.moveTempStateStackToStateStack();
}
上面,填充临时的mTempStateStack数组,保存当前处于激活状态的所有状态,初始状态索引从0开始,后面依次是其父状态,下面举个栗子
mP1 mP2
/ \
mS1 mS2
addState(mP1);
addState(mS1, mP1);
addState(mS2, mP1);
addState(mP2);
setInitialState(mS1);
以上面的状态树为栗子,mS1为初始状态,则当前对应的数据如下:
// mTempStateStack数组中存放的数据
mTempStateStack {mS1,mP1}
mTempStateStackCount = 2
mStateStackTopIndex = -1
moveTempStateStackToStateStack
moveTempStateStackToStateStack拷贝反转临时数组到mStateStack
moveTempStateStackToStateStack方法将上一步mTempStateStack保存的临时数据复制到 mStateStack中,并将其索引反转过来
private final int moveTempStateStackToStateStack() {
int startingIndex = mStateStackTopIndex + 1; // startingIndex = 0
int i = mTempStateStackCount - 1; // mTempStateStack数组的最后一个数据索引
int j = startingIndex;
// 将mTempStateStack中的数据复制到mStateStack中,并将其索引反转过来
while (i >= 0) {
mStateStack[j] = mTempStateStack[i];
j += 1;
i -= 1;
}
mStateStackTopIndex = j - 1; // 保存当前mStateStack数组中最后一个状态(也就是初始状态)的索引
return startingIndex; // startingIndex = 0
}
还是上面的状态树,moveTempStateStackToStateStack完成之后,数据如下:
mStateStack数组的数据:
mStateStack = {mP1,mS1}
mStateStackTopIndex = 1
到现在为止,当前从初始状态所在树的树根到初始状态都已经按照顺序保存到了mStateStack数组中,好了,现在回到completeConstruction方法,继续执行,会发送SM_INIT_CMD消息给SmHandler处理
// 从根状态到初始状态,依次执行每个状态的enter方法
sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj));
SmHandler#handleMessage
SmHandler#handleMessage构造完数组发送消息
@Override
public final void handleMessage(Message msg) {
if (!mHasQuit) {
....
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);
}
....
}
}
处理SM_INIT_CMD消息,执行invokeEnterMethods(0);方法依次调用enter方法
invokeEnterMethods执行enter方法
private final void invokeEnterMethods(int stateStackEnteringIndex) {
for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
if (stateStackEnteringIndex == mStateStackTopIndex) {
// Last enter state for transition
mTransitionInProgress = false;
}
mStateStack[i].state.enter();
mStateStack[i].active = true;
}
mTransitionInProgress = false; // ensure flag set to false if no methods called
}
在上面构造状态树,将当前从根状态到初始状态保存到mStateStack 数组中,可以知道mStateStackTopIndex就是该mStateStack数组的长度,并且该数组从前往后,依次是从根状态到开始,从父状态到子状态,如下:
mP1 mP2
/ \
mS1 mS2
mS1为初始状态
mStateStack = {mP1,mS1}
所以invokeEnterMethods其实就是从根状态开始,从父状态到子状态依次执行每个状态的enter方法。
到现在为止,自定义的StateMachine的初始化就完成了,下面继续消息的处理
SmHandler处理消息
发送一条消息
hsm.sendMessage(obtainMessage(hsm.CMD_1));
可以看到,其实状态机接收到的消息,还是给其内部的SmHandler去处理的
@Override
public final void handleMessage(Message msg) {
....
if (mIsConstructionCompleted || (mMsg.what == SM_QUIT_CMD)) {
/** Normal path */
msgProcessedState = processMsg(msg);
}
....
}
SmHandler#processMsg
private final State processMsg(Message msg) {
// 从mStateStack获取当前的状态
StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
if (isQuit(msg)) {
transitionTo(mQuittingState);
} else {
while (!curStateInfo.state.processMessage(msg)) { //当前状态处理消息,如果不能处理返回false,则循环获取其父状态处理
/**
* Not processed
*/
curStateInfo = curStateInfo.parentStateInfo;
if (curStateInfo == null) {
/**
* No parents left so it's not handled
*/
// 如果当前状态没有父状态了,则该消息没有对应状态处理
mSm.unhandledMessage(msg);
break;
}
}
}
return (curStateInfo != null) ? curStateInfo.state : null;
}
上面的processMsg也正好验证了,我们上面的结论,如果当前的状态无法处理消息,则由其父状态去处理
deferMessage处理
之前说了deferMessage是将该消息保存在一个延迟队列中,这时并不发送出去,而是会在下一次状态转变的时候,将延迟队列中的所有消息放在消息队列的最前面。这些消息就会在切换到新的状态时被优先处理。下面看代码来证明它
private ArrayList<Message> mDeferredMessages = new ArrayList<Message>();
private final void deferMessage(Message msg) {
/* Copy the "msg" to "newMsg" as "msg" will be recycled */
Message newMsg = obtainMessage();
newMsg.copyFrom(msg);
mDeferredMessages.add(newMsg);
}
可以看到deferMessage其实就是先将消息拷贝一份并且添加到mDeferredMessages集合中去,下面看看transitionTo方法
transitionTo转换状态
这里可以验证我们上面所说的,transitionTo并不是立即切换到新的状态,其实是暂时把需要切换到的目的状态暂时保存起来,等待当前状态处理消息完成以后,才会进行切换,这点在handleMessage可以证实:
可以看到,在当前状态处理某一条消息期间,就算执行transitionTo也只是暂时将目的状态保存起来,后面等到该条消息处理完成之后,才会真正执行performTransitions去转换到目的状态
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.
*/
State orgState = mStateStack[mStateStackTopIndex].state;
State destState = mDestState; // 获取transitionTo中保存的目的状态
if (destState != null) {
/**
* Process the transitions including transitions in the enter/exit methods
*/
while (true) {
/**
* 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.
*/
// 计算出目的状态和当前状态的公共父状态commonStateInfo
StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
// flag is cleared in invokeEnterMethods before entering the target state
mTransitionInProgress = true;
// 依次执行从当前状态到公共父状态commonStateInfo的exit方法
invokeExitMethods(commonStateInfo);
// 将临时数组mTempStateStack中的数据反转赋值给mStateStack数组,并返回当前mStateStack数组的长度
int stateStackEnteringIndex = moveTempStateStackToStateStack();
// 从公共父状态依次执行enter方法,这里注意公共父状态是不执行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.
*/
// 当前目的状态已经处于激活状态,此时优先处理mDeferredMessages集合中的消息
moveDeferredMessageAtFrontOfQueue();
}
}
...
}
setupTempStateStackWithStatesToEnter
计算出目的状态和当前状态的公共父状态commonStateInfo
invokeExitMethods
依次执行从当前状态到公共父状态commonStateInfo的exit方法
moveTempStateStackToStateStack
**将临时数组mTempStateStack中的数据反转赋值给mStateStack数组,并返回当前mStateStack数组的长度
**
invokeEnterMethods
从公共父状态依次执行enter方法,这里注意公共父状态是不执行enter的
moveDeferredMessageAtFrontOfQueue
当前目的状态已经处于激活状态,此时优先处理mDeferredMessages集合中的消息
从moveDeferredMessageAtFrontOfQueue方法可以看出,越是最后defer的message,越会优先被处理
好了,到现在为止,StateMachine的原理已经缕清了,下面我做一下总结:
总结
StateMachine流程
- super(name) 构造SmHandler初始化消息循环
- addState 添加当前的状态到mStateInfo集合
- setInitialState 设置初始状态
- start() 启动当前状态机,在start方法里完成了状态树的构建,并且计算当前所有树的最大深度,并且创建长度为最大深度的数组mStateStack,mStateStack中依次保存从根状态到当前状态的所有状态,并且当前状态在最后一个索引存放, 最后发送 消息,依次执行,从根状态到当前初始状态的enter方法,完成之后,通过performTransitions切换到初始状态
- sendMessage 发送SM_INIT_CMD消息,最终是由当前状态的processMsg处理
方法总结
- 对于当前状态机接收到的消息,首先由当前的状态处理,如果当前的状态不能处理该消息,则由其父状态去处理,如果所有的状态都不能处理,则会走到其父类StateMachine#unhandledMessage方法
- deferMessage是将当前消息先临时存放到mDeferredMessages集合中,等到切换到新的状态,在依次从mDeferredMessages集合中取出消息,在新的状态处理,后defer的消息会优先被处理
- transitionTo切换状态并不能立即切换到目的状态,而是现将目的状态保存起来,等到当前状态处理当前消息完成以后,才通过performTransitions切换到目的状态
- 从当前状态切换到目的状态,首先会计算出当前状态和目的状态的公共父亲状态,然后,从当前状态到公共父亲状态依次执行exit方法,在从父亲状态到目的状态依次执行enter方法(需要注意的是,公共父亲状态不参与exit和enter方法的执行)
2018雪景大赛
最后晒晒最近朋友圈的各种大神的雪景大赛,也希望亲人和朋友2018事事顺心。。。