StateMachine 状态机原理

来源:互联网 发布:中宏数据库 讲座 编辑:程序博客网 时间:2024/05/20 20:56

The state machine defined here is a hierarchical state machine which processes messages and can have states arranged hierarchically.
这里通过CallAudioRouteStateMachine 为线索来看状态机的原理。

State

状态机首先要知道的肯定就是状态,它必须要实现processMessage方法和三个可选的方法enter/exit/getName

    abstract class AudioState extends State {        @Override        public void enter() {            super.enter();            Log.event(mCallsManager.getForegroundCall(), Log.Events.AUDIO_ROUTE,                    "Entering state " + getName());        }        @Override        public void exit() {            Log.event(mCallsManager.getForegroundCall(), Log.Events.AUDIO_ROUTE,                    "Leaving state " + getName());            super.exit();        }        @Override        public boolean processMessage(Message msg) {            switch (msg.what) {                case CONNECT_WIRED_HEADSET:                    Log.event(mCallsManager.getForegroundCall(), Log.Events.AUDIO_ROUTE,                            "Wired headset connected");                    mAvailableRoutes &= ~ROUTE_EARPIECE;                    mAvailableRoutes |= ROUTE_WIRED_HEADSET;                    return NOT_HANDLED;                case CONNECT_BLUETOOTH:                    Log.event(mCallsManager.getForegroundCall(), Log.Events.AUDIO_ROUTE,                            "Bluetooth connected");                    mAvailableRoutes |= ROUTE_BLUETOOTH;                    return NOT_HANDLED;                case DISCONNECT_WIRED_HEADSET:                    Log.event(mCallsManager.getForegroundCall(), Log.Events.AUDIO_ROUTE,                            "Wired headset disconnected");                    mAvailableRoutes &= ~ROUTE_WIRED_HEADSET;                    if (mDoesDeviceSupportEarpieceRoute) {                        mAvailableRoutes |= ROUTE_EARPIECE;                    }                    return NOT_HANDLED;                case DISCONNECT_BLUETOOTH:                    Log.event(mCallsManager.getForegroundCall(), Log.Events.AUDIO_ROUTE,                            "Bluetooth disconnected");                    mAvailableRoutes &= ~ROUTE_BLUETOOTH;                    return NOT_HANDLED;                case SWITCH_BASELINE_ROUTE:                    sendInternalMessage(calculateBaselineRouteMessage(false));                    return HANDLED;                case USER_SWITCH_BASELINE_ROUTE:                    sendInternalMessage(calculateBaselineRouteMessage(true));                    return HANDLED;                case SWITCH_FOCUS:                    mAudioFocusType = msg.arg1;                    return NOT_HANDLED;                default:                    return NOT_HANDLED;            }        }        // Behavior will depend on whether the state is an active one or a quiescent one.        abstract public void updateSystemAudioState();        abstract public boolean isActive();    }    // 可以看到在这个基类中processMessage的返回值都是NOT_HANDLED。    abstract class EarpieceRoute extends AudioState {        @Override        public boolean processMessage(Message msg) {            if (super.processMessage(msg) == HANDLED) {                return HANDLED;            }            switch (msg.what) {                case CONNECT_WIRED_HEADSET:                    sendInternalMessage(SWITCH_HEADSET);                    return HANDLED;                case CONNECT_BLUETOOTH:                    if (!mHasUserExplicitlyLeftBluetooth) {                        sendInternalMessage(SWITCH_BLUETOOTH);                    } else {                        Log.i(this, "Not switching to BT route from earpiece because user has " +                                "explicitly disconnected.");                        updateSystemAudioState();                    }                    return HANDLED;                case DISCONNECT_BLUETOOTH:                    updateSystemAudioState();                    // No change in audio route required                    return HANDLED;                case DISCONNECT_WIRED_HEADSET:                    Log.e(this, new IllegalStateException(),                            "Wired headset should not go from connected to not when on " +                            "earpiece");                    updateSystemAudioState();                    return HANDLED;                case BT_AUDIO_DISCONNECT:                    // This may be sent as a confirmation by the BT stack after switch off BT.                    return HANDLED;                case CONNECT_DOCK:                    sendInternalMessage(SWITCH_SPEAKER);                    return HANDLED;                case DISCONNECT_DOCK:                    // Nothing to do here                    return HANDLED;                default:                    return NOT_HANDLED;            }        }    }    // 这里处理硬件变化的message,链接耳机,链接蓝牙之类。class ActiveEarpieceRoute extends EarpieceRoute {        @Override        public String getName() {            return ACTIVE_EARPIECE_ROUTE_NAME;        }        @Override        public boolean isActive() {            return true;        }        @Override        public void enter() {            super.enter();            setSpeakerphoneOn(false);            setBluetoothOn(false);            if (mAudioFocusType == ACTIVE_FOCUS) {                setNotificationsSuppressed(true);            }            CallAudioState newState = new CallAudioState(mIsMuted, ROUTE_EARPIECE,                    mAvailableRoutes);            setSystemAudioState(newState);            updateInternalCallAudioState();        }        @Override        public void exit() {            super.exit();            setNotificationsSuppressed(false);        }        @Override        public void updateSystemAudioState() {            updateInternalCallAudioState();            setSystemAudioState(mCurrentCallAudioState);        }        @Override        public boolean processMessage(Message msg) {            if (super.processMessage(msg) == HANDLED) {                return HANDLED;            }            switch (msg.what) {                case SWITCH_EARPIECE:                case USER_SWITCH_EARPIECE:                    // Nothing to do here                    return HANDLED;                case SWITCH_BLUETOOTH:                case USER_SWITCH_BLUETOOTH:                    if ((mAvailableRoutes & ROUTE_BLUETOOTH) != 0) {                        transitionTo(mAudioFocusType == ACTIVE_FOCUS ?                                mActiveBluetoothRoute : mRingingBluetoothRoute);                    } else {                        Log.w(this, "Ignoring switch to bluetooth command. Not available.");                    }                    return HANDLED;                case SWITCH_HEADSET:                case USER_SWITCH_HEADSET:                    if ((mAvailableRoutes & ROUTE_WIRED_HEADSET) != 0) {                        transitionTo(mActiveHeadsetRoute);                    } else {                        Log.w(this, "Ignoring switch to headset command. Not available.");                    }                    return HANDLED;                case SWITCH_SPEAKER:                case USER_SWITCH_SPEAKER:                    transitionTo(mActiveSpeakerRoute);                    return HANDLED;                case SWITCH_FOCUS:                    if (msg.arg1 == ACTIVE_FOCUS) {                        setNotificationsSuppressed(true);                    }                    if (msg.arg1 == NO_FOCUS) {                        reinitialize();                    }                    return HANDLED;                default:                    return NOT_HANDLED;            }        }    }    // 这里实现了 enter 和 exit 并且处理通话过程中 硬件变化后和用户切换后发送的message

因为这里状态比较复现有继承关系,这里只关注通话中最常见的一个状态Active听筒的实现。有这样的继承关系,也可以看到对message进行一些区分,最后实现的ActiveEarpieceRoute可以只关心它要处理的message,也可以看到如果一个message都会先父类的processMessage,如果父类能够处理,那么子类就不再处理。
所以可以看到State的实现还是非常简单的,只要处理enter这个状态时的操作,exit这个状态时的操作和处在这个状态时Machine向它发送的消息processMessage。

StateMachine

Init

第一件事情:初始化和开始运行
首先可以看到CallAudioRouteStateMachine的构造函数中先addState()

    public CallAudioRouteStateMachine(...) {                addState(mActiveEarpieceRoute);        addState(mActiveHeadsetRoute);        addState(mActiveBluetoothRoute);        addState(mActiveSpeakerRoute);        addState(mRingingBluetoothRoute);        addState(mQuiescentEarpieceRoute);        addState(mQuiescentHeadsetRoute);        addState(mQuiescentBluetoothRoute);        addState(mQuiescentSpeakerRoute);    }    // StateMachine.java    protected final void addState(State state) {        mSmHandler.addState(state, null);    }

看mSmHandler是个什么呢? 为什么又传了一个null

    private static class SmHandler extends Handler

对就是一个Handler,可以猜到,用它来将发送到StateMachine的message发送到指定的State处理
因为addState方法返回值是StateInfo所以先看一下这是什么?

private class StateInfo {            /** The state */            State state;            /** The parent of this state, null if there is no parent */            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());            }        }

