• Android stateMachine分析


    StateMachine与State模式的详细介绍可以参考文章:Android学习 StateMachine与State模式

    下面是我对于StateMachine的理解:

    先了解下消息处理。看下StateMachine::sendMessage方法。

    不管BT/Wifi中,都有继承StateMachine的子类(BluetoothAdapterStateMachine.java/WifiStateMachine.java),在某些类中,会创建这些类的对象,当需要发送消息时,会调用它们的sendMessage方法,即调用父类StateMachine的sendMessage方法。

        /**
         * Enqueue a message to this state machine.
         */
        public final void sendMessage(int what) {
            // mSmHandler can be null if the state machine has quit.
            if (mSmHandler == null) return;
    
            mSmHandler.sendMessage(obtainMessage(what));
        }
    
        /**
         * Enqueue a message to this state machine.
         */
        public final void sendMessage(int what, Object obj) {
            // mSmHandler can be null if the state machine has quit.
            if (mSmHandler == null) return;
    
            mSmHandler.sendMessage(obtainMessage(what,obj));
        }
    
        /**
         * Enqueue a message to this state machine.
         */
        public final void sendMessage(Message msg) {
            // mSmHandler can be null if the state machine has quit.
            if (mSmHandler == null) return;
    
            mSmHandler.sendMessage(msg);
        }

    从sendMessage方法中可以看到,实际上是调用了StateMachine::SmHandler::sendMessage方法,该类没有实现该方法,所以会调用父类Handler::sendMessage方法,然后会调用StateMachine::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 (mDbg) Log.d(TAG, "handleMessage: E msg.what=" + msg.what);
    
                /** Save the current message */
                mMsg = msg;
    
                if (mIsConstructionCompleted) {
                    /** Normal path */
                    processMsg(msg); //1
                } 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(); //2
    
                if (mDbg) Log.d(TAG, "handleMessage: X");
            }

     该方法中有两个重要的方法:

    1.processMsg(msg);

            /**
             * 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.
             */
            private final void processMsg(Message msg) {
                StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
                if (mDbg) {
                    Log.d(TAG, "processMsg: " + curStateInfo.state.getName());
                }
                while (!curStateInfo.state.processMessage(msg)) {
                    /**
                     * Not processed
                     */
                    curStateInfo = curStateInfo.parentStateInfo;
                    if (curStateInfo == null) {
                        /**
                         * No parents left so it's not handled
                         */
                        mSm.unhandledMessage(msg);
                        if (isQuit(msg)) {
                            transitionTo(mQuittingState);
                        }
                        break;
                    }
                    if (mDbg) {
                        Log.d(TAG, "processMsg: " + curStateInfo.state.getName());
                    }
                }
    
                /**
                 * Record that we processed the message
                 */
                if (mSm.recordProcessedMessage(msg)) {
                    if (curStateInfo != null) {
                        State orgState = mStateStack[mStateStackTopIndex].state;
                        mProcessedMessages.add(msg, mSm.getMessageInfo(msg), curStateInfo.state,
                                orgState);
                    } else {
                        mProcessedMessages.add(msg, mSm.getMessageInfo(msg), null, null);
                    }
                }
            }

    这个方法中有一个while循环,看下条件:curStateInfo.state.processMessage(msg),即调用当前状态(State具体的子类)的processMessage方法。在具体实现的State子类中,在processMessage方法中,在具体的case处理完message后,会返回true 或 false(true的话会使得上述代码中的while循环退出,即该消息不上传给父状态处理,自己处理完就好了;false的话,就是再上传给父状态处理)。

    2.performTransitions();

            /**
             * Do any transitions
             */
            private void performTransitions() {
                /**
                 * 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 destState = null;
                while (mDestState != null) {
                    if (mDbg) Log.d(TAG, "handleMessage: new destination call exit");
    
                    /**
                     * Save mDestState locally and set to null
                     * to know if enter/exit use transitionTo.
                     */
                    destState = mDestState;
                    mDestState = null;
    
                    /**
                     * 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);
                    invokeExitMethods(commonStateInfo);
                    int stateStackEnteringIndex = moveTempStateStackToStateStack();
                    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.
                     */
                    moveDeferredMessageAtFrontOfQueue();
                }
    
                /**
                 * After processing all transitions check and
                 * see if the last transition was to quit or halt.
                 */
                if (destState != null) {
                    if (destState == mQuittingState) {
                        cleanupAfterQuitting();
    
                    } else if (destState == mHaltingState) {
                        /**
                         * Call halting() if we've transitioned to the halting
                         * state. All subsequent messages will be processed in
                         * in the halting state which invokes haltedProcessMessage(msg);
                         */
                        mSm.halting();
                    }
                }
            }

     这个方法主要是完成:

    1.当前状态的切换,

    2.更新状态栈。

    比如状态已经通过addState方法添加完毕,形成了树形结构。当前状态是S4,现在要切换到S5。performTransitions方法中会完成一项功能:pop S4 S1,push S2 S5。

     

  • 相关阅读:
    报警界面
    09 | 基础篇:怎么理解Linux软中断?
    08 | 案例篇:系统中出现大量不可中断进程和僵尸进程怎么办?(下)
    07 | 案例篇:系统中出现大量不可中断进程和僵尸进程怎么办?(上)
    06 | 案例篇:系统的 CPU 使用率很高,但为啥却找不到高 CPU 的应用?
    05 | 基础篇:某个应用的CPU使用率居然达到100%,我该怎么办?
    scrapy相关:splash安装 A javascript rendering service 渲染
    MongoDB 及 scrapy 应用
    scrapy相关 通过设置 FEED_EXPORT_ENCODING 解决 unicode 中文写入json文件出现`uXXXX`
    wb 黑名单批量操作
  • 原文地址:https://www.cnblogs.com/chenbin7/p/3120077.html
Copyright © 2020-2023  润新知