前言:最近写了几篇wifi状态机相关的博客,但是状态转换方面一直是囫囵吞枣,感觉代码对的上流程就开始梳理了,没有真正关注过状态切换和消息处理流程,现在梳理一下。
其他的不说,先放个WifiController在WiFi打开时打印的log,以对状态机消息处理及状态切换流程有个直观的认识。
//StaDisabledWithScanState开始处理wifi打开流程所下发的CMD_WIFI_TOGGLED消息
06-25 18:53:28.518 835 982 D WifiController: StaDisabledWithScanState CMD_WIFI_TOGGLED{ when=-1ms what=155656 target=com.android.internal.util.StateMachine$SmHandler }
//StaDisabledWithScanState处理wifi打开流程所下发的CMD_WIFI_TOGGLED消息过程中状态变迁到了DeviceActiveState,而StaEnabledState是DeviceActiveState的父类状态,会依次进入父类-子类状态的enter方法
06-25 18:53:28.518 835 982 D WifiController: Enter DeviceActiveState mScreenOff=false
对照上面log抽象出来有2步
PS:exit log没打印出来,尴尬
下面以WifiController从初始化到处理CMD_WIFI_TOGGLED消息的过程为模板来梳理一下。
流程:ApStaDisabledState.exit()-->StaEnabledState.enter()-->DeviceActiveState.enter()
StateMachine维护着一个栈式结构,每进入一个状态
1)先计算出“现状态”和“要进入状态”往父节点的状态交汇点,比如上面是DefaultState
2)从现状态依次出栈,调用exit方法,直到交汇点(交汇点不调用)
3)把进入的状态(从父状态到子状态依次,不重复)压入栈内,再通过栈顶指针来依次执行此状态的enter( )方法。并且从当前状态一直到根状态的路径上每个状态都为被激活状态。active属性对应于是否激活。
之前在四十九)Android O Wifi中的状态模式-WifiStateMachine的状态初始化 是从WifiStateMachine初始化梳理的,WifiController的初始化还没梳理过,正好这边一起梳理下。
WifiController也是继承的StateMachine,既然是状态机那就有如下三部曲作为初始化
前两步在WifiController的构造函数里完成的
WifiController(Context context, WifiStateMachine wsm, WifiSettingsStore wss,
WifiLockManager wifiLockManager, Looper looper, FrameworkFacade f) {
super(TAG, looper);
mFacade = f;
mContext = context;
mWifiStateMachine = wsm;
mSettingsStore = wss;
mWifiLockManager = wifiLockManager;
mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
mIdleIntent = mFacade.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
addState(mDefaultState);
addState(mApStaDisabledState, mDefaultState);
addState(mStaEnabledState, mDefaultState);
addState(mDeviceActiveState, mStaEnabledState);
addState(mDeviceInactiveState, mStaEnabledState);
addState(mScanOnlyLockHeldState, mDeviceInactiveState);
addState(mFullLockHeldState, mDeviceInactiveState);
addState(mFullHighPerfLockHeldState, mDeviceInactiveState);
addState(mNoLockHeldState, mDeviceInactiveState);
addState(mStaDisabledWithScanState, mDefaultState);
addState(mApEnabledState, mDefaultState);
addState(mEcmState, mDefaultState);
boolean isAirplaneModeOn = mSettingsStore.isAirplaneModeOn();
boolean isWifiEnabled = mSettingsStore.isWifiToggleEnabled();
boolean isScanningAlwaysAvailable = mSettingsStore.isScanAlwaysAvailable();
log("isAirplaneModeOn = " + isAirplaneModeOn +
", isWifiEnabled = " + isWifiEnabled +
", isScanningAvailable = " + isScanningAlwaysAvailable);
if (isScanningAlwaysAvailable) {
setInitialState(mStaDisabledWithScanState);
} else {
setInitialState(mApStaDisabledState);
}
...
}
主要是start这步是和流程结合比较紧密的
之前说过WifiServiceImpl是在WifiService内部初始化的
public final class WifiService extends SystemService {
private static final String TAG = "WifiService";
final WifiServiceImpl mImpl;
public WifiService(Context context) {
super(context);
mImpl = new WifiServiceImpl(context, new WifiInjector(context), new WifiAsyncChannel(TAG));
}
@Override
public void onStart() {
Log.i(TAG, "Registering " + Context.WIFI_SERVICE);
publishBinderService(Context.WIFI_SERVICE, mImpl);
}
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
mImpl.checkAndStartWifi();
}
}
@Override
public void onSwitchUser(int userId) {
mImpl.handleUserSwitch(userId);
}
@Override
public void onUnlockUser(int userId) {
mImpl.handleUserUnlock(userId);
}
@Override
public void onStopUser(int userId) {
mImpl.handleUserStop(userId);
}
}
而WifiServiceImpl初始化的构造函数里呢通过WifiInjector获取了包括WifiStateMachine和WifiController在内的很多wifi变量
mWifiController = mWifiInjector.getWifiController();
其实WifiStateMachine和WifiController在内的很多wifi变量的初始化是放在WifiInjector的构造函数里完成的,WifiInjector的创建如上可见是在WifiService的构造方法里完成的。
mWifiStateMachine = new WifiStateMachine(mContext, mFrameworkFacade,
wifiStateMachineLooper, UserManager.get(mContext),
this, mBackupManagerProxy, mCountryCode, mWifiNative,
new WrongPasswordNotifier(mContext, mFrameworkFacade));
mWifiController = new WifiController(mContext, mWifiStateMachine, mSettingsStore,
mLockManager, mWifiServiceHandlerThread.getLooper(), mFrameworkFacade);
而WifiController的start方法是由WifiService的onBootPhase方法调用WifiServiceImpl的checkAndStartWifi调用的:
/**
* Check if we are ready to start wifi.
*
* First check if we will be restarting system services to decrypt the device. If the device is
* not encrypted, check if Wi-Fi needs to be enabled and start if needed
*
* This function is used only at boot time.
*/
public void checkAndStartWifi() {
...
mWifiController.start();
...
}
好了,WifiController简单的启动看完了,简要说来就是WifiService完成了WifiController的初始化,不再往上深究了。
这部分逻辑其实和四十九)Android O Wifi中的状态模式-WifiStateMachine的状态初始化 是一样的,但是具体实现不同
addState过程在之前的WifiStateMachine里讲过了,其实就是构建一个树状结构:
setInitialState过程也没啥讲的,就是设置一个初始化变量,即WifiController的初始状态为ApStaDisabledState(暂不考虑isScanningAlwaysAvailable为true)。
/**
* 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.
*/
public final void setInitialState(State initialState) {
mSmHandler.setInitialState(initialState);
}
/** @see StateMachine#setInitialState(State) */
private final void setInitialState(State initialState) {
if (mDbg) mSm.log("setInitialState: initialState=" + initialState.getName());
mInitialState = initialState;
}
主要看下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;
/** 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);
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));
if (mDbg) mSm.log("completeConstruction: X");
}
setupInitialStateStack()是初始化两个数组mStateStack和mTempStateStack
/**
* 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;
}
// Empty the StateStack
mStateStackTopIndex = -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;
}
mStateStackTopIndex = j - 1;
if (mDbg) {
mSm.log("moveTempStackToStateStack: X mStateStackTop=" + mStateStackTopIndex
+ ",startingIndex=" + startingIndex + ",Top="
+ mStateStack[mStateStackTopIndex].state.getName());
}
return startingIndex;
}
所以这边初始化后mStateStack和mTempStateStack情况如下图所示
然后发出初始化消息
/** Sending SM_INIT_CMD message to invoke enter methods asynchronously */
sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj));
StateMachine的内部类SMHander开始处理
/**
* 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 || (mMsg.what == SM_QUIT_CMD)) {
/** 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);
// 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);
}
}
}
mIsConstructionCompleted一开始是false,毕竟还没初始化,默认是false。走到invokeEnterMethod里
/**
* Invoke the enter method starting at the entering index to top of state stack
*/
private final void invokeEnterMethods(int stateStackEnteringIndex) {
for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
if (stateStackEnteringIndex == mStateStackTopIndex) {
// Last enter state for transition
mTransitionInProgress = false;
}
if (mDbg) mSm.log("invokeEnterMethods: " + mStateStack[i].state.getName());
mStateStack[i].state.enter();
mStateStack[i].active = true;
}
mTransitionInProgress = false; // ensure flag set to false if no methods called
}
这边其实就是遍历mStateStack数组,逐个走enter方法和将active设为true。可以看到是先父类状态的enter方法,然后子类的enter方法。
下面的performTransitions方法作为状态变化时的关键方法现在还起不到作用,因为destState是null。
/**
* 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;
/**
* 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);
}
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.
*/
StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
// flag is cleared in invokeEnterMethods before entering the target state
mTransitionInProgress = true;
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();
}
}
}
/**
* 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 || (mMsg.what == SM_QUIT_CMD)) {
/** 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);
// 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和onPostHandleMessage让我想起来AsyncTask,但是它们的实现都是空的,不用管。
如上代码标红的2处对应于一开始说的
先看下经过初始化mIsConstructionCompleted变为true,所以走进了第一步
msgProcessedState = 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.
* @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);
} 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;
}
if (mDbg) {
mSm.log("processMsg: " + curStateInfo.state.getName());
}
}
}
return (curStateInfo != null) ? curStateInfo.state : null;
}
处理消息的流程一开始说了“
”这里就是对应该逻辑的。
像ApStaDisabledState处理CMD_WIFI_TOGGLED过程中会调用
transitionTo(mDeviceActiveState);
public final void transitionTo(IState destState) {
mSmHandler.transitionTo(destState);
}
/** @see StateMachine#transitionTo(IState) */
private final void transitionTo(IState destState) {
if (mTransitionInProgress) {
Log.wtf(mSm.mName, "transitionTo called while transition already in progress to " +
mDestState + ", new target state=" + destState);
}
mDestState = (State) destState;
if (mDbg) mSm.log("transitionTo: destState=" + mDestState.getName());
}
mDestState变为了mDeviceActiveState
这就使得handleMessage中的performTransitions(msgProcessedState, msg)有了用武之地,这就是第二步。
/**
* 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;
/**
* 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);
}
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.
*/
StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
// flag is cleared in invokeEnterMethods before entering the target state
mTransitionInProgress = true;
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();
}
}
}
看第一次while循环
/**
* Setup the mTempStateStack with the states we are going to enter.
*
* This is found by searching up the destState's ancestors for a
* state that is already active i.e. StateInfo.active == true.
* The destStae and all of its inactive parents will be on the
* TempStateStack as the list of states to enter.
*
* @return StateInfo of the common ancestor for the destState and
* current state or null if there is no common parent.
*/
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);
if (mDbg) {
mSm.log("setupTempStateStackWithStatesToEnter: X mTempStateStackCount="
+ mTempStateStackCount + ",curStateInfo: " + curStateInfo);
}
return curStateInfo;
}
mTempStackStack变为
这边设置了一个标志位
// flag is cleared in invokeEnterMethods before entering the target state
mTransitionInProgress = true;
然后继续
invokeExitMethods(commonStateInfo);
/**
* 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
先调用ApStaDisabledState的exit方法,将active设为false;接着由于commonStateInfo为mDefaultState,不继续往下调用exit方法了,这时候mStateStackTopIndex为0。
继续往下看
int stateStackEnteringIndex = 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;
}
mStateStackTopIndex = j - 1;
if (mDbg) {
mSm.log("moveTempStackToStateStack: X mStateStackTop=" + mStateStackTopIndex
+ ",startingIndex=" + startingIndex + ",Top="
+ mStateStack[mStateStackTopIndex].state.getName());
}
return startingIndex;
}
倒序后
返回的startingIndex为1,mStateStackTopIndex为2,即继续依次调用StaEnabledState和DeviceActiveState的enter方法,并将其active设为true。
/**
* Invoke the enter method starting at the entering index to top of state stack
*/
private final void invokeEnterMethods(int stateStackEnteringIndex) {
for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
if (stateStackEnteringIndex == mStateStackTopIndex) {
// Last enter state for transition
mTransitionInProgress = false;
}
if (mDbg) mSm.log("invokeEnterMethods: " + mStateStack[i].state.getName());
mStateStack[i].state.enter();
mStateStack[i].active = true;
}
mTransitionInProgress = false; // ensure flag set to false if no methods called
}
后面将延迟消息放在队列前面处理,以及如果mDestState在这过程中又变了,那么while循环第二次。
/**
* 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;
}
这里对应上面分析的第二步“若当前状态处理消息过程中涉及状态变化,则依次进入退出状态的exit方法和变化状态的enter方法(有条件地考虑是否调用父类的exit和enter方法,具体查看2.3.2节,,取决于active属性)”。