可以看到非常简单存了当前的State,parentStateInfo和Active状态
再看addState方法

        private HashMap<State, StateInfo> mStateInfo = new HashMap<State, StateInfo>();        // 可以看到mStateInfo是一个HashMap,存State和对应的StateInfo,可以通过它知道active状态和parent        /**         * Add a new state to the state machine. Bottom up addition         * of states is allowed but the same state may only exist         * in one hierarchy.         *         * @param state the state to add         * @param parent the parent of state         * @return stateInfo for this state         */        private final StateInfo addState(State state, State parent) {            // 第二个参数是parent,也就是说状态有父子关系,说明了一开始说的分层关系            if (mDbg) {                mSm.log("addStateInternal: E state=" + state.getName() + ",parent="                        + ((parent == null) ? "" : parent.getName()));            }            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);                }            }            // 如果有parent,先从mStateInfo找到parentStateInfo,如没有那就先加进去            StateInfo stateInfo = mStateInfo.get(state);            if (stateInfo == null) {                stateInfo = new StateInfo();                mStateInfo.put(state, stateInfo);            }            // 从mStateInfo寻找当前State, 如果没有将当前State加入mStateInfo            // Validate that we aren't adding the same state in two different hierarchies.            if ((stateInfo.parentStateInfo != null)                    && (stateInfo.parentStateInfo != parentStateInfo)) {                throw new RuntimeException("state already added");            }            // 这里做了一个特殊判断,防止一个State被add两次并且parent还不同            stateInfo.state = state;            stateInfo.parentStateInfo = parentStateInfo;            stateInfo.active = false;            // 对stateInfo进行赋值,容易理解            if (mDbg) mSm.log("addStateInternal: X stateInfo: " + stateInfo);            return stateInfo;        }

