Android 狀態(tài)機(jī)

概念

有限狀態(tài)機(jī)即FSM,簡稱狀態(tài)機(jī),表示有限個狀態(tài)以及在這些狀態(tài)之間的轉(zhuǎn)移和動作等行為的數(shù)學(xué)模型。

狀態(tài)機(jī)可以描述為一個有向圖樹,有一組節(jié)點(diǎn)和一組轉(zhuǎn)移函數(shù)組成。狀態(tài)機(jī)通過相應(yīng)一些列事件運(yùn)行。每個
事件都屬于當(dāng)前結(jié)點(diǎn)的轉(zhuǎn)移函數(shù)的控制范圍內(nèi),其中函數(shù)的范圍是一個節(jié)點(diǎn)的子集。函數(shù)返回下一個節(jié)點(diǎn)。這些節(jié)點(diǎn)至少有一個終態(tài),到達(dá)終態(tài),狀態(tài)機(jī)停止。

Android StateMachine

Android 系統(tǒng)使用狀態(tài)機(jī)處理不同的狀態(tài),可以避免分支語句導(dǎo)致的程序閱讀性差以及擴(kuò)展問題。

使用類

state_machine.jpg
  • IState.java 狀態(tài)接口,每個狀態(tài)必須實(shí)現(xiàn)的接口
    • void enter() 狀態(tài)進(jìn)入時調(diào)用
    • void exit() 狀態(tài)退出時調(diào)用
    • boolean processMessage(Message msg) 消息處理函數(shù)
  • State.java 默認(rèn)實(shí)現(xiàn)的IState接口的狀態(tài), 需要實(shí)現(xiàn)新的狀態(tài)時,一般只需要集成State重寫里面方法即可
  • StateInfo.java 狀態(tài)節(jié)點(diǎn)信息,類似鏈表節(jié)點(diǎn)
  • StateMachine.java 定義狀態(tài)層次關(guān)系以及狀態(tài)轉(zhuǎn)換。根據(jù)實(shí)際需求繼承StateMachine,實(shí)現(xiàn)自己的狀態(tài)管理。

狀態(tài)機(jī)重點(diǎn)時SmHandler類

StateMachine

StateMachine有3個構(gòu)造函數(shù)

    protected StateMachine(String name) {
        mSmThread = new HandlerThread(name);
        mSmThread.start();
        Looper looper = mSmThread.getLooper();

        initStateMachine(name, looper);
    }

    protected StateMachine(String name, Handler handler) {
        initStateMachine(name, handler.getLooper());
    }

    protected StateMachine(String name, Looper looper) {
        initStateMachine(name, looper);
    }

    private void initStateMachine(String name, Looper looper) {
        mName = name;
        mSmHandler = new SmHandler(looper, this);
    }

常用的為protected StateMachine(String name)方法創(chuàng)建一個狀態(tài)機(jī)。
mSmThread為HandlerThread,作為消息循環(huán)線程
mSmHandler為handler用來處理消息

在狀態(tài)機(jī)維護(hù)一個狀態(tài)數(shù)(或者狀態(tài)層次關(guān)系),每個狀態(tài)的節(jié)點(diǎn)信息存儲在StateInfo中

StateInfo 節(jié)點(diǎn)信息

/**
         * Information about a state.
         * Used to maintain the hierarchy.
         */
        private class StateInfo {
            /** The state */
            State state; //節(jié)點(diǎn)信息

            /** The parent of this state, null if there is no parent */
            StateInfo parentStateInfo;  //父節(jié)點(diǎn)信息

            /** True when the state has been entered and on the stack */
            boolean active; //節(jié)點(diǎn)入棧,且已經(jīng)激活

            /**
             * Convert StateInfo to string
             */
            @Override
            public String toString() {
                return "state=" + state.getName() + ",active=" + active + ",parent="
                        + ((parentStateInfo == null) ? "null" : parentStateInfo.state.getName());
            }
        }

與鏈表區(qū)別是:鏈表中存儲的下一個子節(jié)點(diǎn)的信息,在狀態(tài)樹節(jié)點(diǎn)中存儲的不是子節(jié)點(diǎn)而是父節(jié)點(diǎn)信息;有點(diǎn)便于迅速查找父節(jié)點(diǎn),當(dāng)該節(jié)點(diǎn)無法處理此消息時,可以直接轉(zhuǎn)給父節(jié)點(diǎn)處理。

