Android StateMachine实践

本文探讨了Android中的StateMachine实现,遵循状态模式设计原则。IState接口定义了状态行为,如enter()、exit()和processMessage()。StateMachine通过Handler和Message处理状态转换,其状态树是一个非根节点的链表结构。在状态切换时,会执行从当前状态到新状态最近公共祖先之间的exit和enter操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 我们在实际应用中经常遇到状态设计模式,Android 框架中给我们提供了一个经典的状态模式实现——StateMachine。在StateMachine之前,先来看下状态设计模式定义和UML类图。
 状态模式:当一个对象的内在状态改变时,允许改变其行为。状态模式中行为是由状态来决定的,不同的状态下有不同的行为。状态模式的意图是让一个对象在其内部状态改变时,其行为也随之改变。

 状态模式的UML类图:


Context:环境类,定义客户感兴趣的接口,维护一个State子类的实例,这个实例定义了对象的当前状态。
State:抽象状态类或者状态接口,定义一个或者一组接口,表示该状态下的行为。
ConcreteStateA、ConcreteStateB:具体状态类,每一个具体的状态类实现抽象State中定义的接口,从而达到不同状态下的不同行为。

 接下来我们将分析Android中的StateMachine实现。首先看下StateMachine的UML类图,从图中可以看到,StateMachine的UML类图符合状态模式的设计原则,IState接口代表一组接口,表示该状态下的行为。HaltingState和QuittingState代表具体的状态,StateMachine对象维护当前状态,提供客户端感兴趣的接口。


 IState接口定义在frameworks/core/java/com/android/internal/util/IState.java中
 State接口定义frameworks/core/java/com/android/internal/util/State.java类中
 StateMachine类定义在frameworks/core/java/com/android/internal/util/StateMachine.java中。


  IState接口
   IState接口定义了一组方法,表示该状态下的行为。

  • enter()
            当进入一个状态时调用该方法;
  • exit()
           当退出一个状态时调用该方法;
  • processMessage()
           当状态机处理消息时调用该方法;
  • getName()
          返回状态的名字,调试使用;

 

State类
    State类提供一个IState接口的基本实现。State类必须实现processMessage方法,可选地实现enter和exit函数,这两个方法等价于构造函数和析构函数,用于初始化和清理相关的工作。


