android 状态机的作用,Android状态机statemachine详解

接上页(http://www.linuxidc.com/Linux/2013-08/88700.htm)接下来先看下状态转移performTransitions方法,首先碰到mDestState,这是SmHandler里面的一个标记,指向当前状态路径最下面的一个状态,后面都是父状态。可以在其他时候调用private final void transitionTo(IState destState)方法(外面的接口方法)改变当前mDestState的指向。这样处理完当前消息之后,performTransitions就会根据最新的mDestState来进行状态路径切换。状态切换有点像树的遍历一样,并不是回到根节点在进行搜索到新的节点,而是会回到原来的mDestState和最新的mDestState最近的一个共同祖先,然后在走向新的mDestState状态。进行状态切换主要是执行原状态路径上需要退出的状态的exit()方法,和新的状态路径上的enter()方法。

最后看下状态机的初始化invokeEnterMethods,这个直接看状态机的实例比较方便。看一个简单一些的应用,蓝牙APK里面关于耳机和电话连接处理的HeadsetStateMachine类,其构造方法中,关于状态机的代码如下:

addState(mDisconnected);

addState(mPending);

addState(mConnected);

addState(mAudioOn);

setInitialState(mDisconnected);

以上两块代码,第一块是建立本状态机的整个框架,就相当于建立整个状态树,第二个是设置初始化状态。再看看HeadsetStateMachine中的静态代码块

static HeadsetStateMachine make(HeadsetService context) {

Log.d(TAG, "make");

HeadsetStateMachine hssm = new HeadsetStateMachine(context);

hssm.start();

return hssm;

}

以上两块代码,第一块是建立本状态机的整个框架,就相当于建立整个状态树,第二个是设置初始化状态。再看看HeadsetStateMachine中的静态代码块

这里面有一个start()方法,从这个方法开始,状态机开始运作,包括分配内存,根据初始化状态设置初始化状态路径,这一点主要在setupInitialStateStack方法中执行,依次执行状态路径上每个状态的enter方法,这个使用了消息机制sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj));,最终就在本段开头的invokeEnterMethods方法中执行。

到这里状态机主要内容基本讲解完毕,貌似绝大多数都需要记忆,记住了感觉就理解到了。:-D 有点像本文开头说的。初一看感觉没有什么,但是如果想象下你有一个这样的需求,耳机和手机的状态一直在切换,你会采用什么方式去做,在考虑了很多之后会感觉状态机真的是一个很厉害的东西。:-D 接下来附上Android源码中的demo,为了方便理解,笔者将输出增加了一些空行,多余的空行不是demo打印的。

class Hsm1 extends StateMachine {

private static final String TAG = "hsm1";

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.d(TAG, "makeHsm1 E");

Hsm1 sm = new Hsm1("hsm1");

sm.start();

Log.d(TAG, "makeHsm1 X");

return sm;

}

Hsm1(String name) {

super(name);

Log.d(TAG, "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.d(TAG, "ctor X");

}

class P1 extends State {

@Override public void enter() {

Log.d(TAG, "mP1.enter");

}

@Override public boolean processMessage(Message message) {

boolean retVal;

Log.d(TAG, "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.d(TAG, "mP1.exit");

}

}

class S1 extends State {

@Override public void enter() {

Log.d(TAG, "mS1.enter");

}

@Override public boolean processMessage(Message message) {

Log.d(TAG, "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.d(TAG, "mS1.exit");

}

}

class S2 extends State {

@Override public void enter() {

Log.d(TAG, "mS2.enter");

}

@Override public boolean processMessage(Message message) {

boolean retVal;

Log.d(TAG, "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.d(TAG, "mS2.exit");

}

}

class P2 extends State {

@Override public void enter() {

Log.d(TAG, "mP2.enter");

sendMessage(obtainMessage(CMD_5));

}

@Override public boolean processMessage(Message message) {

Log.d(TAG, "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.d(TAG, "mP2.exit");

}

}

@Override

void onHalting() {

Log.d(TAG, "halting");

synchronized (this) {

this.notifyAll();

}

}

P1 mP1 = new P1();

S1 mS1 = new S1();

S2 mS2 = new S2();

P2 mP2 = new P2();

}

*

If this is executed by sending two messages CMD_1 and CMD_2

* (Note the synchronize is only needed because we use hsm.wait())

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) {

Log.e(TAG, "exception while waiting " + e.getMessage());

}

}

输出如下:

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

D/hsm1    ( 1999): mS1.processMessage what=1

D/hsm1    ( 1999): mS1.exit

D/hsm1    ( 1999): mS1.enter

D/hsm1    ( 1999): mS1.processMessage what=2

D/hsm1    ( 1999): mP1.processMessage what=2

D/hsm1    ( 1999): mS1.exit

D/hsm1    ( 1999): mS2.enter

D/hsm1    ( 1999): mS2.processMessage what=2

D/hsm1    ( 1999): mS2.processMessage what=3

D/hsm1    ( 1999): mS2.exit

D/hsm1    ( 1999): mP1.exit

D/hsm1    ( 1999): mP2.enter

D/hsm1    ( 1999): mP2.processMessage what=3

D/hsm1    ( 1999): mP2.processMessage what=4

D/hsm1    ( 1999): mP2.processMessage what=5

D/hsm1    ( 1999): mP2.exit

D/hsm1    ( 1999): halting

0b1331709591d260c1c78e86d0c51c18.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值