狀態(tài)機(jī)的構(gòu)建

    protected final void addState(State state) {
        mSmHandler.addState(state, null);
    }

狀態(tài)機(jī)構(gòu)建使用addState()方法,addState調(diào)用mSmHandler.addState()方法完成整個構(gòu)建過程。后面會看到狀態(tài)機(jī)的很多工作都是mSmHandler來完成。

        /**
         * 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) {
            if (mDbg) {
                mSm.log("addStateInternal: E state=" + state.getName() + ",parent="
                        + ((parent == null) ? "" : parent.getName()));
            }
            StateInfo parentStateInfo = null;
            if (parent != null) {
                parentStateInfo = mStateInfo.get(parent);
                //存在父節(jié)點(diǎn),但不在狀態(tài)樹中,添加進(jìn)來
                if (parentStateInfo == null) {
                    // Recursively add our parent as it's not been added yet.
                    //此處為遞歸調(diào)用
                    parentStateInfo = addState(parent, null);
                }
            }
            //狀態(tài)不在狀態(tài)樹中,添加進(jìn)來
            StateInfo stateInfo = mStateInfo.get(state);
            if (stateInfo == null) {
                //將新state包裝成StateInfo,存放在map中
                stateInfo = new StateInfo();
                mStateInfo.put(state, stateInfo);
            }

            // Validate that we aren't adding the same state in two different hierarchies.
            //每個狀態(tài)只能有一個父狀態(tài)
            if ((stateInfo.parentStateInfo != null)
                    && (stateInfo.parentStateInfo != parentStateInfo)) {
                throw new RuntimeException("state already added");
            }
            //認(rèn)親
            stateInfo.state = state;
            stateInfo.parentStateInfo = parentStateInfo;
            stateInfo.active = false;
            if (mDbg) mSm.log("addStateInternal: X stateInfo: " + stateInfo);
            return stateInfo;
        }

addState()方法將每個新添加進(jìn)來的狀態(tài)封裝成StateInfo,添加進(jìn)狀態(tài)樹中,如果該狀態(tài)的父節(jié)點(diǎn)不在狀態(tài)樹中,遞歸調(diào)用addState()添加進(jìn)狀態(tài)樹中。
StateInfo存儲父節(jié)點(diǎn)信息,這樣可以通過StateInfo將每個節(jié)點(diǎn)聯(lián)系在一起。狀態(tài)機(jī)中所節(jié)點(diǎn)都存儲在HashMap<State, StateInfo>()的鍵值對中,

每個狀態(tài)只能有一個父節(jié)點(diǎn)

狀態(tài)機(jī)啟動

    /**
     * Start the state machine.
     */
    public void start() {
        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        /** Send the complete construction message */
        smh.completeConstruction();
    }

start()調(diào)用smh.completeConstruction()完成狀體機(jī)構(gòu)建

        /**
         * 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.
             */
            //計(jì)算狀態(tài)樹最大深度,用于創(chuàng)建狀態(tài)樹容量
            //狀態(tài)樹記錄某個節(jié)點(diǎn)到根節(jié)點(diǎn)的狀態(tài)路徑,長度不會超過maxDeep
            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);

            //根據(jù)狀態(tài)棧的最大節(jié)點(diǎn)數(shù),創(chuàng)建mStateStack,mTempStateStack狀態(tài)棧
            mStateStack = new StateInfo[maxDepth];
            mTempStateStack = new StateInfo[maxDepth];
            //將狀態(tài)路徑存入狀態(tài)棧
            setupInitialStateStack();

            /** Sending SM_INIT_CMD message to invoke enter methods asynchronously */
            /*
            狀態(tài)棧中存儲當(dāng)前節(jié)點(diǎn)到根節(jié)點(diǎn)的所有狀態(tài),根節(jié)點(diǎn)位于mStateStack的0位置
             */
            //開啟狀態(tài)數(shù);通過發(fā)送SM_INIT_CMD消息,通知狀態(tài)樹可以工作,異步調(diào)用enter方法
            sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj));

            if (mDbg) mSm.log("completeConstruction: X");
        }

