State machine
来源:互联网 发布:私密空间软件 编辑:程序博客网 时间:2024/05/19 22:02
在看state machine代码(StateMachine.java)的时候,发现源码的注释写的很好; 前半部分是讲解,后半部分是示例代码,读过之后state machine的要点也就基本掌握了。今天就做下翻译。当然翻译的意义并不大,能看英文的还是直接看英文的好,这里只是给自己练练手。言归正传,原文如下:
这里定义的是一个分层次的状态机,可以处理消息,并且拥有预制的分层状态。
状态是一个State对象,必须实现processMessage方法,选择性的实现enter/exit/getName方法。enter/exit就相当于面向对象编程里的构造和析构方法,分别用于初始化和清理状态对象。getName方法可以返回状态对象的名字; 默认实现是返回类名。建议实现getName方法返回state实例的名字,特别是一个state类有多个实例的情况。
当一个state machine被创建的时候,addState方法用于创建状态的层次结构,setInitialState方法用于确定初始状态。完成构造之后可以通过调用start方法初始化,并开启这个state machine。StateMachine的第一个动作是调用所有层次状态的enter方法,并从它的根父状态开始。enter方法调用的完成是在StateMachine的handler中,而不是在start方法的调用中,并且这些enter方法的调用是在所有消息被处理之前。例如,下面例子中的mP1.enter首先被调用,然后是mS1.enter被调用。最终,发往这个state machine的消息会被当前状态处理, 即下面例子中的初始状态mS1的precessMessage方法。
mP1 / \ mS2 mS1 --->initial state
当state machine被创建完成,并start后,消息可以通过obtainMessage方法创建,并通过sendMessage方法发往state machine。当state machine接收到消息后,当前状态的processMessage方法会被调用。 在上面的例子中,mS1.processMessage会被第一个调用。当前状态可以通过transitonTo方法转往新状态。
state machine中的每个状态可以没有或者有一个父状态。 如果一个子状态不能够处理消息,那么可以返回false 或者Not_HANDLED, 交由它的父状态处理。如果一个消息没有被任何状态处理,那么unhandledMessage方法会被调用,这是state machine处理这个消息的最后机会。
当所有的处理任务完成之后, state machine可以选择调用transitionToHaltingState方法。当 当前状态的processMessage方法返回后,state machine将会转换到Halting中间状态,并且调用onHalting方法。此后state machine收到的所有消息都会导致haltedProcessMessage方法被调用。
完全停止state machine可以调用quit或者quitNow方法。这两个方法会调用当前状态和它父状态的exit方法,然后onQutting方法会被调用,最后退出Thread/Loopers。
除了processMessage方法,每个状态还有enter和exit方法可以被重写。
由于所有的状态是分层预制的,转换到一个新状态会引起当前状态退出,并且进入新状态。靠近当前状态的通用父状态(多个状态的父状态)被用于确定应该进入/退出的状态序列。首先从当前状态退出,并依次退出父状态,直到遇到通用父状态,然后依次进入这个通用父状态下的子状态,直到进入目标状态。如果没有通用父状态,所有的状态都会退出,然后直接进入目标新状态。
状态可以调用的另外两个方法是deferMessage和sendMessageAtFrontOfQueue。sendMessageAtFrontOfQueue方法可以发送一个消息,并将它放在队列的首位,而不是末尾。deferMessage方法的调用会导致message被放进一个list中,直到转换到新状态; 等转换到新状态后所有被延迟的消息都会被放到state machine消息队列的前部。这些消息会被新状态优先处理。deferMessage方法在Android N 上还是protected类型, 在Android O上是public类型; sendMessageAtFrontOfQueue方法在Android O上依然是protected类型, 只可以在state machine内部调用。
下面的例子用一个拥有8个状态的state machine来说明了上面介绍的特点:
mP0 / \ mP1 mS0 / \ mS2 mS1 / \ \ mS3 mS4 mS5 --->initial state
当开启mS5状态后,mP0, mP1, mS1和mS5都会处于活跃状态。所以当收到消息的时候,如果每个状态的processMessage方法都无法处理这个消息而返回false或则NOT_HANDLED,那么processMessage方法被调用的顺序是mS5, mS1, mP1,mP0。
现在假设mS5.processMessage接收到一个它可以处理的消息,而且在处理的过程中确定要转换到新状态。mS5.processMessage可以调用transitionTo(mS4),并且返回true或者HANDLED。当从processMessage方法返回后,state machine的runtime会立刻找到通用父状态,即mP1。然后state machine会调用mS5.exit,mS1.exit,后续调用mS2.enter和mS4.enter。现在活跃的状态是mP0, mP1,mS2和mS4。所以当收到下一个消息的时候,mS4.processMessage会被调用。
下面是HelloWorld式的具体例子, 每个消息都会打印”Hello World”。
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());}
下面的state machine更有趣,他有4个状态,却有两个相互独立的父状态。
mP1 mP2 / \ms2 mS1
下面用伪代码对这个state machine做了描述。
state mP1 { enter { log("mP1.enter"); } exit { log("mP1.exit"); } on msg { CMD_2 { send(CMD_3); defer(msg); transitionTo(mS2); return HANDLED; } return NOT_HANDLED; }}INITIALstate mS1 parent mP1 { enter { log("mS1.enter"); } exit { log("mS1.exit"); } on msg { CMD_1 { transitionTo(mS1); return HANDLED; } return NOT_HANDLED; }}state mS2 parent mP1 { enter { log("mS2.enter"); } exit { log("mS2.exit"); } on msg { CMD_2 { send(CMD_4); return HANDLED; } CMD_3 { defer(msg); transitionTo(mP2); return HANDLED; } return NOT_HANDLED; }}state mP2 { enter { log("mP2.enter"); send(CMD_5); } exit { log("mP2.exit"); } on msg { CMD_3, CMD_4 { return HANDLED; } CMD_5 { transitionTo(HaltingState); return HANDLED; } return NOT_HANDLED; }}
下面代码是具体实现,StateMachineTest也有这部分代码:
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);//添加状态mP1 addState(mS1, mP1);//添加状态mS1,mP1为其父状态 addState(mS2, mP1);//添加状态mS2,mP1为其父状态 addState(mP2);//添加状态mP2 // Set the initial state setInitialState(mS1);//将mS1设置为初始状态 log("ctor X"); } class P1 extends State {//状态类P1 @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));//发送消息CMD_3 deferMessage(message);//延迟CMD_2,转换到状态mS2处理 transitionTo(mS2);//转换到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 {//状态类S1 @Override public void enter() { log("mS1.enter"); } @Override public boolean processMessage(Message message) { log("S1.processMessage what=" + message.what); if (message.what == CMD_1) {//收到消息CMD_1,就转换到mS1状态,这有意思,退出再进来一次 // Transition to ourself to show that enter/exit is called transitionTo(mS1);//转换到mS1,重新进mS1 return HANDLED; } else {//否则不处理,返回NOT_HANDLED // Let parent process all other messages return NOT_HANDLED; } } @Override public void exit() { log("mS1.exit"); } } class S2 extends State {//状态类S2 @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)://收到CMD_2消息后发送CMD_4消息 sendMessage(obtainMessage(CMD_4)); retVal = HANDLED; break; case(CMD_3)://收到CMD_3消息后,延迟该消息,转换到状态mP2后处理 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 {//状态类P2 @Override public void enter() { log("mP2.enter"); sendMessage(obtainMessage(CMD_5));//进入该状态就发送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)://收到CMD_5消息后转换到Halting状态 transitionToHaltingState(); break; } return HANDLED; } @Override public void exit() { log("mP2.exit"); } } @Override void onHalting() { log("halting"); synchronized (this) { this.notifyAll();//唤醒wait的线程 } } //创建各个状态类的实例对象 P1 mP1 = new P1(); S1 mS1 = new S1(); S2 mS2 = new S2(); P2 mP2 = new P2();}
如果在执行的过程中只发送CMD_1和CMD_2这两个消息(由于使用了hsm.wait(), 所以需要使用synchronize同步块,并且基于hsm):
Hsm1 hsm = makeHsm1();//构造并启动状态机synchronize(hsm) { hsm.sendMessage(obtainMessage(hsm.CMD_1));//发送CMD_1消息 hsm.sendMessage(obtainMessage(hsm.CMD_2));//发送CMD_2消息 try { // wait for the messages to be handled hsm.wait(); } catch (InterruptedException e) { loge("exception while waiting " + e.getMessage()); }}
输出如下:
D/hsm1 ( 1999): makeHsm1 E //makeHsm1()最先被调用,这个log第一个打印,即开始构造状态机D/hsm1 ( 1999): ctor E //进入状态机Hsm1的构造函数D/hsm1 ( 1999): ctor X //退出状态机Hsm1的构造函数D/hsm1 ( 1999): mP1.enter //Start状态机后,mS1作为初始状态,会引起其父状态enter方法被调用D/hsm1 ( 1999): mS1.enter //mS1.enter被调用D/hsm1 ( 1999): makeHsm1 X //状态机构造结束D/hsm1 ( 1999): mS1.processMessage what=1 //状态mS1收到CMD_1消息,重新进入mS1状态D/hsm1 ( 1999): mS1.exit //mS1.exit方法被调用D/hsm1 ( 1999): mS1.enter //mS1.enter方法被调用。D/hsm1 ( 1999): mS1.processMessage what=2 //mS1收到CMD_2消息,但是不处理,交由父状态mP1处理D/hsm1 ( 1999): mP1.processMessage what=2 //mP1收到CMD_2消息;发送CMD_3,延迟CMD_2,转换到mS2D/hsm1 ( 1999): mS1.exit //退出mS1状态,mS1.exit被调用D/hsm1 ( 1999): mS2.enter //进入mS2状态,mS2.enter被调用D/hsm1 ( 1999): mS2.processMessage what=2 //mS2优先处理CMD_2消息,发送CMD_4(队列中的排在CMD_3之后)D/hsm1 ( 1999): mS2.processMessage what=3 //mS2收到CMD_3消息; 延迟CMD_3,并转换到mP2状态D/hsm1 ( 1999): mS2.exit //退出mS2状态, mS2.exit方法被调用D/hsm1 ( 1999): mP1.exit //退出mP1状态,mP1.exit方法被调用D/hsm1 ( 1999): mP2.enter //进入mP2状态,mP2.enter方法被调用, 并发生CMD_5(队列中排在CMD_4之后)D/hsm1 ( 1999): mP2.processMessage what=3 //mP2优先处理之前被延迟的CMD_3消息D/hsm1 ( 1999): mP2.processMessage what=4 //处理CMD_4消息D/hsm1 ( 1999): mP2.processMessage what=5 //处理CMD_5消息; 转入Halting状态D/hsm1 ( 1999): mP2.exit //退出mP2状态,mP2.exit方法被调用。D/hsm1 ( 1999): halting //onHalting方法被调用,在该方法中notifyAll会唤醒阻塞的线程。
- state machine
- State Machine
- State machine
- 有限状态机(finity state machine)
- FSM(finite state machine)
- OpenGL&D3D State Machine
- experiment: State machine
- Regal State Machine
- EtherCAT State Machine Transitions
- The finite state machine
- The State Machine Framework
- Unity3D,Finite State Machine
- Finite State Machine
- State Machine 实现
- Nova state machine simplification
- wpa_supplicant-0.8 state machine
- CocosCreator使用state-machine
- JKI State Machine
- Luogu 3865(st表)
- 算24
- 1115. Counting Nodes in a BST (30)(建立二叉搜索树)
- GUROBI 学术许可(免IP验证)申请流程
- C语言实现hashmap,安卓系统AOSP源码
- State machine
- Java初学者使用 break continue switch 运用实例
- day13 常用类
- Leetcode算法学习日志-78 Subsets
- 1.双目立体视觉算法
- 欢迎使用CSDN-markdown编辑器
- ES6之类语法(Classes)
- 打印 * .
- hadoop2.8.2 MapReduce官方教程