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/
- StateMachine 状态机原理
- StateMachine状态机
- statemachine状态机
- android状态机机制StateMachine
- android状态机机制StateMachine
- android状态机statemachine详解
- Mina状态机StateMachine
- Mina状态机StateMachine()
- android状态机statemachine详解
- android状态机机制StateMachine
- android状态机机制StateMachine
- Quick StateMachine状态机
- android状态机statemachine详解
- android状态机statemachine详解
- android状态机statemachine详解
- spring Spring StateMachine状态机
- andorid状态机StateMachine
- StateMachine状态机初识
- 9. Palindrome Number
- 各大公司广泛使用的在线学习算法FTRL详解
- webpack笔记-----编辑webpack.config.js文件
- hdu 3018 欧拉回路
- python3 汉字转十六进制unicode
- StateMachine 状态机原理
- nyoj 82 迷宫寻宝(一)【dfs】
- CNNdroid+Caffe使用攻略
- python学习01--装饰器
- C++中的类模板详细讲述
- LMAX高并发系统架构
- java将数据写入xml与读取xml文件数据
- 安卓的事件分发的总结
- Unity3d 拖拽物体