主要工作

  • 遍歷狀態(tài)樹中的節(jié)點(diǎn),獲取樹的最大節(jié)點(diǎn)數(shù)maxDeep
  • 使用棧來記錄某個節(jié)點(diǎn)到根節(jié)點(diǎn)的狀態(tài)路徑,路徑不超過maxDeep
  • 根據(jù)當(dāng)前節(jié)點(diǎn)和樹的最大節(jié)點(diǎn)數(shù),調(diào)用setupInitialStateStack創(chuàng)建兩個狀態(tài)棧
  • 初始化完畢,發(fā)送SM_INIT_CMD消息,表示狀態(tài)樹構(gòu)建完成

setupInitialStateStack 填充棧數(shù)據(jù)

        /**
         * Initialize StateStack to mInitialState.
         */
        private final void setupInitialStateStack() {
            if (mDbg) {
                mSm.log("setupInitialStateStack: E mInitialState=" + mInitialState.getName());
            }

            //根據(jù)第一個初始狀態(tài)
            StateInfo curStateInfo = mStateInfo.get(mInitialState);
            for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) {
                mTempStateStack[mTempStateStackCount] = curStateInfo;
                curStateInfo = curStateInfo.parentStateInfo;
            }
            //循環(huán)完畢,根節(jié)點(diǎn)位于棧頂,初始節(jié)點(diǎn)位于棧底

            // Empty the StateStack,清空mStateStack
            mStateStackTopIndex = -1;
            //將temporary stack棧中數(shù)據(jù)反序添沖到state stack中
            //這是根節(jié)點(diǎn)位于棧底(index=0),當(dāng)前節(jié)點(diǎn)位于棧頂
            moveTempStateStackToStateStack();
        }

根據(jù)當(dāng)前節(jié)點(diǎn),遍歷所有父節(jié)點(diǎn),將當(dāng)前節(jié)點(diǎn)到根節(jié)點(diǎn)的信息存儲在mTempStateStack中,循環(huán)過后當(dāng)前節(jié)點(diǎn)位于棧底(index=0),根節(jié)點(diǎn)位于棧頂
調(diào)用moveTempStateStackToStateStack將mTempStateStack中樹反轉(zhuǎn)存儲到mStateStack中。

moveTempStateStackToStateStack 反轉(zhuǎn)數(shù)據(jù)

        /**
         * 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.
         *
         * 將temporary stack棧中數(shù)據(jù)反序添加到state stack中
         *
         * 在mStateStack已有節(jié)點(diǎn)的基礎(chǔ)上添加新節(jié)點(diǎn),添加完成當(dāng)前節(jié)點(diǎn)位于棧頂
         *
         * @return index into mStateStack where entering needs to start
         */
        private final int moveTempStateStackToStateStack() {
            //startingIndex 表示mStateStack接受新狀態(tài)的其實(shí)位置,
            //不是每次都從0開始
            int startingIndex = mStateStackTopIndex + 1;
            //mTempStateStack個數(shù)
            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;
            }

            //invokeEnterMethods 會使用到這個變量
            //新狀態(tài)棧位置mStateStackTopIndex
            mStateStackTopIndex = j - 1;
            if (mDbg) {
                mSm.log("moveTempStackToStateStack: X mStateStackTop=" + mStateStackTopIndex
                        + ",startingIndex=" + startingIndex + ",Top="
                        + mStateStack[mStateStackTopIndex].state.getName());
            }
            return startingIndex;
        } 

當(dāng)狀態(tài)處理完畢,發(fā)送SM_INIT_CMD,Smhandler從消息隊(duì)列中取出消息,完成狀態(tài)機(jī)初始化工作

if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)
     && (mMsg.obj == mSmHandlerObj)) {
        /** Initial one time path. */
        //根據(jù)SM_INIT_CMD消息表明構(gòu)建任務(wù)完成,設(shè)置完成標(biāo)志,開始處理消息
        mIsConstructionCompleted = true;
        //循環(huán)調(diào)用mStateStack中enter方法并將狀態(tài)設(shè)為激活狀態(tài)
        invokeEnterMethods(0);
     }

將mIsConstructionCompleted標(biāo)記變量設(shè)置為true,表示完成初始化,調(diào)用invokeEnterMethods,將每個狀態(tài)設(shè)為激活狀態(tài),并調(diào)用enter()方法

/**
 * Invoke the enter method starting at the entering index to top of state stack
* 從stateStackEnteringIndex開始循環(huán)調(diào)用mStateStack中enter方法并將狀態(tài)設(shè)為激活狀態(tài)
*/
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 方法是進(jìn)入狀態(tài)的必要工作,enter方法執(zhí)行完,對應(yīng)狀態(tài)開始進(jìn)行消息處理 processMessage
    }

