StateMachine有自己单独的工作线程,

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

StateMachine中一个很重要的角色就是SmHandler,SmHandler在构造伊始就添加了两个状态:

private SmHandler(Looper looper, StateMachine sm) {    super(looper);    mSm = sm;    addState(mHaltingState, null);    addState(mQuittingState, null);}

这两个状态意思是整个状态机的停止状态和退出状态,如下:

/** * State entered when transitionToHaltingState is called. */private class HaltingState extends State {    @Override    public boolean processMessage(Message msg) {        mSm.haltedProcessMessage(msg);        return true;    }}/** * State entered when a valid quit message is handled. */private class QuittingState extends State {    @Override    public boolean processMessage(Message msg) {        return NOT_HANDLED;    }}

可见这两个状态都是继承自State,这个状态机中的状态都是用State表示的,如下:

public class State implements IState {    protected State() {    }    @Override    public void enter() {    }    @Override    public void exit() {    }    @Override    public boolean processMessage(Message msg) {        return false;    }    @Override    public String getName() {        String name = getClass().getName();        int lastDollar = name.lastIndexOf('$');        return name.substring(lastDollar + 1);    }}

看起来很简单,主要就三个函数,enter表示进入状态的回调,exit表示离开状态的回调,processMessage表示收到消息的回调。

再来看State是如何添加到状态机中的,如下:

/** The map of all of the states in the state machine */private HashMap mStateInfo = new HashMap();private final StateInfo addState(State state, State parent) {    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);        }    }    StateInfo stateInfo = mStateInfo.get(state);    if (stateInfo == null) {        stateInfo = new StateInfo();        mStateInfo.put(state, stateInfo);    }    // 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");    }    stateInfo.state = state;    stateInfo.parentStateInfo = parentStateInfo;    stateInfo.active = false;    return stateInfo;}

可见每个State都只能有最多一个parent,或者没有parent,那这种带层级的State状态机有什么意义呢?因为以往我们认为的状态机都是若干完全独立的状态之间互相切换,不会有状态层级关系的,接下来我们就来看看这种层级关系的奥秘,从状态切换入手:

private final void transitionTo(IState destState) {    mDestState = (State) destState;}

只是设置了一个变量,不免让人有些失望,我们看这个变量在哪引用的,结果是在performTransitions中,而这个函数是在SmHandler的handleMessage中:

/** true if construction of the state machine has not been completed */private boolean mIsConstructionCompleted;@Overridepublic final void handleMessage(Message msg) {    if (!mHasQuit) {        /** Save the current message */        mMsg = msg;        /** State that processed the message */        State msgProcessedState = null;        if (mIsConstructionCompleted) {            /** Normal path */            msgProcessedState = processMsg(msg);        } 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);    }}

这个mHasQuit从字面意思上就是状态机quit了,状态切换到QuitState时整个状态机就要destroy了,这时候再发消息也不会处理了。再看mIsConstructionCompleted,这个字面意思是状态机的初始化构造是否结束了,用到的地方也就是handleMessage中,而构造指令就是SM_INIT_CMD,发出指令的地方在状态机启动的时候,如下:

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();}

我们参考AdapterState状态机,如下:

public static AdapterState make(AdapterService service, AdapterProperties adapterProperties) {    Log.d(TAG, "make() - Creating AdapterState");    AdapterState as = new AdapterState(service, adapterProperties);    as.start();    return as;}

就是创建好状态机之后调用其start函数启动状态机。我们接下来看看start函数中completeConstruction的实现,如下:

