1. 案例
案例:我們常見的汽車亿胸,我們可以使用它行駛坯钦,也可以將它停止在路邊预皇。當(dāng)它在行駛的過程中,需要不斷的檢測(cè)油量婉刀,一旦油量不足的時(shí)候吟温,就將陷入停止?fàn)顟B(tài)。而停止在路邊的汽車突颊,需要點(diǎn)火啟動(dòng)鲁豪,此時(shí)將檢測(cè)車中的油量,當(dāng)油量不足的時(shí)候律秃,汽車就需要去加油站加油爬橡。
當(dāng)我們對(duì)汽車的狀態(tài)和行為進(jìn)行抽象,汽車的狀態(tài)可以有 :
- 停車 STOP
- 行駛 RUN
- 檢測(cè)油量 CHECK_OIL
- 加油 ADDING_OIL
而我們可以對(duì)汽車的操作可以是:
- 停車 ACTION_STOP
- 行駛 ACTION_RUN
- 加油 ACTION_ADD_OIL
我們建立一個(gè)二維表棒动,將狀態(tài)和可操作的行為組合在一起:
2. HSM
我們通過這個(gè)狀態(tài)表構(gòu)建我們的狀態(tài)引用關(guān)系模型:
這幅狀態(tài)圖實(shí)際上一個(gè)相對(duì)復(fù)雜的網(wǎng)狀圖形糙申,當(dāng)構(gòu)建一個(gè)更為復(fù)雜的系統(tǒng)的時(shí)候,這種網(wǎng)狀圖將會(huì)以成倍的復(fù)雜性遞增船惨。為了解決這個(gè)問題郭宝,我們需要將這種網(wǎng)狀的狀態(tài)機(jī)轉(zhuǎn)化為一個(gè)樹狀的層次狀態(tài)機(jī),也叫 HSM (Hierarchical State Machine)掷漱。我們可以將上述的狀態(tài)模型轉(zhuǎn)化為:
這張圖里粘室,將 STOP
作為根節(jié)點(diǎn),從層次上作為其他狀態(tài)節(jié)點(diǎn)的父節(jié)點(diǎn)卜范。
-
STOP
作為初始狀態(tài) - 發(fā)生了
ACTION_ADD_OIL
動(dòng)作衔统,STOP
狀態(tài)就變成了ADDING_OIL
狀態(tài) - 當(dāng)
ADDING_OIL
結(jié)束,發(fā)生了ACTION_RUN
動(dòng)作海雪,就需要彈出ADDING_OIL
狀態(tài) 锦爵,傳入到CHECK_OIL
,然后傳入RUN
狀態(tài)奥裸。
3. [StateMachine] 初始化
StateMachine
是 Android
系統(tǒng)提供的 HSM
狀態(tài)機(jī)的實(shí)現(xiàn),它的源碼在包com.android.internal.util
下险掀。StateMachine
提供了三個(gè)構(gòu)造方法,但這三個(gè)方法大同小異:
protected StateMachine(String name) {
mSmThread = new HandlerThread(name);
mSmThread.start();
Looper looper = mSmThread.getLooper();
initStateMachine(name, looper);
}
構(gòu)造器調(diào)用 initStateMachine
函數(shù),這個(gè)函數(shù)需要傳入了一個(gè) Looper
對(duì)象湾宙,StateMachine
對(duì)象所有的操作都需要在這個(gè) Looper
所在的線程中運(yùn)行樟氢。而之間的通訊是通過 SmHandler
對(duì)象傳遞。
private void initStateMachine(String name, Looper looper) {
mName = name;
mSmHandler = new SmHandler(looper, this);
}
上面我們說了侠鳄,StateMachine
是 HSM
狀態(tài)機(jī)埠啃,構(gòu)造它的時(shí)候,需要指定它的層次關(guān)系伟恶,這需要調(diào)用 addState
函數(shù)碴开,這個(gè)函數(shù)有兩個(gè)參數(shù),第第二個(gè)參數(shù)代表的是第一個(gè)參數(shù)的父節(jié)點(diǎn):
protected final void addState(State state, State parent) {
mSmHandler.addState(state, parent);
}
而根節(jié)點(diǎn),又稱為初始狀態(tài)節(jié)點(diǎn)潦牛,需要通過 setInitialState
函數(shù)指定:
protected final void setInitialState(State initialState) {
mSmHandler.setInitialState(initialState);
}
這里眶掌,不論設(shè)置什么樣的節(jié)點(diǎn),都需要通過 mSmHandler
對(duì)象設(shè)置,比如巴碗,當(dāng)通過調(diào)用 StateMachine.addState
添加節(jié)點(diǎn)的時(shí)候朴爬,需要調(diào)用到 SmHandler.addState
函數(shù):
//code SmHandler
private final StateInfo addState(State state, State parent) {
if (mDbg) {
//debug開關(guān)可以通過 StateMachine.setDbg接口設(shè)置打開
mSm.log("addStateInternal: E state=" + state.getName() + ",parent="
+ ((parent == null) ? "" : parent.getName()));
}
StateInfo parentStateInfo = null;
// StateInfo 表示在 HSM 樹中的狀態(tài)節(jié)點(diǎn)
if (parent != null) {
parentStateInfo = mStateInfo.get(parent);
//mStateInfo 是一個(gè)hashmap對(duì)象
if (parentStateInfo == null) {
//當(dāng)父節(jié)點(diǎn)不存在的時(shí)候,添加該節(jié)點(diǎn)
// Recursively add our parent as it's not been added yet.
parentStateInfo = addState(parent, null);
}
}
StateInfo stateInfo = mStateInfo.get(state);
//通過狀態(tài)構(gòu)建一個(gè)狀態(tài)節(jié)點(diǎn)
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)) {
//不允許一個(gè)節(jié)點(diǎn)存在兩個(gè)父節(jié)點(diǎn)
throw new RuntimeException("state already added");
}
stateInfo.state = state;
stateInfo.parentStateInfo = parentStateInfo;
//構(gòu)建父子的層次關(guān)系
stateInfo.active = false;
if (mDbg) mSm.log("addStateInternal: X stateInfo: " + stateInfo);
return stateInfo;
}
mStateInfo
是一個(gè) HashMap<State, StateInfo>
類型的對(duì)象良价, 而 StateInfo
類是用于記錄狀態(tài) State
對(duì)象信息,和父節(jié)點(diǎn)信息的 HSM
節(jié)點(diǎn)對(duì)象
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;
}
按照我們剛才對(duì) Car
這個(gè)模型的抽象蒿叠,我們可以定義出一個(gè) Car
的狀態(tài)機(jī):
public class Car extends StateMachine {
....
public Car(String name) {
super(name);
this.addState(mStopState,null);
//mStopState 作為根節(jié)點(diǎn)狀態(tài)明垢,沒有父節(jié)點(diǎn)
this.addState(mAddOilState,mStopState);
//mAddOilState 作為mStopState 的子狀態(tài)
this.addState(mCheckOilState,mStopState);
//mCheckOilState 作為mStopState 的子狀態(tài)
this.addState(mRunState,mCheckOilState);
//mRunState 作為mCheckOilState 的子狀態(tài)
this.setInitialState(mStopState);
// mStopState 為初始狀態(tài)
}
}
當(dāng)我們構(gòu)造完我們的樹形結(jié)構(gòu)了以后,我們就可以將我們的狀態(tài)機(jī)啟動(dòng)起來市咽,這個(gè)啟動(dòng)依賴于 StateMachine.start
函數(shù):
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();//調(diào)用SmHandler.completeConstruction
}
StateMachine.start
中調(diào)用 SmHandler.completeConstruction
用于提交我們之前的所有操作:
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;// step1
for (StateInfo si : mStateInfo.values()) {
int depth = 0;
for (StateInfo i = si; i != null; depth++) {
i = i.parentStateInfo;
}
if (maxDepth < depth) {
maxDepth = depth;//找到一個(gè)最深的堆棧
}
}
if (mDbg) mSm.log("completeConstruction: maxDepth=" + maxDepth);
mStateStack = new StateInfo[maxDepth];
mTempStateStack = new StateInfo[maxDepth];//用于計(jì)算的臨時(shí)變量
setupInitialStateStack();//以初始狀態(tài)為棧底保存到 mStateStack
/** Sending SM_INIT_CMD message to invoke enter methods asynchronously */
sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj));
if (mDbg) mSm.log("completeConstruction: X");
}
按照我們的 HSM
模型痊银,以 STOP
狀態(tài)為基礎(chǔ)狀態(tài)的時(shí)候,那么我們以這個(gè)狀態(tài)為棧底向上延伸施绎,我們可以得到兩個(gè)棧溯革,分別是:
stack1: [STOP,CHECK_OIL,RUN]
stack2: [STOP,ADD_OIL]
stack1
的最大深度為 3 , stack2
的最大深度為 2 。那么 stack1
就可以應(yīng)用于 stack2
的情況谷醉。 completeConstruction
代碼中 step1
段的代碼就是這個(gè)目的致稀,找到一個(gè)最大的棧,用于給所有的棧情況使用俱尼。
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;
}
//將初始狀態(tài)位根狀態(tài)以0->N的順序存入 tempStack
// Empty the StateStack
mStateStackTopIndex = -1;
moveTempStateStackToStateStack();//將 tempstack 倒敘復(fù)制給 stateStack
}
mTempStateStack
是一個(gè)中間變量抖单,它存的是倒敘的 mStateStack
。比如我們的初始狀態(tài)是 RUN
遇八。那么我們需要不斷循環(huán)將 RUN
的父節(jié)點(diǎn)存入 mTempStateStack
得到:
mTempStateStack :[RUN,CHECK_OIL,STOP]
這時(shí)候我們需要調(diào)用 moveTempStateStackToStateStack
函數(shù)將它倒敘復(fù)制到 mStateStack
對(duì)象中矛绘,保證當(dāng)前狀態(tài) RUN
位于棧頂:
mStateStack: [STOP,CHECK_OIL,RUN]
mStateStackTopIndex
變量指向 mStateStack
的棧頂。剛才的這個(gè)例子刃永,mStateStackTopIndex
的值為 2 ,指向 RUN
所在的數(shù)組索引位置货矮。
到了 start
函數(shù)調(diào)用的這一步,我們就完成了一個(gè)樹形數(shù)據(jù)結(jié)構(gòu)和初始狀態(tài)的設(shè)置斯够,接下來囚玫,我們就可以往我們的狀態(tài)機(jī)上發(fā)送我們的指令。
4. [StateMachine] 處理消息
我們通過上面的手段構(gòu)造完一個(gè)狀態(tài)機(jī)以后读规,就可以通過指令讓這個(gè)狀態(tài)機(jī)去處理消息了劫灶。我們先給我們的狀態(tài)機(jī)開一些外部調(diào)用的接口:
public interface ICar {
public void run();
public void stop();
public void addOil();
}
public class Car extends StateMachine implements ICar{
....
}
public void func() {
ICar car = new Car("Ford");
car.addOil();
car.run();
car.stop();
}
當(dāng)我們要向我們的狀態(tài)機(jī)發(fā)送指令的時(shí)候,需要調(diào)用狀態(tài)機(jī)的 sendMessage(...)
函數(shù)掖桦,這套函數(shù)跟 android.os.Handler
提供的 api
的含義一模一樣本昏。實(shí)際上,狀態(tài)機(jī)在處理這種消息的時(shí)候枪汪,也是采用 Handler
的方式涌穆,而我們上面反復(fù)提到的 SmHandler
對(duì)象實(shí)際上就是 Handler
對(duì)象的子類怔昨。
public final void sendMessage(int what) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
smh.sendMessage(obtainMessage(what));//通過Handler方式發(fā)送消息
}
這樣,我們就可以通過這個(gè)函數(shù)去實(shí)現(xiàn)我們的幾個(gè)接口方法:
public class Car extends StateMachine implements ICar{
...
public void run() {
this.sendMessage(ACTION_RUN);
}
public void stop() {
this.sendMessage(ACTION_STOP);
}
public void addOil() {
this.sendMessage(ACTION_ADD_OIL);
}
}
根據(jù)我們對(duì) Handler
類的了解宿稀,每當(dāng)我們通過 Handler.sendMessage
函數(shù)發(fā)送一個(gè)消息的時(shí)候趁舀,都將在 Looper
的下個(gè)處理消息執(zhí)行的時(shí)候,回調(diào) Handler.handleMessage(Message msg)
方法祝沸。由于 SmHandler
繼承于 Handler
,并且它復(fù)寫了 handleMessage
函數(shù)矮烹,因此 , 消息發(fā)送之后罩锐,最后將回調(diào)到SmHandler.handleMessage
方法中奉狈。
//code SmHandler
public final void handleMessage(Message msg) {
if (!mHasQuit) {
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);
//由當(dāng)前狀態(tài)處理
} else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)
&& (mMsg.obj == mSmHandlerObj)) {
/** Initial one time path. */
//執(zhí)行初始化操作函數(shù)
mIsConstructionCompleted = true;
invokeEnterMethods(0);
//當(dāng)調(diào)用
} 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");
}
}
SmHandler.handleMessage
函數(shù)主要執(zhí)行以下幾個(gè)操作:
- 根據(jù)
mHasQuit
判斷是否退出,如果退出將不執(zhí)行后續(xù)指令 - 判斷是否初始完成(根據(jù)變量
mIsConstructionCompleted
),如果初始化完成調(diào)用processMsg
將消息拋給當(dāng)前狀態(tài)執(zhí)行 - 如果尚未初始化涩惑,并且接受的是初始化命令
SM_INIT_CMD
將執(zhí)行一次初始化操作 - 當(dāng)命令執(zhí)行結(jié)束后仁期,執(zhí)行
performTransitions
函數(shù)用于轉(zhuǎn)變當(dāng)前狀態(tài)和mStateStack
我們先接著上面第三個(gè)主題 [StateMachine] 初始化
看下第三步。 SM_INIT_CMD
指令的發(fā)出位于 SmHandler.completeConstruction
函數(shù)中:
//code SmHandler
private final void completeConstruction() {
...
/** Sending SM_INIT_CMD message to invoke enter methods asynchronously */
sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj));
...
}
處理初始化消息的時(shí)候會(huì)先將 mIsConstructionCompleted
設(shè)置為 true
竭恬,告訴狀態(tài)機(jī)已經(jīng)初始化過了跛蛋,可以讓狀態(tài)處理消息了。然后調(diào)用了個(gè) invokeEnterMethods
函數(shù)痊硕。這個(gè)函數(shù)的目的是回調(diào)當(dāng)前 mStateStack
棧中所有的活動(dòng)狀態(tài)的 enter
方法赊级。并且將非活躍狀態(tài)設(shè)置為活躍態(tài):
private final void invokeEnterMethods(int stateStackEnteringIndex) {
for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
mStateStack[i].state.enter();
mStateStack[i].active = true;
}
}
這樣,如果我們的初始狀態(tài)是 STOP
的話岔绸,我們就可以在后臺(tái)打印中看到:
//console output:
output: [StateMachine] StopState enter
如果我們的初始狀態(tài)是 RUN
狀態(tài)的話就可以看到:
//console output:
output: [StateMachine] StopState enter
output: [StateMachine] CheckOilState enter
output: [StateMachine] RunState enter
上面就是處理初始化消息的過程此衅,到這一步,初始化的過程算是完整走完亭螟。我們繼續(xù)來看初始化后的邏輯,當(dāng)初始化已經(jīng)結(jié)束之后挡鞍,再收到的消息將通過 processMsg
函數(shù)提交給合適的狀態(tài)執(zhí)行。
private final State processMsg(Message msg) {
StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
//獲取當(dāng)前狀態(tài)節(jié)點(diǎn)
if (isQuit(msg)) {
//判斷當(dāng)前消息是否是退出消息
transitionTo(mQuittingState);
} else {
while (!curStateInfo.state.processMessage(msg)) {
//當(dāng)該狀態(tài)不處理當(dāng)前消息的時(shí)候预烙,將委托給父狀態(tài)處理
curStateInfo = curStateInfo.parentStateInfo;
if (curStateInfo == null) {
mSm.unhandledMessage(msg);
//當(dāng)沒有狀態(tài)可以處理當(dāng)前消息的時(shí)候回調(diào)unhandledMessage
break;
}
}
}
return (curStateInfo != null) ? curStateInfo.state : null;
}
processMsg
會(huì)先判斷當(dāng)前是否是退出消息墨微,如果 isQuit
成立,將轉(zhuǎn)入 mQuittingState
狀態(tài)扁掸。我們將在后面分析如何執(zhí)行退出操作翘县,這塊東西,我們暫且有個(gè)印象谴分。當(dāng)并非退出消息時(shí)候锈麸,將會(huì)分配給當(dāng)前狀態(tài)處理,如果當(dāng)前狀態(tài)處理不了牺蹄,將委托給父狀態(tài)處理忘伞。比如當(dāng)前我們的初始狀態(tài)是 RUN
。那么對(duì)應(yīng)的 mStateStack
為:
[STOP,CHECK_OIL,RUN]
我們給狀態(tài)的測(cè)試代碼是:
private class BaseState extends State {
@Override
public void enter() {
log(" enter "+this.getClass().getSimpleName());
super.enter();
}
@Override
public void exit() {
log(" exit "+this.getClass().getSimpleName());
super.exit();
}
}
public class StopState extends BaseState {
@Override
public boolean processMessage(Message msg) {
log("StopState.processMessage");
return HANDLED;//處理消息
}
}
public class CheckOilState extends BaseState {
@Override
public boolean processMessage(Message msg) {
log("CheckOilState.processMessage");
return NOT_HANDLED;// 不處理消息
}
}
public class RunState extends BaseState {}
我們往狀態(tài)機(jī) Car
發(fā)送一條消息:
Car car = new Car();
car.sendMessage(0x01);
我們將在后臺(tái)打印出log:
--> enter StopState
--> enter CheckOilState
--> enter RunState
// 初始化結(jié)束
-->[StateMachine]:handleMessage 1
-->CheckOilState.processMessage // run狀態(tài)不處理,扔給checkoil狀態(tài)
-->StopState.processMessage // checkoil狀態(tài)不處理氓奈,扔給stop 狀態(tài)
當(dāng)然翘魄,如果你并不希望消息被委托調(diào)用,你可以在初始狀態(tài)調(diào)用 processMessage
函數(shù)的時(shí)候舀奶,返回 HANDLED
常量暑竟,這樣就不會(huì)往下調(diào)用。
5. [StateMachine] 狀態(tài)轉(zhuǎn)換
通常育勺,我們會(huì)在 State.processMessage
內(nèi)部但荤,通過調(diào)用 transitionTo
函數(shù)執(zhí)行一次狀態(tài)轉(zhuǎn)換,而調(diào)用這個(gè)函數(shù)只是將你要轉(zhuǎn)換的狀態(tài)存入一個(gè)臨時(shí)的對(duì)象中:
protected final void transitionTo(IState destState) {
mSmHandler.transitionTo(destState);
}
private final void transitionTo(IState destState) {
mDestState = (State) destState;
}
真正的狀態(tài)轉(zhuǎn)換將發(fā)生在 SmHandler.handleMessage
函數(shù)執(zhí)行之后:
public final void handleMessage(Message msg) {
if (!mHasQuit) {
...
performTransitions(msgProcessedState, msg);//變更狀態(tài)
}
}
這里將調(diào)用 performTransitions
函數(shù)完成狀態(tài)轉(zhuǎn)換,假如,現(xiàn)在的狀態(tài)是 RUN
狀態(tài)涧至,當(dāng)需要轉(zhuǎn)成 ADD_OIL
狀態(tài)的時(shí)候腹躁,將進(jìn)行一下轉(zhuǎn)變:
/**
初始:
mStateStack : [ STOP,CHECK_OIL,RUN]
*/
private void performTransitions(State msgProcessedState, Message msg) {
State orgState = mStateStack[mStateStackTopIndex].state;
//orgState記錄當(dāng)前狀態(tài)
State destState = mDestState;
//destState 記錄要轉(zhuǎn)變的目標(biāo)狀態(tài)
if (destState != null) {
while (true) {
StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
//查找跟目標(biāo)狀態(tài)的公共節(jié)點(diǎn)狀態(tài),此時(shí)為 STOP 狀態(tài)節(jié)點(diǎn)
invokeExitMethods(commonStateInfo);
//從棧頂一直到commonStateInfo(不包含) 所在的位置執(zhí)行退出操作
int stateStackEnteringIndex = moveTempStateStackToStateStack();
invokeEnterMethods(stateStackEnteringIndex);
moveDeferredMessageAtFrontOfQueue();
//將Deferred 消息放入隊(duì)列頭部優(yōu)先執(zhí)行
if (destState != mDestState) {
destState = mDestState;
} else {
break;
}
}
mDestState = null;
}
if (destState != null) {
if (destState == mQuittingState) {
//TODO clean
} else if (destState == mHaltingState) {
//TODO halt
}
}
}
這段代碼執(zhí)行的時(shí)候化借,會(huì)先去尋找目標(biāo)節(jié)點(diǎn)和當(dāng)前節(jié)點(diǎn)的公共祖先節(jié)點(diǎn)潜慎,這是通過調(diào)用 setupTempStateStackWithStatesToEnter
調(diào)用的捡多。StateMachine
的函數(shù)名起的見名知意蓖康,*Temp*
代表這個(gè)函數(shù)中要使用中間變量 mTempStateStack
。*ToEnter
代表需要對(duì)添加進(jìn)的狀態(tài)執(zhí)行 State.enter
操作垒手。
private final StateInfo setupTempStateStackWithStatesToEnter(State destState) {
mTempStateStackCount = 0;//重置 mTempStateStack
StateInfo curStateInfo = mStateInfo.get(destState);
do {
mTempStateStack[mTempStateStackCount++] = curStateInfo;
curStateInfo = curStateInfo.parentStateInfo;
} while ((curStateInfo != null) && !curStateInfo.active);
//找到第一個(gè) active 的狀態(tài)節(jié)點(diǎn)蒜焊。
return curStateInfo;
}
setupTempStateStackWithStatesToEnter
函數(shù)就是將目標(biāo)節(jié)點(diǎn)的堆棧復(fù)制到 mTempStateStack
變量中,然后將最終相交的節(jié)點(diǎn)返回科贬。這里采用 do-while
的寫法泳梆,說明這個(gè)函數(shù)的執(zhí)行,至少包含一個(gè) destState
元素榜掌。剛才從 RUN->ADD_OIL
的例子中优妙,setupTempStateStackWithStatesToEnter
將返回 STOP
狀態(tài),mTempStateStack
的為:
mTempStateStack: {ADD_OIL}
我們回到 performTransitions
的流程憎账,執(zhí)行 setupTempStateStackWithStatesToEnter
完套硼,將執(zhí)行 invokeExitMethods
函數(shù)。
private final void invokeExitMethods(StateInfo commonStateInfo) {
while ((mStateStackTopIndex >= 0)
&& (mStateStack[mStateStackTopIndex] != commonStateInfo)) {
State curState = mStateStack[mStateStackTopIndex].state;
curState.exit();
mStateStack[mStateStackTopIndex].active = false;
mStateStackTopIndex -= 1;
}
}
這個(gè)函數(shù)相當(dāng)于將 mStateStack
棧中的非 commonStateInfo
進(jìn)行出棧胞皱。
mStateStack: {STOP,CHECK_OIL,RUN} ->
invokeExitMethods(STOP) ->
mStateStack: {STOP}
執(zhí)行完出棧后邪意,只需要將我們剛才構(gòu)建的 mTempStateStack
拷貝到 mStateStack
就可以構(gòu)建新的狀態(tài)棧了,而這個(gè)操作是通過 moveTempStateStackToStateStack
函數(shù)完成反砌,而 moveTempStateStackToStateStack
我們剛才說過雾鬼,實(shí)際上就是將 mTempStateStack
逆序賦值到 mStateStack
。這樣宴树,我們就構(gòu)建了一個(gè)新的 mStateStack
:
mStateStack: {STOP,ADD_OIL}
這個(gè)時(shí)候策菜,我們構(gòu)建了一個(gè)新的狀態(tài)棧,相當(dāng)于已經(jīng)切換了狀態(tài)。performTransitions
在執(zhí)行完 moveTempStateStackToStateStack
之后做入,調(diào)用 invokeEnterMethods
函數(shù)冒晰,執(zhí)行非 active
狀態(tài)的 enter
方法。之后執(zhí)行 moveDeferredMessageAtFrontOfQueue
將通過 deferMessage
函數(shù)緩存的消息隊(duì)列放到 Handler
消息隊(duì)列的頭部:
...
int stateStackEnteringIndex = moveTempStateStackToStateStack();
invokeEnterMethods(stateStackEnteringIndex);
moveDeferredMessageAtFrontOfQueue();
//將Deferred 消息放入隊(duì)列頭部優(yōu)先執(zhí)行
if (destState != mDestState) {
destState = mDestState;
} else {
break;
}
...
當(dāng)我們完成狀態(tài)的轉(zhuǎn)換了以后竟块,需要對(duì)兩種特殊的狀態(tài)進(jìn)行處理壶运,在 performTransitions
函數(shù)的末尾會(huì)判斷兩個(gè)特殊的狀態(tài):
1. HaltingState
2. QuittingState
6. 狀態(tài)機(jī)的退出
狀態(tài)機(jī)的退出,StateMachine
提供了幾個(gè)方法:
- quit: 執(zhí)行完消息隊(duì)列中所有的消息后執(zhí)行退出和清理操作
- quitNow: 拋棄掉消息隊(duì)列中的消息浪秘,直接執(zhí)行退出和清理操作
- transitionToHaltingState: 拋棄掉消息隊(duì)列中的消息蒋情,直接執(zhí)行退出,不做清理
從上面的表述中看耸携,quit
相對(duì) halt
操作來說更加的安全棵癣。這個(gè) Thread
的 intercept
和 stop
方法很類似,很好理解夺衍。上面我們說到狈谊,退出狀態(tài) HaltingState
和 QuittingState
是在performTransitions
函數(shù)的末尾判斷和執(zhí)行的,我們來看下代碼:
if (destState != null) {
if (destState == mQuittingState) {
mSm.onQuitting();
cleanupAfterQuitting();//清理操作
} else if (destState == mHaltingState) {
mSm.onHalting();//只是執(zhí)行回調(diào)
}
}
private final void cleanupAfterQuitting() {
if (mSm.mSmThread != null) {
getLooper().quit();//退出線程
mSm.mSmThread = null;
}
/*清空數(shù)據(jù)*/
mSm.mSmHandler = null;
mSm = null;
mMsg = null;
mLogRecords.cleanup();
mStateStack = null;
mTempStateStack = null;
mStateInfo.clear();
mInitialState = null;
mDestState = null;
mDeferredMessages.clear();
mHasQuit = true;
}
當(dāng) destState == mQuittingState
語句成立沟沙,將回調(diào) StateMachine.onQuitting
函數(shù)河劝,之后將執(zhí)行 cleanupAfterQuitting
進(jìn)行清理操作。清理操作中矛紫,會(huì)將線程清空赎瞎,和其他數(shù)據(jù)變量清空,而如果 destState == mHaltingState
成立颊咬,StateMachine
將不執(zhí)行任何的清理操作务甥,通過回調(diào) onHalting
函數(shù)來通知狀態(tài)機(jī)退出。
7. 總結(jié)
Android
里面的這個(gè) StateMachine
狀態(tài)機(jī)在很多源碼中都有涉及喳篇,代碼也很簡單敞临,沒有什么太大的難度,希望以上的總結(jié)能幫各位看官理解 StateMachine
源碼的含義麸澜,并且能基于它挺尿,開發(fā)更多個(gè)性化的功能