StateMachine类
    StateMachine是一个层次式状态机,可以管理和处理状态的跳转。StateMachine是基于Handler来实现的,通过Message来驱动状态的跳转。首先来看下状态机的构建:

    /**
     * 状态机的构建函数
     *
     * @param name 状态机的名字
     */
    protected StateMachine(String name) {
        //通过HandlerThread来处理消息
        mSmThread = new HandlerThread(name);
        mSmThread.start();
        Looper looper = mSmThread.getLooper();

        initStateMachine(name, looper);
    }

    /**
     * 初始化状态机
     *
     * @param looper 状态机使用的Looper
     * @param name 状态机名字
     */
    private void initStateMachine(String name, Looper looper) {
        mName = name;
        mSmHandler = new SmHandler(looper, this);
    }

    /*
    * SmHandler继承自Handler
    */
    private SmHandler(Looper looper, StateMachine sm) {
            super(looper);
            mSm = sm;//持有一个状态机的引用

            //将Halting和Quitting状态添加到状态列表中
            addState(mHaltingState, null);
            addState(mQuittingState, null);
    }
 当一个状态机被创建,通过addState函数来构建状态的层级,通过setInitialState函数来设置初始状态。

        /**
         * 添加一个新的状态到状态机
         * 
         *
         * @param 需要添加的状态
         * @param parent the 状态的父状态
         * @return stateInfo 返回当前状态的信息
         */
        private final StateInfo addState(State state, State parent) {

            StateInfo parentStateInfo = null;
            if (parent != null) {
                parentStateInfo = mStateInfo.get(parent);
                if (parentStateInfo == null) {
                    //如果parent状态还未添加,则先添加parent状态
                    parentStateInfo = addState(parent, null);
                }
            }
            StateInfo stateInfo = mStateInfo.get(state);
            if (stateInfo == null) {
                stateInfo = new StateInfo();
                //将状态添加到状态集合中
                mStateInfo.put(state, stateInfo);
            }

            //验证是否存在相同的状态,不同parent的情况,保证一个状态只有一个parent状态存在
            if ((stateInfo.parentStateInfo != null)
                    && (stateInfo.parentStateInfo != parentStateInfo)) {
                throw new RuntimeException("state already added");
            }
            stateInfo.state = state;
            stateInfo.parentStateInfo = parentStateInfo;
            stateInfo.active = false;
            return stateInfo;
        }

        /*
        * 状态信息
        */
        private class StateInfo {
            /** 状态 */
            State state;

            /** 父类状态信息,如果没有父类状态,则为空 */
            StateInfo parentStateInfo;

            /** True when the state has been entered and on the stack */
            boolean active;

            /**
             * Convert StateInfo to string
             */
            @Override
            public String toString() {
                return "state=" + state.getName() + ",active=" + active + ",parent="
                        + ((parentStateInfo == null) ? "null" : parentStateInfo.state.getName());
            }
        }
        //保存状态机中所有的状态
        private HashMap<State, StateInfo> mStateInfo = new HashMap<State, StateInfo>();
 当把状态添加到状态机列表后,需要通过setInitialState函数设置状态机的初始状态。

       /*
        * 设置状态机的初始化状态
        */
        public final void setInitialState(State initialState) {
            mSmHandler.setInitialState(initialState);
        }

        private final void setInitialState(State initialState) {
            if (mDbg) mSm.log("setInitialState: initialState=" + initialState.getName());
            mInitialState = initialState;
        }

        //状态机的初始状态,将处理第一个消息
        private State mInitialState;
 设置完状态机的初始状态之后,可以调用start方法,启动状态机。
       /*
        * 启动状态机
        */
        public void start() {
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.completeConstruction();
        }

        /*
        * 完成状态机的构建
        */
        private final void completeConstruction() {

             /*
             * 获取状态树最大的高度
             */
            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;
                }
            }

            //根据状态树最大高度穿件StateStack数组和TempStateStack数组
            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));

        }
       /*
        * 初始化StateStack数组
        */
        private final void setupInitialStateStack() {
            //获取初始状态的状态信息
            StateInfo curStateInfo = mStateInfo.get(mInitialState);
            //将初始状态以及初始状态的父状态和祖先状态放入TempStateStack数组中
            for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) {
                mTempStateStack[mTempStateStackCount] = curStateInfo;
                curStateInfo = curStateInfo.parentStateInfo;
            }

            // StateStack的索引,初始化时为-1,表示是一个空数组
            mStateStackTopIndex = -1;

            moveTempStateStackToStateStack();
        }

        /*
        * 将TempStackState数组中的状态转移到StateStack数组中,转移的顺序是反序的。
        */
        private final int moveTempStateStackToStateStack() {
            //StateStack数组的起始索引,这里为0
            int startingIndex = mStateStackTopIndex + 1;
            //TempStateStack数组最后一个元素的索引
            int i = mTempStateStackCount - 1;
            int j = startingIndex;
            //循环将TempStateStack数组中的元素以倒序的方式存入StateStack数组中
            while (i >= 0) {
                mStateStack[j] = mTempStateStack[i];
                j += 1;
                i -= 1;
            }
            //StateStack数组的索引指向最后一个元素
            mStateStackTopIndex = j - 1;

            return startingIndex;
        }

 举个例子来说,状态树如下:
         mP0
         /       \
      mP1   mS0
     /        \
  mS2     mS1
  /        \         \