第二个参数是parent,也就是说状态有父子关系,并且只能找到当前状态的父亲状态,可以猜测状态的变化只能从子到父?
到这里addState就完全了解了

接下来一件事情可定需要一个初始状态

   /**     * Set the initial state. This must be invoked before     * and messages are sent to the state machine.     *     * @param initialState is the state which will receive the first message.     */    protected final void setInitialState(State initialState) {        mSmHandler.setInitialState(initialState);        // 还是mSmHandler    }    /** @see StateMachine#setInitialState(State) */    private final void setInitialState(State initialState) {        if (mDbg) mSm.log("setInitialState: initialState=" + initialState.getName());        mInitialState = initialState;        // 还是非常简单 赋了个值而已    }

接下来就可以start了

Start

    /**     * Start the state machine.     */    public void start() {        // mSmHandler can be null if the state machine has quit.        SmHandler smh = mSmHandler;        if (smh == null) return;        // 还是mSmHandler 做一下非空判断        /** Send the complete construction message */        smh.completeConstruction();    }    /**         * Complete the construction of the state machine.         */        private final void completeConstruction() {            if (mDbg) mSm.log("completeConstruction: E");            /**             * Determine the maximum depth of the state hierarchy             * so we can allocate the state stacks.             */            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;                }            }            if (mDbg) mSm.log("completeConstruction: maxDepth=" + maxDepth);            // 计算一下构建的状态树最大深度,如果状态连成一个环,死循环了,根据上面的分析,之前的addState并没有规避这个情况。            mStateStack = new StateInfo[maxDepth];            mTempStateStack = new StateInfo[maxDepth];            setupInitialStateStack();            // 创建了两个StateStack,其中一个是temp,可能没啥用            /** Sending SM_INIT_CMD message to invoke enter methods asynchronously */            sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj));            // 发送一个message,并且还在队列最前端            if (mDbg) mSm.log("completeConstruction: X");        }

先看一下setupInitialStateStack

        /**         * Initialize StateStack to mInitialState.         */        private final void setupInitialStateStack() {            if (mDbg) {                mSm.log("setupInitialStateStack: E mInitialState=" + mInitialState.getName());            }            StateInfo curStateInfo = mStateInfo.get(mInitialState);            for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) {                mTempStateStack[mTempStateStackCount] = curStateInfo;                curStateInfo = curStateInfo.parentStateInfo;            }            // 从mInitialState开始,按顺序将stateInfo放入mTempStateStack中,最开始是mInitialState,最后是它的祖宗            // Empty the StateStack            mStateStackTopIndex = -1;            // 将栈顶指针置为-1 空栈            moveTempStateStackToStateStack();        }        /**         * Move the contents of the temporary stack to the state stack         * reversing the order of the items on the temporary stack as         * they are moved.         *         * @return index into mStateStack where entering needs to start         */        private final int moveTempStateStackToStateStack() {            int startingIndex = mStateStackTopIndex + 1;            int i = mTempStateStackCount - 1;            int j = startingIndex;            while (i >= 0) {                if (mDbg) mSm.log("moveTempStackToStateStack: i=" + i + ",j=" + j);                mStateStack[j] = mTempStateStack[i];                j += 1;                i -= 1;            }            // 一个简单算法,mTempStateStack数组倒序复制到mStateStack, mStateStack数组最开始是祖宗,最后是mInitialState            mStateStackTopIndex = j - 1;            // 初始化栈顶指针到现在的栈顶            if (mDbg) {                mSm.log("moveTempStackToStateStack: X mStateStackTop=" + mStateStackTopIndex                        + ",startingIndex=" + startingIndex + ",Top="                        + mStateStack[mStateStackTopIndex].state.getName());            }            return startingIndex;        }

接着再看这个发送的初始化的message吧 sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj)); 我们知道SmHandler是个Handler 所以处理这个消息的就是SmHandler重写的handleMessage

        // 这里mSm是构造SmHandler时传入的StateMachine对象,东西太多了,都要交代清楚        /**     * Constructor creates a StateMachine with its own thread.     *     * @param name of the state machine     */    protected StateMachine(String name) {        mSmThread = new HandlerThread(name);        mSmThread.start();        Looper looper = mSmThread.getLooper();        // new了一个Thread得到looper        initStateMachine(name, looper);    }    /**     * Initialize.     *     * @param looper for this state machine     * @param name of the state machine     */    private void initStateMachine(String name, Looper looper) {        mName = name;        mSmHandler = new SmHandler(looper, this);        // new mSmHandler 传入looper 和 this 就是这个StateMachine,之后逻辑自己看吧,还会加入两个状态,关系不大,不关心也可以    }        /**         * Handle messages sent to the state machine by calling         * the current state's processMessage. It also handles         * the enter/exit calls and placing any deferred messages         * back onto the queue when transitioning to a new state.         */        @Override        public final void handleMessage(Message msg) {            if (!mHasQuit) {                if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {                    mSm.onPreHandleMessage(msg);                }                // 如果不是初始化和退出的message 先让mSm(StateMachine)去onPreHandleMessage(这个就是StateMachine可重写的方法,看名字就只到干嘛预处理)                if (mDbg) mSm.log("handleMessage: E msg.what=" + msg.what);                /** Save the current message */                mMsg = msg;                // 如源码注释                /** State that processed the message */                State msgProcessedState = null;                if (mIsConstructionCompleted) {                    /** Normal path */                    msgProcessedState = processMsg(msg);                    // 是否已init过了, 是执行processMsg                } else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)                        && (mMsg.obj == mSmHandlerObj)) {                    /** Initial one time path. */                    mIsConstructionCompleted = true;                    invokeEnterMethods(0);                    // 这里应该是出事化的方法                } else {                    throw new RuntimeException("StateMachine.handleMessage: "                            + "The start method not called, received msg: " + msg);                }                performTransitions(msgProcessedState, msg);                // We need to check if mSm == null here as we could be quitting.                if (mDbg && mSm != null) mSm.log("handleMessage: X");                if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {                    mSm.onPostHandleMessage(msg);                    // 如onPreHandleMessage,最后处理的可重写方法                }            }        }

