/** * Constructor creates a StateMachine using the looper. * * @param name of the state machine */ protectedStateMachine(String name, Looper looper){ initStateMachine(name, looper); }
/** * Constructor creates a StateMachine using the handler. * * @param name of the state machine */ protectedStateMachine(String name, Handler handler){ initStateMachine(name, handler.getLooper()); }
/** * Initialize. * * @param looper for this state machine * @param name of the state machine */ privatevoidinitStateMachine(String name, Looper looper){ mName = name; mSmHandler = new SmHandler(looper, this); }
StateMachine::addState(State state, State parent)
-> SmHandler::addState(State state, State parent)
添加 State: State 保存在 HashMap<State, StateInfo> mStateInfo
StateInfo : 保存 State , parentStateInfo 还有 active 标志位
privatefinal 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)) { thrownew RuntimeException("state already added"); } stateInfo.state = state; stateInfo.parentStateInfo = parentStateInfo; stateInfo.active = false; if (mDbg) mSm.log("addStateInternal: X stateInfo: " + stateInfo); return stateInfo; }
/** State that processed the message */ State msgProcessedState = null; if (mIsConstructionCompleted) { /** Normal path */ msgProcessedState = processMsg(msg); } ... performTransitions(msgProcessedState, msg); /** onPostHandleMessage **/ ... }
SmHandler::processMsg(Message msg)
把消息交给当前 State 处理 if NOT_HANDLED -> StateInfo.parentState.state.processMessage(msg) -> SmHandler::unhandledMessage(msg)
privatevoidperformTransitions(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); } } elseif (recordLogMsg) { /** Record message */ mLogRecords.add(mSm, mMsg, mSm.getLogRecString(mMsg), msgProcessedState, orgState, mDestState); } 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(); } elseif (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(); } } }
privatefinal 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);