mS3   mS4   mS5  ---> initial state

  状态树的最大高度maxDepth为3,当初始状态为mS5时,将初始状态及其父状态和祖先状态存入TempStateStack数组中,即mS5,mS1,mP1,mP0。接着将TempStackState数组中的元素以倒序的方式存入StateStack数组中,即mP0,mP1,mS1,mS5。mStateStackTopIndex索引指向数组的最后一个元素,即mStateStackTopIndex为3。

 需要说明的是,上面所说的状态树并不是真正的树数据结构,因为没有树的根节点,可以理解为有交叉的单链表结构。

    当完成了TempStackState和StateStack数组的初始化之后,发送了一个SM_INIT_CMD消息到消息队列的首部,触发状态的启动。

 sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj));
 sendMessageAtFrontOfQueue发送一个消息到消息队列的首部,让该消息最先处理。

        /*
         * 通过调用当前状态的processMessage方法处理消息
         * 调用状态的enter/exit方法
         * 将deferred的消息放入到消息队列的首部,在新的状态中处理
         *
         */
        @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);
                }


                //保存当前消息
                mMsg = msg;

                //保存处理当前信息的状态
                State msgProcessedState = null;
                if (mIsConstructionCompleted) {
                    // 1.调用processMessage处理消息
                    msgProcessedState = processMsg(msg);
                } else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)
                        && (mMsg.obj == mSmHandlerObj)) {
                    //初始化第一次时调用到这里
                    mIsConstructionCompleted = true;
                    invokeEnterMethods(0);
                } else {
                    throw new RuntimeException("StateMachine.handleMessage: "
                            + "The start method not called, received msg: " + msg);
                }
                // 2.调用状态的enter/exit方法,将deferred的消息放入消息队列的首部
                performTransitions(msgProcessedState, msg);

                if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
                    //可以覆写onPostHandleMessage方法,在消息处理完成后做一些工作
                    mSm.onPostHandleMessage(msg);
                }
            }
        }
 当收到SM_INIT_CMD消息,并且Message的obj为mSmHandlerObj时,表示这是第一次初始化状态。
       /*
        * 触发StateStack数组中元素进入enter状态,从stateStackEnteringIndex到mStateStackTopIndex之间的状态都将进入enter状态,并将active设置为true。
        */
        private final void invokeEnterMethods(int stateStackEnteringIndex) {
            for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
                if (stateStackEnteringIndex == mStateStackTopIndex) {
                    mTransitionInProgress = false;
                }
                mStateStack[i].state.enter();
                mStateStack[i].active = true;
            }
            mTransitionInProgress = false; 
        }
 当发送完SM_INIT_CMD消息之后,所有初始化相关的状态都执行enter方法,进入等待处理消息。StateMachine类是基于HandlerThread实现的,当状态机被创建并启动后,消息是通过sendMessage方法发送到当前状态处理。当前状态调用processMessage()方法来处理该消息。如果当前状态没有处理完该消息,则交由它的父状态的processMessage处理。