狀態(tài)處理

        /**
         * 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.
         *
         * 調(diào)用當(dāng)前狀態(tài)處理消息,
         *
         * 調(diào)整更新狀態(tài)棧stateStack的內(nèi)容
         */
        @Override
        public final void handleMessage(Message msg) {
            if (!mHasQuit) {
                if (mDbg) mSm.log("handleMessage: E msg.what=" + msg.what);

                /** Save the current message */
                mMsg = msg;

                /** State that processed the message */
                State msgProcessedState = null;
                //構(gòu)建初始化是否已經(jīng)完成
                if (mIsConstructionCompleted) {
                    //構(gòu)建完成,開始處理狀態(tài)
                    /** Normal path */
                    msgProcessedState = processMsg(msg);
                    //處理完成msgProcessedState,處理完了這個Message以后,將切換到哪個State
                } else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)
                        && (mMsg.obj == mSmHandlerObj)) {
                    /** Initial one time path. */
                    //根據(jù)SM_INIT_CMD消息表明構(gòu)建任務(wù)完成,設(shè)置完成標(biāo)志,開始處理消息
                    mIsConstructionCompleted = true;
                    //循環(huán)調(diào)用mStateStack中enter方法并將狀態(tài)設(shè)為激活狀態(tài)
                    invokeEnterMethods(0);
                } else {
                    throw new RuntimeException("StateMachine.handleMessage: "
                            + "The start method not called, received msg: " + msg);
                }

                //msg處理后,做狀態(tài)切換,更新mStateStack
                performTransitions(msgProcessedState, msg);

                // We need to check if mSm == null here as we could be quitting.
                if (mDbg && mSm != null) mSm.log("handleMessage: X");
    }
}

狀態(tài)機(jī)構(gòu)建完成,調(diào)用processMsg()處理該狀態(tài),狀態(tài)處理完畢,調(diào)用performTransitions完成狀態(tài)樹的更新

        /**
         * 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.
         *
         * 調(diào)用當(dāng)前狀態(tài)處理消息,如果當(dāng)前狀態(tài)沒有處理調(diào)用該狀態(tài)的父狀態(tài)處理,
         * 如果最后都沒有處理,調(diào)用unhandledMessage方法
         *
         * @return the state that processed the message 處理了該消息的狀態(tài)
         */
        private final State processMsg(Message msg) {
            //獲取棧頂狀態(tài),當(dāng)前所處的狀態(tài)
            StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
            if (mDbg) {
                mSm.log("processMsg: " + curStateInfo.state.getName());
            }

            if (isQuit(msg)) {
                //SM_QUIT_CMD消息,切換到mQuittingState狀態(tài)
                transitionTo(mQuittingState);
            } else {
                //調(diào)用當(dāng)前狀態(tài)機(jī)處理
                while (!curStateInfo.state.processMessage(msg)) {
                    /**
                     * Not processed
                     沒有處理調(diào)用父狀態(tài)處理
                     */
                    curStateInfo = curStateInfo.parentStateInfo;
                    if (curStateInfo == null) {
                        /**
                         * No parents left so it's not handled
                         */
                        mSm.unhandledMessage(msg);
                        break;
                    }
                    if (mDbg) {
                        mSm.log("processMsg: " + curStateInfo.state.getName());
                    }
                }
            }
            //返回最后成功處理了Message的那個狀態(tài),如果沒有,那么就是返回null
            return (curStateInfo != null) ? curStateInfo.state : null;
        }
  • 如果接受到是SM_QUIT_CMD消息,切換到mQuittingState狀態(tài),退出狀態(tài)機(jī)
  • 調(diào)用當(dāng)前狀態(tài)處理,如果當(dāng)前狀態(tài)沒有處理,沒有處理調(diào)用父狀態(tài)處理
  • 如果所有的狀態(tài)都沒有處理該消息,調(diào)用mSm.unhandledMessage