private final void completeConstruction() {    /**     * 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;        }    }    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));}

这里首先遍历所有的状态,算出最大的深度,然后初始化状态栈mStateStack和mTempStateStack,再调用setupInitialStateStack,最后才发送了SM_INIT_CMD到消息队列的头。

状态机的切换中非常重要的角色就是这个状态栈了,所以我们要重点关注状态栈的初始化。不过这里还是先分析SM_INIT_CMD,发消息的时候还带上了mSmHandlerObj,这个东西就是一个普通的Object,每次状态机自身发的消息都会带上这个Object以区分是外面的消息还是状态机自身的消息,比如关于INIT和QUIT都会带上这个Object。在handleMessage中收到SM_INIT_CMD后会给mIsConstructionCompleted置为true,表示初始化过了,然后调用invokeEnterMethods(0),如下:

private final void invokeEnterMethods(int stateStackEnteringIndex) {    for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {        mStateStack[i].state.enter();        mStateStack[i].active = true;    }}

这个函数会从stateStackEnteringIndex到mStateStackTopIndex遍历调用enter函数,这个mStateStackTopIndex是什么呢?要搞清楚这个问题我们就得回到setupInitialStateStack函数了。

private final void setupInitialStateStack() {    StateInfo curStateInfo = mStateInfo.get(mInitialState);    for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) {        mTempStateStack[mTempStateStackCount] = curStateInfo;        curStateInfo = curStateInfo.parentStateInfo;    }    // Empty the StateStack    mStateStackTopIndex = -1;    moveTempStateStackToStateStack();}

这里从initial state开始遍历其父state一直到头,遍历路径记录在mTempStateStack中,而将StateStack栈顶index置为-1,然后moveTempStateStackToStateStack。

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;}

这个函数相当于将TempStateStack倒序copy到StateStack中。在TempStateStack中先入栈的是底层的状态,后入栈的是顶层的状态,而StateStack刚好相反,先入栈的是顶层parent状态,后入栈的是底层状态。现在我们回到invokeEnterMethods(0),这里会从StateStack的0开始到mStateStackTopIndex调用enter,也就是从状态机的初始状态的最顶层parent层层往下调到最底层状态的enter。

总结一下,状态机初始化时会先addState,然后设置好initial state,然后start,在start中初始化StateStack,将initial state从祖先开始依次入栈,然后再从祖先开始依次调用他们的enter回调。

我们再回到handleMessage,在invokeEnterMethods之后还调用了performTransitions(msgProcessedState, msg); 这个是检查状态切换的,如果设置过mDestState则这里要切换状态了:

private void performTransitions(State msgProcessedState, Message msg) {    State destState = mDestState;    if (destState != null) {        /**         * Process the transitions including transitions in the enter/exit methods         */        while (true) {            /**             * 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();            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();        }    }}

由于是初始化,所以msgProcessedState为null,而且mDestState也为null,所以这里其实什么也没有做。再回到handleMessage,如果是初始化之后则会调processMsg,如下

private final State processMsg(Message msg) {    StateInfo curStateInfo = mStateStack[mStateStackTopIndex];    if (isQuit(msg)) {        transitionTo(mQuittingState);    } else {        while (!curStateInfo.state.processMessage(msg)) {            /**             * Not processed             */            curStateInfo = curStateInfo.parentStateInfo;            if (curStateInfo == null) {                /**                 * No parents left so it's not handled                 */                mSm.unhandledMessage(msg);                break;            }        }    }    return (curStateInfo != null) ? curStateInfo.state : null;}

从状态栈中取出栈顶状态,将msg交给该state处理,如果处理了返回true则直接返回当前处理的state,否则交给父state处理,如果一直没有哪个state可以处理的话就调用SmHandler的unhandledMessage。

从processMsg返回到handleMessage后,还会调用performTransitions,不过可以看到如果mDestState为空则什么也不做。而mDestState是调transitionTo设置的,所以如果是单纯的发消息不会涉及状态的切换。

通常transitionState都是在某个state的processMsg中,这样在processMsg返回后继续调performTransitions时就会检查切换状态了。

不过注意的是切换状态会依次将当前状态栈出栈并将新状态链入栈,不过如果两者有共同的祖先结点,那祖先结点就没必要折腾了,只是下面不同的子状态才exit。我们分析performTransitions函数,首先通过setupTempStateStackWithStatesToEnter找到最低公共祖先,这里面就是从目标state开始往上遍历直到发现state是active为止,因为当前state的链上肯定都是active的。

接下来从当前状态开始调用exit直到最低公共祖先,注意不包括这个祖先,路上的state的active都标为false。

我们总结一下,当调enter的时候是从上往下,调exit的时候是从下往上,处理msg的时候也是从下往上。不过也可以理解,初始化的时候是先从上开始,退出的时候是反着来。处理消息也是先让下处理,处理不好才往上走。

更多相关文章

  1. Android(安卓)动画之RotateAnimation应用详解
  2. android获取手机电话信息
  3. Android程序中输入法弹出的时候如何不遮挡输入,与布局相配
  4. android 系统定制的小技巧
  5. Android判断是Wifi还是4G网络代码
  6. Android四方形输入框、密码框
  7. 获取手机屏幕大小(DisplayMetrics类取得画面宽高)
  8. Android 监听 USB 接口的插拔状态

随机推荐

  1. android ui篇 自己写界面
  2. Android(安卓)O 8.0及其以上系统的通知(N
  3. android 窗口背景透明方法
  4. Google操作系统是经典骗局?
  5. android ViewPager动态加载问题
  6. Android(安卓)开发学习手记(三):关于PullToR
  7. Android程序退出彻底关闭进程的方法
  8. Android(安卓)Handler 泄漏
  9. 手机rom的那些坑
  10. Android使用外部字体