public void sendMessage(int what) {
            SmHandler smh = mSmHandler;
            if (smh == null) return;
            smh.sendMessage(obtainMessage(what));
        }
      当接收到新的消息后,StateMachine会调用handleMessage来处理该消息,并调用当前状态的processMessage方法来处理消息。状态机出初始化完成后,将调用processMsg方法来处理消息。
      在状态机中的,每个状态都有0个或者一个父状态。如果子状态不能处理完消息,则交由父类状态继续处理,或者它的祖先处理。如果父状态或其祖先还未能处理完成消息,则调用unhandleMessage方法做最后的处理。
       /*
        * 处理该消息,如果当前状态不能处理该消息,则交由其父状态处理以及祖先处理。
        * 如果该消息最终还未被处理,则交由状态机的unhandleMessage方法来处理。
        */
        private final State processMsg(Message msg) {
            //获取当前状态信息
            StateInfo curStateInfo = mStateStack[mStateStackTopIndex];

            if (isQuit(msg)) {
                //如果是终止消息,则转移到终止状态
                transitionTo(mQuittingState);
            } else {
                while (!curStateInfo.state.processMessage(msg)) {
                    获取当前状态的父状态信息
                    curStateInfo = curStateInfo.parentStateInfo;
                    if (curStateInfo == null) {
                        /**
                         * No parents left so it's not handled
                         */
                        mSm.unhandledMessage(msg);
                        break;
                    }
                }
            }
            //返回处理该消息的状态
            return (curStateInfo != null) ? curStateInfo.state : null;
        }
 processMessage方法返回处理消息的状态,接下来处理状态转移操作。状态转移的大致流程如下:
 1.获取当前状态与目标状态的共同祖先;
 2.将从当前状态到共同祖先状态(不包含共同祖先)之间的所有状态都执行exit方法;
 3.将从共同祖先状态到目标状态之间的所有状态都执行enter方法;
 4.判断是否是quit或halt状态,并执行相应的操作;

 当一个状态跳转到其他状态时,会导致当前状态被退出,进入新的状态。为了找出哪些状态需要执行exit退出操作,哪些状态需要执行enter进入操作,首先需要找到当前状态与新状态的最近公共祖先状态。然后我们从当前状态到公共祖先状态之间的状态(但不包含公共祖先状态),都执行exit退出操作。从公共祖先状态到新状态之间的状态都执行enter进入操作。如果当前状态与新状态没有公共祖先状态,则当前状态及其父状态和祖先状态都执行exit操作,并执行新状态的enter操作。

       /*
        * 状态转移操作
        */
        private void performTransitions(State msgProcessedState, Message msg) {
            .........
            //目标状态,通过transitionTo方法设置目标状态
            State destState = mDestState;
            if (destState != null) {

                while (true) {

                    //获取当前状态和目标状态共同的祖先状态
                    StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
                    mTransitionInProgress = true;
                    //从当前状态到公共祖先状态之间的状态都执行exit方法
                    invokeExitMethods(commonStateInfo);
                    //获取进入enter状态的索引
                    int stateStackEnteringIndex = moveTempStateStackToStateStack();
                    //从公共祖先状态到目标状态之间的状态都执行enter方法
                    invokeEnterMethods(stateStackEnteringIndex);


                    //将deferred的消息放入到消息队列的首部,在新的状态中处理
                    moveDeferredMessageAtFrontOfQueue();

                    if (destState != mDestState) {
                        // A new mDestState so continue looping
                        destState = mDestState;
                    } else {
                        // No change in mDestState so we're done
                        break;
                    }
                }
                mDestState = null;
            }

            //如果目标状态是quit状态,则执行onQuitting操作,如果是halt状态,则执行onHalting操作
            if (destState != null) {
                if (destState == mQuittingState) {
                    mSm.onQuitting();
                    cleanupAfterQuitting();
                } else if (destState == mHaltingState) {
                    mSm.onHalting();
                }
            }
        }
   
       /*
        * 将需要执行enter操作的状态保存到TempStateStack数组中
        * 返回当前状态与目标状态的共同祖先状态,如果没有则返回目标状态信息
        */
        private final StateInfo setupTempStateStackWithStatesToEnter(State destState) {
            mTempStateStackCount = 0;
            //获取目标状态信息
            StateInfo curStateInfo = mStateInfo.get(destState);
            do {
                mTempStateStack[mTempStateStackCount++] = curStateInfo;
                //父状态信息
                curStateInfo = curStateInfo.parentStateInfo;
            } while ((curStateInfo != null) && !curStateInfo.active);

            return curStateInfo;
        }

        /*
        * 将当前状态到共同祖先状态之间的状态执行exit方法
        */
        private final void invokeExitMethods(StateInfo commonStateInfo) {
            //从StateStack数组尾部索引开始查找,直到公共祖先状态,但不包含公共祖先状态,都执行exit方法
            while ((mStateStackTopIndex >= 0)
                    && (mStateStack[mStateStackTopIndex] != commonStateInfo)) {
                State curState = mStateStack[mStateStackTopIndex].state;
                curState.exit();
                mStateStack[mStateStackTopIndex].active = false;
                mStateStackTopIndex -= 1;
            }
        }

        /*
        * 将TempStackState数组中的状态转移到StateStack数组中,转移的顺序是反序的。
        */
        private final int moveTempStateStackToStateStack() {
            int startingIndex = mStateStackTopIndex + 1;
            int i = mTempStateStackCount - 1;
            int j = startingIndex;
            while (i >= 0) {
                mStateStack[j] = mTempStateStack[i];
                j += 1;
                i -= 1;
            }

            mStateStackTopIndex = j - 1;
            return startingIndex;
        }

        /*
        * 从stateStackEnteringIndex索引开始,将StateStack数组中的状态执行enter操作
        */
        private final void invokeEnterMethods(int stateStackEnteringIndex) {
            for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
                if (stateStackEnteringIndex == mStateStackTopIndex) {
                    mTransitionInProgress = false;
                }
                mStateStack[i].state.enter();
                mStateStack[i].active = true;
            }
            mTransitionInProgress = false; 
        }

       /*
        * 将deferred的消息放入到消息队列的首部
        */
        private final void moveDeferredMessageAtFrontOfQueue() {

            //将deferred数组中消息放入消息队列的首部,最早放入的数组的消息,在消息队列的最前面
            for (int i = mDeferredMessages.size() - 1; i >= 0; i--) {
                Message curMsg = mDeferredMessages.get(i);
                sendMessageAtFrontOfQueue(curMsg);
            }
            mDeferredMessages.clear();
        }
      还是以上面的例子来说, 现在假设mS5的processMessage能处理当前消息,并且在处理过程中,转移状态到mS4(transitionTo(mS4))。当从processMessage返回时,将会去查找mS5和mS4的公共祖先——mP1。所以接着执行mS5.exit,mS1.exit;mS2.enter,mS4.enter。新的活动列表是mP0,mP1,mS2,mS4。当下一个消息到达时,最先执行的是mS4.processMessage方法。

 在状态处理消息的时候,可以通过transitionTo方法跳转到其他的状态。

       /*
        * 转移到目标状态
        */
        public final void transitionTo(IState destState) {
            mSmHandler.transitionTo(destState);
        }

        private final void transitionTo(IState destState) {
            mDestState = (State) destState;
        }
 当所有的状态都处理完成后,则状态机会选择调用transitionToHaltingState()方法。
       /*
        * 转移到终止状态
        */
        public final void transitionToHaltingState() {
            mSmHandler.transitionTo(mSmHandler.mHaltingState);
        }
  如果想完全终止状态机,可以调用quit方法或者quitNow方法。这些方法将会调用exit方法退出当前状态和其父类状态,然后调用onQuiting,退出线程和Looper。
 public final void quit() {
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.quit();
        }

        private final void quit() {
            sendMessage(obtainMessage(SM_QUIT_CMD, mSmHandlerObj));
        }