狀態(tài)樹切換



        /**
        * transition to destination state. Upon returning
        * from processMessage the current state's exit will
        * be executed and upon the next message arriving
        * destState.enter will be invoked.
        *
        * this function can also be called inside the enter function of the
        * previous transition target, but the behavior is undefined when it is
        * called mid-way through a previous transition (for example, calling this
        * in the enter() routine of a intermediate node when the current transition
        * target is one of the nodes descendants).
        *
        * @param destState will be the state that receives the next message.
        */
        protected final void transitionTo(IState destState) {
            mSmHandler.transitionTo(destState);
        }

        /**
         * Do any transitions
         *
         * performTransitions來檢查狀態(tài)切換,為狀態(tài)數(shù)跟新
         *
         * @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;

            /**
             * 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);
            }

            //mDestState,具體狀態(tài)調(diào)用transitionTo(State)時傳入的參數(shù)
            //具體狀態(tài)在重寫processMessage時,調(diào)用transitionTo(state)方法,設(shè)置下一步要切換的狀態(tài)
            State destState = mDestState;
            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.
                     *
                     * 獲取從destState到還沒有active的父節(jié)點(diǎn),
                     * mTempStateStack存儲是新的終止節(jié)點(diǎn)和
                     * 舊終止節(jié)點(diǎn)的公共節(jié)點(diǎn)與新的終止節(jié)點(diǎn)的一段狀態(tài)樹
                     */
                    StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
                    invokeExitMethods(commonStateInfo);

                    //stateStackEnteringIndex 需要調(diào)用enter方法的狀態(tài)在mStateStack中位置
                    int stateStackEnteringIndex = moveTempStateStackToStateStack();

                    //從stateStackEnteringIndex位置開始調(diào)用狀態(tài)棧中state的enter并將active設(shè)為true
                    invokeEnterMethods(stateStackEnteringIndex);

                    /**
                     * 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.
                     *
                     * 轉(zhuǎn)換新狀態(tài)后,將之前的延遲消息移動到消息隊(duì)列的頭部,使得延遲消息的處理早于其他消息
                     */
                    moveDeferredMessageAtFrontOfQueue();

                    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();
                }
            }
        }
  • 調(diào)用transitionTo轉(zhuǎn)換狀態(tài),在調(diào)用mSmHandler.transitionTo()設(shè)置目的狀態(tài),當(dāng)消息處理完畢后變調(diào)用performTransitions做真正的狀態(tài)調(diào)整,主要是調(diào)整狀態(tài)棧的節(jié)點(diǎn)信息
  • 根據(jù)新的目的節(jié)點(diǎn),調(diào)用setupTempStateStackWithStatesToEnter(),查找到根節(jié)點(diǎn)沒有被激活的狀態(tài),這些節(jié)點(diǎn)存儲在mTempStateStack中,并得到新目的節(jié)點(diǎn)和舊目的節(jié)點(diǎn)公共節(jié)點(diǎn)commonStateInfo
  • 根據(jù)commonStateInfo,調(diào)用invokeExitMethods(),將需要移除棧的節(jié)點(diǎn)的狀態(tài)設(shè)為false,并調(diào)用exit方法
  • 調(diào)用moveTempStateStackToStateStack將mTempStateStack節(jié)點(diǎn)反轉(zhuǎn)存儲到mStateStack中,這樣當(dāng)前目的節(jié)點(diǎn)位于棧頂,下次處理消息時直接調(diào)用當(dāng)前設(shè)置的目的節(jié)點(diǎn)
  • 調(diào)用invokeEnterMethods方法,將新添加的節(jié)點(diǎn)狀態(tài)設(shè)為true,并調(diào)用enter方法
  • 在切換狀態(tài)后,如果存在消息沒有處理,調(diào)用moveDeferredMessageAtFrontOfQueue將延遲消息存放在消息隊(duì)列的頭部

狀態(tài)機(jī)的退出

    /**
     * Quit the state machine after all currently queued up messages are processed.
     */
    protected final void quit() {
        // mSmHandler can be null if the state machine is already stopped.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.quit();
    }

調(diào)用SmHandler的quit方法


        /** @see StateMachine#quit() */
        private final void quit() {
            if (mDbg) mSm.log("quit:");
            sendMessage(obtainMessage(SM_QUIT_CMD, mSmHandlerObj));
        }

processMsg處理消息時判斷時退出消息,調(diào)用transitionTo(mQuittingState),切換到QuittingState狀態(tài),做狀態(tài)機(jī)退出工作