processMsg和performTransitions这个方法应该处理message的和状态变化的关键也是核心,我们先看invokeEnterMethods

        private final void invokeEnterMethods(int stateStackEnteringIndex) {            for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {                if (mDbg) mSm.log("invokeEnterMethods: " + mStateStack[i].state.getName());                mStateStack[i].state.enter();                mStateStack[i].active = true;            }            // 很简单 应该可以看出端倪了,这个状态和它的子孙全部enter并全部激活(mStateStack开始是祖宗)        }

到这里Machine就已经开始工作了,接下来让我们 看看想它发送一个message会发生什么?

sendMessage

假设我们现在通话结束,向mCallAudioRouteStateMachine发送一个message,不再foucus

    @VisibleForTesting    public void setCallAudioRouteFocusState(int focusState) {        // 假设这里focusState为0,切换为NO_FOCUS状态        mCallAudioRouteStateMachine.sendMessageWithSessionInfo(                CallAudioRouteStateMachine.SWITCH_FOCUS, focusState);    }    // mCallAudioRouteStateMachine.java    public void sendMessageWithSessionInfo(int message, int arg) {        sendMessage(message, arg, 0, Log.createSubsession());    }    // StateMachine.java    /**     * Enqueue a message to this state machine.     *     * Message is ignored if state machine has quit.     */    public void sendMessage(int what, int arg1, int arg2, Object obj) {        // mSmHandler can be null if the state machine has quit.        SmHandler smh = mSmHandler;        if (smh == null) return;        smh.sendMessage(obtainMessage(what, arg1, arg2, obj));        发现又是向SmHandler sendMessage,所以我们又回到了SmHandler的handleMessage方法    }

这时又要回到handleMessage,与Start时的不同之处就是这次要执行processMsg这个方法了

processMsg

        /**         * Process the message. If the current state doesn't handle         * it, call the states parent and so on. If it is never handled then         * call the state machines unhandledMessage method.         * @return the state that processed the message         */        private final State processMsg(Message msg) {            StateInfo curStateInfo = mStateStack[mStateStackTopIndex];            // 这里指向当前的状态            if (mDbg) {                mSm.log("processMsg: " + curStateInfo.state.getName());            }            if (isQuit(msg)) {                transitionTo(mQuittingState);                // 如果是退出的message 就退出,mQuittingState具体使怎样这里就不写了            } else {                while (!curStateInfo.state.processMessage(msg)) {                    /**                     * Not processed                     */                    curStateInfo = curStateInfo.parentStateInfo;                    // 可以发现这里是个循环,不断地调用state的processMessage,如果不能处理,调用它的parent继续处理,                    if (curStateInfo == null) {                        /**                         * No parents left so it's not handled                         */                        mSm.unhandledMessage(msg);                        // 如果所有的状态都不能处理这个message,执行StateMachine的unhandledMessage()方法,这时一个可重写的方法                        break;                    }                    if (mDbg) {                        mSm.log("processMsg: " + curStateInfo.state.getName());                    }                }            }            return (curStateInfo != null) ? curStateInfo.state : null;        }        // 先回到ActiveEarpieceRoute的               @Override        public boolean processMessage(Message msg) {            if (super.processMessage(msg) == HANDLED) {                return HANDLED;            }            switch (msg.what) {                ...                case SWITCH_FOCUS:                    if (msg.arg1 == ACTIVE_FOCUS) {                        setNotificationsSuppressed(true);                    }                    if (msg.arg1 == NO_FOCUS) {                        reinitialize();                        // 很简单 执行到这里                    }                    return HANDLED;                default:                    return NOT_HANDLED;            }        }    private void reinitialize() {        CallAudioState initState = getInitialAudioState();        mAvailableRoutes = initState.getSupportedRouteMask();        mIsMuted = initState.isMuted();        setMuteOn(mIsMuted);        mWasOnSpeaker = false;        mHasUserExplicitlyLeftBluetooth = false;        mLastKnownCallAudioState = initState;        // 处理一些AudioState的状态        transitionTo(mRouteCodeToQuiescentState.get(initState.getRoute()));        // 执行transitionTo    }    protected final void transitionTo(IState destState) {        mSmHandler.transitionTo(destState);        执行mSmHandler的transitionTo    }    private final void transitionTo(IState destState) {        mDestState = (State) destState;        很简单 对mDestState赋一下值        if (mDbg) mSm.log("transitionTo: destState=" + mDestState.getName());    }

我们应该注意到processMsg这个返回值,返回的是能处理这个消息的状态,这个返回值有什么用呢,又要回到SmHandler的handleMessage

performTransitions

凸显SmHandler的handleMessage的重要性,再复制一遍代码,

        /**         * Handle messages sent to the state machine by calling         * the current state's processMessage. It also handles         * the enter/exit calls and placing any deferred messages         * back onto the queue when transitioning to a new state.         */        @Override        public final void handleMessage(Message msg) {            if (!mHasQuit) {                if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {                    mSm.onPreHandleMessage(msg);                }                if (mDbg) mSm.log("handleMessage: E msg.what=" + msg.what);                /** Save the current message */                mMsg = msg;                /** State that processed the message */                State msgProcessedState = null;                if (mIsConstructionCompleted) {                    /** Normal path */                    msgProcessedState = processMsg(msg);                    // 这次执行到这里,msgProcessedState这时处理了这个message的State                } else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)                        && (mMsg.obj == mSmHandlerObj)) {                    /** Initial one time path. */                    mIsConstructionCompleted = true;                    invokeEnterMethods(0);                } else {                    throw new RuntimeException("StateMachine.handleMessage: "                            + "The start method not called, received msg: " + msg);                }                performTransitions(msgProcessedState, msg);                // start的时候msgProcessedState为空,这次来执行performTransitions,这次有了mDestState和performTransitions                // We need to check if mSm == null here as we could be quitting.                if (mDbg && mSm != null) mSm.log("handleMessage: X");                if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {                    mSm.onPostHandleMessage(msg);                }            }        }        // 来看看performTransitions都干了些啥吧        /**         * Do any transitions         * @param msgProcessedState is the state that processed the message         */        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            /**             * Record whether message needs to be logged before we transition and             * and we won't log special messages SM_INIT_CMD or SM_QUIT_CMD which             * always set msg.obj to the handler.             */            boolean recordLogMsg = mSm.recordLogRec(mMsg) && (msg.obj != mSmHandlerObj);            if (mLogRecords.logOnlyTransitions()) {                /** Record only if there is a transition */                if (mDestState != null) {                    mLogRecords.add(mSm, mMsg, mSm.getLogRecString(mMsg), msgProcessedState,                            orgState, mDestState);                }            } else if (recordLogMsg) {                /** Record message */                mLogRecords.add(mSm, mMsg, mSm.getLogRecString(mMsg), msgProcessedState, orgState,                        mDestState);            }            // 打些log 不关注            State destState = mDestState;            // 刚才我们给它赋值了,不为null            if (destState != null) {                /**                 * Process the transitions including transitions in the enter/exit methods                 */                while (true) {                    if (mDbg) mSm.log("handleMessage: new destination call exit/enter");                    /**                     * 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.                     */                    StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);                    // 将destState及它非active的parent更新到mTempStateStack,类似start的时候                    invokeExitMethods(commonStateInfo);                    // 在commonStateInfo之前清空mStateStack并执行State的exit                    int stateStackEnteringIndex = moveTempStateStackToStateStack();                    // 又是这个方法,不再说了,就是更新mStateStack,就是新的状态和它的父亲                    invokeEnterMethods(stateStackEnteringIndex);                    // 也是一样,就是没有active的状态都enter并active,如上所说两个状态的公共祖先不需要再次enter,所以有stateStackEnteringIndex                    // 到这里状态就完成切换了,也可以发现msgProcessedState只用来打了一些log                    /**                     * 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.                     */                    moveDeferredMessageAtFrontOfQueue();                    // 切换状态前先处理之前的message                    if (destState != mDestState) {                        // A new mDestState so continue looping                        destState = mDestState;                    } else {                        // No change in mDestState so we're done                        break;                    }                }                mDestState = null;            }            /**             * After processing all transitions check and             * see if the last transition was to quit or halt.             */            if (destState != null) {                if (destState == mQuittingState) {                    /**                     * Call onQuitting to let subclasses cleanup.                     */                    mSm.onQuitting();                    cleanupAfterQuitting();                } else if (destState == mHaltingState) {                    /**                     * Call onHalting() if we've transitioned to the halting                     * state. All subsequent messages will be processed in                     * in the halting state which invokes haltedProcessMessage(msg);                     */                    mSm.onHalting();                }                // 这时两个初始加入的状态不关注            }        }        private final StateInfo setupTempStateStackWithStatesToEnter(State destState) {            /**             * Search up the parent list of the destination state for an active             * state. Use a do while() loop as the destState must always be entered             * even if it is active. This can happen if we are exiting/entering             * the current state.             */            mTempStateStackCount = 0;            StateInfo curStateInfo = mStateInfo.get(destState);            do {                mTempStateStack[mTempStateStackCount++] = curStateInfo;                curStateInfo = curStateInfo.parentStateInfo;            } while ((curStateInfo != null) && !curStateInfo.active);            // 将目标状态和它的祖宗加入到mTempStateStack,这里判断active使可以节省一些,因为如果它active了,那它的祖宗都active了            if (mDbg) {                mSm.log("setupTempStateStackWithStatesToEnter: X mTempStateStackCount="                        + mTempStateStackCount + ",curStateInfo: " + curStateInfo);            }            return curStateInfo;        }        /**         * Call the exit method for each state from the top of stack         * up to the common ancestor state.         */        private final void invokeExitMethods(StateInfo commonStateInfo) {            while ((mStateStackTopIndex >= 0)                    && (mStateStack[mStateStackTopIndex] != commonStateInfo)) {                State curState = mStateStack[mStateStackTopIndex].state;                if (mDbg) mSm.log("invokeExitMethods: " + curState.getName());                curState.exit();                mStateStack[mStateStackTopIndex].active = false;                mStateStackTopIndex -= 1;            }            // 相当与清空mStateStack,并将其中的状态执行exit,除非到达commonStateInfo,就如setupTempStateStackWithStatesToEnter所说的,可以节省一些,也可以防止公共的parent再次执行enter。        }

到这里状态机的工作就算总结完了,通过看状态机的源码,也可以发现,之前State的继承关系其实是不必要的,完全可以通过state的parent关系实现完全一样的功能,当然google的这个还是有一些bug,写这篇博客的时候也给google 提了一个patch https://android-review.googlesource.com/#/c/345216/

0 0
原创粉丝点击