一个具体的例子:
 在构建StateMachine对象的时候,将所有的状态都添加到状态列表中,并将初始状态设置为mS1。状态树为
        mP1      mP2
        /       \
      mS2   mS1 ---->初始状态
 然后调用start方法启动状态机,执行初始状态mS1以及mP1的enter方法,进入等待处理消息状态。
 当状态机通过sendMessage方法发送消息时,当前状态会开始处理消息,在消息处理的过程中,可以通过transitionTo转移到其他的状态。
public class StateMachineTest extends StateMachine {
private static final String TAG = "StateMachineTest";
    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 StateMachineTest makeStateMachine(){
        Log.e(TAG, "makeStateMachine()...");
StateMachineTest machine = new StateMachineTest("StateMachineTest");
machine.start();
        return machine;
}


protected StateMachineTest(String name) {
super(name);
Log.e(TAG, "StateMachineTest()...");
addState(mP1);
addState(mS1, mP1);
addState(mS2, mP1);
addState(mP2);

setInitialState(mS1);
}

class P1 extends State{
@Override
public void enter() {
            Log.e(TAG, "P1 enter()");
}

@Override
public boolean processMessage(Message message) {
            Log.e(TAG,"P1 processMessage()...message.what = " + message.what);
            boolean retVal;
            switch (message.what){
case CMD_2:
                    sendMessage(obtainMessage(CMD_3));
deferMessage(message);
transitionTo(mS2);
retVal = HANDLED;
                    break;
                default:
                    retVal = NOT_HANDLED;
                    break;

}
return retVal;
}

@Override
public void exit() {
            Log.e(TAG, "P1 exit()");
}
    }

class P2 extends State{
@Override
public void enter() {
            Log.e(TAG, "P2 enter()");
sendMessage(obtainMessage(CMD_5));
}

@Override
public boolean processMessage(Message message) {
            Log.e(TAG,"P2 processMessage()...message.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.e(TAG, "P2 exit()");
}
    }

class S1 extends State{
@Override
public void enter() {
            Log.e(TAG, "S1 enter()");
}

@Override
public boolean processMessage(Message message) {
            Log.e(TAG,"S1 processMessage()...message.what = " + message.what);
            boolean retVal;
            switch (message.what){
case CMD_1:
                    transitionTo(mS1);
retVal = HANDLED;
                    break;
                default:
                    retVal = NOT_HANDLED;
                    break;
}
return retVal;
}

@Override
public void exit() {
            Log.e(TAG, "S1 exit()");
}
    }

class S2 extends State{
@Override
public void enter() {
            Log.e(TAG, "S2 enter()");
}

@Override
public boolean processMessage(Message message) {
            Log.e(TAG,"S2 processMessage()...message.what = " + message.what);
            boolean retVal;
            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.e(TAG, "S2 exit()");
}
    }

@Override
protected void onHalting() {
        Log.e(TAG, "onHalting()....");
        synchronized (this){
this.notifyAll();
}
    }

P1 mP1 = new P1();
P2 mP2 = new P2();
S1 mS1 = new S1();
S2 mS2 = new S2();
}
 测试方法:
void testStateMachine(){
    StateMachineTest sm = StateMachineTest.makeStateMachine();
    synchronized (sm){
        sm.sendMessage(Message.obtain(sm.getHandler(),StateMachineTest.CMD_1));
sm.sendMessage(Message.obtain(sm.getHandler(), StateMachineTest.CMD_2));
        try {
            sm.wait();
}catch (InterruptedException e){
            Log.e(TAG,"exception while waiting " + e.getMessage());
}
    }
}
 代码执行结果为:

05-25 14:19:39.603  22337-22337/com.example.statemachinedemo E/StateMachineTest﹕ makeStateMachine()...
05-25 14:19:39.645  22337-22337/com.example.statemachinedemo E/StateMachineTest﹕ StateMachineTest()...
05-25 14:19:39.646  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ P1 enter()
05-25 14:19:39.646  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ S1 enter()
05-25 14:19:39.647  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ S1 processMessage()...message.what = 1
05-25 14:19:39.648  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ S1 exit()
05-25 14:19:39.648  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ S1 enter()
05-25 14:19:39.649  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ S1 processMessage()...message.what = 2
05-25 14:19:39.649  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ P1 processMessage()...message.what = 2
05-25 14:19:39.649  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ S1 exit()
05-25 14:19:39.650  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ S2 enter()
05-25 14:19:39.650  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ S2 processMessage()...message.what = 2
05-25 14:19:39.650  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ S2 processMessage()...message.what = 3
05-25 14:19:39.650  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ S2 exit()
05-25 14:19:39.651  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ P1 exit()
05-25 14:19:39.651  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ P2 enter()
05-25 14:19:39.651  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ P2 processMessage()...message.what = 3
05-25 14:19:39.651  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ P2 processMessage()...message.what = 4
05-25 14:19:39.652  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ P2 processMessage()...message.what = 5
05-25 14:19:39.652  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ P2 exit()
05-25 14:19:39.652  22337-22373/com.example.statemachinedemo E/StateMachineTest﹕ onHalting()....

完整代码例子在 https://github.com/qiubing/StateMachineDemo
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值