具體消息的處理

    //藍(lán)牙關(guān)閉狀態(tài)
    private class OffState extends State {
        @Override
        public void enter() {
            infoLog("Entering OffState");
        }

        @Override
        public boolean processMessage(Message msg) {
            AdapterService adapterService = mAdapterService;
            if (adapterService == null) {
                errorLog("Received message in OffState after cleanup: " + msg.what);
                return false;
            }

            debugLog("Current state: OFF, message: " + msg.what);

            switch(msg.what) {
                //初始狀態(tài)是OffState,由OffState處理藍(lán)牙開啟操作
               case BLE_TURN_ON:
                   //通知BluetoothmangerService藍(lán)牙正在開啟
                   notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_TURNING_ON);
                   mPendingCommandState.setBleTurningOn(true);
                   transitionTo(mPendingCommandState);
                   //發(fā)送延遲消息,檢測打開超時任務(wù)
                   sendMessageDelayed(BLE_START_TIMEOUT, BLE_START_TIMEOUT_DELAY);
                   //批量啟動 profile service
                   adapterService.BleOnProcessStart();
                   break;

               case USER_TURN_OFF:
                   //TODO: Handle case of service started and stopped without enable
                   break;

               default:
                   return false;
            }
            return true;
        }
    }

當(dāng)藍(lán)牙關(guān)閉狀態(tài)收到BLE_TURN_ON消息時,表示藍(lán)牙執(zhí)行打開操作,發(fā)出通知表示正在執(zhí)行打開操作,調(diào)用transitionTo將目的狀態(tài)切換到mPendingCommandState,由mPendingCommandState處理后續(xù)的狀態(tài),并開啟打開任務(wù)的超時檢測;調(diào)用BleOnProcessStart,啟動所需要的藍(lán)牙服務(wù);服務(wù)啟動后通過StateMachine的sendMessage()會發(fā)送BLE_STARTED消息,mSmHandler調(diào)用processMsg(),該消息由mPendingCommandState處理。

總結(jié)

StateMachine在初始化時會創(chuàng)建一個HandleThread,用來處理維護(hù)消息隊(duì)列。
通過addState方法創(chuàng)建一個層次狀體樹,所有這些節(jié)點(diǎn)將存儲在HashMap<State,StateInfo> mStateInfo中,
調(diào)用setInitialState方法設(shè)置初始狀態(tài);調(diào)用start方法開始創(chuàng)建狀態(tài)棧,使得初始狀態(tài)位于棧頂,這樣處理消息時,直接交給棧頂節(jié)點(diǎn)處理。狀態(tài)棧構(gòu)建完成將所有棧中的節(jié)點(diǎn)設(shè)為true,并執(zhí)行enter方法,表示狀態(tài)可以進(jìn)入工作。然后向狀態(tài)機(jī)發(fā)送SM_INIT_CMD消息,由狀態(tài)機(jī)處理該消息。如果狀態(tài)機(jī)構(gòu)建完成,這是消息由當(dāng)前的節(jié)點(diǎn)處理,如果當(dāng)前節(jié)點(diǎn)不能處理交由父節(jié)點(diǎn)處理,所有節(jié)點(diǎn)都不能處理處理,調(diào)用狀態(tài)機(jī)的unhandledMessage方法(這個方法一般由具體狀態(tài)機(jī)實(shí)現(xiàn)),消息處理了返回true,沒有處理返回false。
如果在處理消息時調(diào)用transitionTo設(shè)置新目的狀態(tài),消息處理完成后,performTransition方法會設(shè)置調(diào)整狀態(tài)棧的節(jié)點(diǎn)信息,這樣新的節(jié)點(diǎn)設(shè)置在棧頂,消息來消息時直接調(diào)用棧中取出,處理消息。
推出狀態(tài)機(jī)調(diào)用quit或quitNow,向狀態(tài)機(jī)發(fā)送SM_QUIT_CMD消息,處理后續(xù)的事情。

備注

源代碼使用androud_6.0.1_r1
注釋代碼

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,063評論 25 709
  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時芥藍(lán)閱讀 42,810評論 11 349
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,569評論 19 139
  • Java8張圖 11、字符串不變性 12、equals()方法、hashCode()方法的區(qū)別 13、...
    Miley_MOJIE閱讀 3,899評論 0 11
  • 看著身邊的小伙伴一個個找到新的工作機(jī)會,你是不是也想試水市場。還在糾結(jié)的同學(xué),可以嘗試回答下面的兩個問題: 1. ...
    FuQiang閱讀 773評論 0 6

友情鏈接更多精彩內(nèi)容