文章目录
##综述
创建状态机的流程主要是这几步:
1、通过MyStateMachine的静态方法,得到实例
2、建立状态树
3、设初始状态
4、Start状态机
###流程图
上图是创建状态机的流程图,一个深绿色的大框框代表一步,与上相对应。
##代码分析
对应的server端MyStateMachine代码大概是这样:
public class MyStateMachine extends StateMachine{
public static MyStateMachine makeHsm1() {
MyStateMachine sm = new MyStateMachine("hsm1");
sm.start();
return sm;
}
MyStateMachine(String name) {
super(name);
// Add states, use indentation to show hierarchy
addState(mS1);
addState(mS2, mS1);
... ...
// Set the initial state
setInitialState(mS4);
}
class S1 extends State {
@Override
public void enter() {
super.enter();
}
@Override
public boolean processMessage(Message message) {
super.processMessage();
}
@Override
public void exit() {
super.exit();
}
}
... ...
client端由MyStateMachine stateMachine = MyStateMachine.makeHsm1()得到状态机唯一实例。
###通过MyStateMachine的静态方法,得到实例
StateMachine的构造方法:
protected StateMachine(String name) {
mSmThread = new HandlerThread(name);
mSmThread.start();
Looper looper = mSmThread.getLooper();
initStateMachine(name, looper);
}
这是initStateMachine:
private void initStateMachine(String name, Looper looper) {
mName = name;
mSmHandler = new SmHandler(looper, this);
}
从中看到,启一个mSmThread的线程,获取它的Looper对象,并和SmHandlr关联。得到SmHandler实例。
MyStateMachine的构造函数默认是protect,不能从其它非继承类创建实例,只能makeHsm1()静态方法获得唯一实例,该方法new MyStateMachine实例。 这便是单例模式,这里使用时为了避免有一大堆MyStateMachine实例,不然就乱套了。
###建立状态树
- 通过addState()方法建立状态树。
- 该步骤上一篇博客已说过,见https://blog.csdn.net/lijunxie/article/details/81302421。
- addState()的原理是将当前状态和其父状态关联起来,加到一个HashMap中,这样通过子状态便能找到其父状态,(不能通过父状态找到子状态,我们的状态也用不上这样的功能,因为状态之间的跳转不涉及其子状态),可以多个状态拥有共同的父状态,这样便达到类似树的关系。
###设初始状态
private final void setInitialState(State initialState) {
if (mDbg) mSm.log("setInitialState: initialState=" + initialState.getName());
mInitialState = initialState;
}
这一步只是将 InitialState 赋个mInitialState 变量,该变量有什么用,怎么用在下一步中详细介绍。
###Start状态机
如上流程图所示,StateMachine.java提供start()方法,它只是封装的SmHandler的completeConstruction()方法。
如上篇wiki所示,该方法里最重要的是这两步:
mStateStack = new StateInfo[maxDepth];
mTempStateStack = new StateInfo[maxDepth];
setupInitialStateStack();
/** Sending SM_INIT_CMD message to invoke enter methods asynchronously */
sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj));
第一,初始化mStateStack和mTempStateStack 这两个数组,maxDepth是树的深度, 并往里面填充数据。这数据是怎们填充的呢?
第二,发送SM_INIT_CMD消息,SmHandler的handleMessage接收到后,调invokeEnterMethods(0), 这个方法其实就是遍历mStateStack数组,并依次调state的enter方法,代码是这样的:
private final void invokeEnterMethods(int stateStackEnteringIndex) {
for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
mStateStack[i].state.enter();
mStateStack[i].active = true;
}
}
上面两点用图这样表示:
如此过程便完成了状态机的start。
注意:状态机在start前一定要设置初始状态,不然,everything is spadework.
##END