1. 程式人生 > >Android狀態機原始碼分析

Android狀態機原始碼分析

轉載自:http://blog.csdn.net/yangwen123/article/details/10591451

Android系統中,經常使用狀態機來處理不同狀態下的行為動作。狀態機是將物件的狀態與行為封裝在一起;可以解決龐大的分支語句帶來程式閱讀性差和不便於進行擴充套件問題,使整個結構變得更加清晰明瞭,降低程式管理的複雜性提高靈活度。Android系統的StateMachine機制是一個State模式的應用,StateMachine是一個分層處理訊息的狀態機,並且是能夠有分層排列狀態。


構造狀態機

StateMachine的建構函式都是protected型別,不能例項化,都是由其子類進行初始化操作。StateMachine有兩個過載的建構函式,一個是通過指定訊息迴圈物件來構造狀態機

[java] view plain copy print?
  1. protected StateMachine(String name, Looper looper) {  
  2.     initStateMachine(name, looper);  
  3. }  
protected StateMachine(String name, Looper looper) {
	initStateMachine(name, looper);
}

另一個則是直接啟動一個訊息迴圈執行緒來構造一個狀態機

[java] view plain copy print?
  1. protected StateMachine(String name) {  
  2.     //啟動一個訊息迴圈執行緒
  3.     mSmThread = new HandlerThread(name);  
  4.     mSmThread.start();  
  5.     Looper looper = mSmThread.getLooper();  
  6.     initStateMachine(name, looper);  
  7. }  
protected StateMachine(String name) {
	//啟動一個訊息迴圈執行緒
	mSmThread = new HandlerThread(name);
	mSmThread.start();
	Looper looper = mSmThread.getLooper();
	initStateMachine(name, looper);
}
這兩種建構函式都會通過initStateMachine函式來初始化該狀態機 [java] view plain copy print?
  1. privatevoid initStateMachine(String name, Looper looper) {  
  2.     mName = name;  
  3.     mSmHandler = new SmHandler(looper, this);  
  4. }  
private void initStateMachine(String name, Looper looper) {
	mName = name;
	mSmHandler = new SmHandler(looper, this);
}
初始化過程比較簡單,就是將狀態機名稱儲存到成員變數mName中,同時建立SmHandler物件,SmHandler是一個Handle物件,用於派發訊息。

狀態機中的每個狀態使用State來封裝,對於每個狀態的資訊又採用StateInfo來描述

StateMachine三個內部類:
1.ProcessedMessageInfo:儲存已處理訊息的資訊;
2.ProcessedMessages:儲存StateMachine最近處理的一些訊息,需要儲存最近處理的訊息條數預設20,可以使用者自己設定最大數目;
3.SmHandle是訊息處理派發和狀態控制切換的核心,執行在單獨的執行緒上;

SmHandle成員變數定義:


ProcessedMessages用於儲存已處理過的訊息,mStateStack和mTempStateStack是一個數組棧,用於儲存狀態機中的鏈式狀態關係。

mStateInfo定義為一個Hash連結串列,用於儲存新增的所有狀態。mInitialState儲存初始狀態,mDestState儲存切換的目的狀態。

建立樹形層次結構狀態機

在構造完一個狀態機前需要向狀態機中新增各種狀態,StateMachine提供了addState函式來新增狀態
[java] view plain copy print?
  1. protectedfinalvoid addState(State state, State parent) {  
  2.     mSmHandler.addState(state, parent);  
  3. }  
protected final void addState(State state, State parent) {
	mSmHandler.addState(state, parent);
}
直接通過mSmHandler來完成狀態新增過程 [java] view plain copy print?
  1. privatefinal StateInfo addState(State state, State parent) {  
  2.     if (mDbg) {  
  3.         Log.d(TAG, "addStateInternal: E state=" + state.getName()  
  4.                 + ",parent=" + ((parent == null) ? "" : parent.getName()));  
  5.     }  
  6.     StateInfo parentStateInfo = null;  
  7.     if (parent != null) {  
  8.         parentStateInfo = mStateInfo.get(parent);  
  9.         if (parentStateInfo == null) {  
  10.             // Recursively add our parent as it's not been added yet.
  11.             parentStateInfo = addState(parent, null);  
  12.         }  
  13.     }  
  14.     StateInfo stateInfo = mStateInfo.get(state);  
  15.     if (stateInfo == null) {  
  16.         stateInfo = new StateInfo();  
  17.         mStateInfo.put(state, stateInfo);  
  18.     }  
  19.     // Validate that we aren't adding the same state in two different hierarchies.
  20.     if ((stateInfo.parentStateInfo != null) &&  
  21.             (stateInfo.parentStateInfo != parentStateInfo)) {  
  22.             thrownew RuntimeException("state already added");  
  23.     }  
  24.     stateInfo.state = state;  
  25.     stateInfo.parentStateInfo = parentStateInfo;  
  26.     stateInfo.active = false;  
  27.     if (mDbg) Log.d(TAG, "addStateInternal: X stateInfo: " + stateInfo);  
  28.     return stateInfo;  
  29. }  
private final StateInfo addState(State state, State parent) {
	if (mDbg) {
		Log.d(TAG, "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);
		}
	}
	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;
	if (mDbg) Log.d(TAG, "addStateInternal: X stateInfo: " + stateInfo);
	return stateInfo;
}
狀態新增過程其實就是為每個State建立相應的StateInfo物件,通過該物件來建立各個狀態之間的關係,並且一個State-StateInfo鍵值對的方式儲存到mStateInfo Hash表中。StateInfo就是包裝State組成一個Node,建立State的父子關係;mStateInfo =new HashMap<State, StateInfo>();用來儲存State Machine中的所有State,可以按照樹形層次結構組織狀態機中的所有狀態 接下來介紹構造以下樹形狀態機的過程: [java] view plain copy print?
  1. sm.addState(S0,null);  
  2. sm.addState(S1,S0);  
  3. sm.addState(S2,S0);  
  4. sm.addState(S3,S1);  
  5. sm.addState(S4,S1);  
  6. sm.addState(S5,S2);  
  7. sm.addState(S6,S2);  
  8. sm.addState(S7,S2);  
  9. setInitialState(S4);      //設定初始狀態
sm.addState(S0,null);
sm.addState(S1,S0);
sm.addState(S2,S0);
sm.addState(S3,S1);
sm.addState(S4,S1);
sm.addState(S5,S2);
sm.addState(S6,S2);
sm.addState(S7,S2);
setInitialState(S4);      //設定初始狀態
1.新增根節點狀態過程 對於根節點狀態的加入sm.addState(S0,null)程式碼執行如下:
[java] view plain copy print?
  1. privatefinal StateInfo addState(S0,null)   
  2. {  
  3.     StateInfo parentStateInfo = null;  
  4.     //狀態S0還未加入狀態機中
  5.     StateInfo stateInfo = mStateInfo.get(state);  
  6.   if (stateInfo == null) {  
  7.     //建立State詳細資訊物件
  8.     stateInfo = new StateInfo();  
  9.         //將S0加入狀態機中
  10.     mStateInfo.put(state, stateInfo);  
  11.   }  
  12.   //設定狀態S0的狀態資訊
  13.     stateInfo.state = state;  
  14.     //S0的父節點為null
  15.     stateInfo.parentStateInfo = parentStateInfo;  
  16.   stateInfo.active = false;  
  17.   return stateInfo;  
  18. }  
private final StateInfo addState(S0,null) 
{
	StateInfo parentStateInfo = null;
	//狀態S0還未加入狀態機中
	StateInfo stateInfo = mStateInfo.get(state);
  if (stateInfo == null) {
    //建立State詳細資訊物件
    stateInfo = new StateInfo();
		//將S0加入狀態機中
    mStateInfo.put(state, stateInfo);
  }
  //設定狀態S0的狀態資訊
  	stateInfo.state = state;
	//S0的父節點為null
  	stateInfo.parentStateInfo = parentStateInfo;
  stateInfo.active = false;
  return stateInfo;
}
2.新增樹枝節點狀態過程 對於子節點S1狀態的加入過程如下sm.addState(S1,S0):
[java] view plain copy print?
  1. privatefinal StateInfo addState(State state, State parent)   
  2. {  
  3.   StateInfo parentStateInfo = null;  
  4.     //狀態S0在前面已經加入狀態機中了
  5.   if (parent != null) {  
  6.     //獲取S0詳細資訊 StateInfo
  7.         parentStateInfo = mStateInfo.get(parent);  
  8.         //因為S0已經存在於狀態機中,因此這裡不為空
  9.     if (parentStateInfo == null) {  
  10.       //當前狀態父狀態未加入到StateMachine中,遞迴先加入其父State
  11.       parentStateInfo = addState(parent, null);  
  12.     }  
  13.   }  
  14.   //從狀態機中得到S1的狀態資訊,由於S1還為加入狀態機,因此得到的結果為空
  15.   StateInfo stateInfo = mStateInfo.get(state);  
  16.   if (stateInfo == null) {  
  17.     //建立State詳細資訊物件
  18.     stateInfo = new StateInfo();  
  19.         //將S1加入狀態機中
  20.     mStateInfo.put(state, stateInfo);  
  21.   }  
  22.   //S1的狀態資訊剛建立,還沒有為其設定父節點,因此其父節點為空
  23.   if ((stateInfo.parentStateInfo != null) &&  
  24.     (stateInfo.parentStateInfo != parentStateInfo)) {  
  25.       thrownew RuntimeException("state already added");  
  26.   }  
  27.   //設定狀態S1的狀態資訊
  28.     stateInfo.state = state;  
  29.     //S1的父節點為S0
  30.     stateInfo.parentStateInfo = parentStateInfo;  
  31.   stateInfo.active = false;  
  32.   return stateInfo;  
  33. }  
private final StateInfo addState(State state, State parent) 
{
  StateInfo parentStateInfo = null;
	//狀態S0在前面已經加入狀態機中了
  if (parent != null) {
    //獲取S0詳細資訊 StateInfo
		parentStateInfo = mStateInfo.get(parent);
		//因為S0已經存在於狀態機中,因此這裡不為空
    if (parentStateInfo == null) {
      //當前狀態父狀態未加入到StateMachine中,遞迴先加入其父State
      parentStateInfo = addState(parent, null);
    }
  }
  //從狀態機中得到S1的狀態資訊,由於S1還為加入狀態機,因此得到的結果為空
  StateInfo stateInfo = mStateInfo.get(state);
  if (stateInfo == null) {
    //建立State詳細資訊物件
    stateInfo = new StateInfo();
		//將S1加入狀態機中
    mStateInfo.put(state, stateInfo);
  }
  //S1的狀態資訊剛建立,還沒有為其設定父節點,因此其父節點為空
  if ((stateInfo.parentStateInfo != null) &&
    (stateInfo.parentStateInfo != parentStateInfo)) {
      throw new RuntimeException("state already added");
  }
  //設定狀態S1的狀態資訊
  	stateInfo.state = state;
	//S1的父節點為S0
  	stateInfo.parentStateInfo = parentStateInfo;
  stateInfo.active = false;
  return stateInfo;
}
對於其他樹枝節點的新增過程類似,這裡不在介紹,最後儲存在mStateInfo表中的所有狀態之間就建立了以下樹形關係:

啟動狀態機

當向狀態機中新增完所有狀態時,通過函式start函式來啟動狀態機 [java] view plain copy print?
  1. publicvoid start() {  
  2.     // mSmHandler can be null if the state machine has quit.
  3.     if (mSmHandler == nullreturn;  
  4.     /** Send the complete construction message */
  5.     mSmHandler.completeConstruction();  
  6. }  
public void start() {
	// mSmHandler can be null if the state machine has quit.
	if (mSmHandler == null) return;
	/** Send the complete construction message */
	mSmHandler.completeConstruction();
}
呼叫mSmHandler的completeConstruction函式來完成狀態機的構造完成處理 [java] view plain copy print?
  1. privatefinalvoid completeConstruction() {  
  2.     if (mDbg) Log.d(TAG, "completeConstruction: E");  
  3.     //查詢狀態樹的深度
  4.     int maxDepth = 0;  
  5.     for (StateInfo si : mStateInfo.values()) {  
  6.         int depth = 0;  
  7.         //根據父子關係計算樹枝層次數
  8.         for (StateInfo i = si; i != null; depth++) {  
  9.             i = i.parentStateInfo;  
  10.         }  
  11.         if (maxDepth < depth) {  
  12.             maxDepth = depth;  
  13.         }  
  14.     }  
  15.     if (mDbg) Log.d(TAG, "completeConstruction: maxDepth=" + maxDepth);  
  16.     //建立mStateStack,mTempStateStack狀態棧
  17.     mStateStack = new StateInfo[maxDepth];  
  18.     mTempStateStack = new StateInfo[maxDepth];  
  19.     //設定狀態堆疊
  20.     setupInitialStateStack();  
  21.     /** Sending SM_INIT_CMD message to invoke enter methods asynchronously */
  22.     sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj));  
  23.     if (mDbg) Log.d(TAG, "completeConstruction: X");  
  24. }  
private final void completeConstruction() {
	if (mDbg) Log.d(TAG, "completeConstruction: E");
	//查詢狀態樹的深度
	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) Log.d(TAG, "completeConstruction: maxDepth=" + maxDepth);
	//建立mStateStack,mTempStateStack狀態棧
	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) Log.d(TAG, "completeConstruction: X");
}
計算狀態樹的最大深度方法: 1.遍歷狀態樹中的所有節點; 2.以每一個節點為起始點,根據節點父子關係查詢到根節點; 3.累計起始節點到根節點之間的節點個數;查詢最大的節點個數。 根據查詢到的樹的最大節點個數來建立兩個狀態堆疊,並呼叫函式setupInitialStateStack來填充該堆疊 [java] view plain copy print?
  1. privatefinalvoid setupInitialStateStack() {  
  2.     //在mStateInfo中取得初始狀態mInitialState對應的StateInfo
  3.     StateInfo curStateInfo = mStateInfo.get(mInitialState);  
  4.     //從初始狀態mInitialState開始根據父子關係填充mTempStateStack堆疊
  5.     for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) {  
  6.         mTempStateStack[mTempStateStackCount] = curStateInfo;  
  7.         curStateInfo = curStateInfo.parentStateInfo;  
  8.     }  
  9.     // Empty the StateStack
  10.     mStateStackTopIndex = -1;  
  11.     //將mTempStateStack中的狀態按反序方式移動到mStateStack棧中
  12.     moveTempStateStackToStateStack();  
  13. }  
private final void setupInitialStateStack() {
	//在mStateInfo中取得初始狀態mInitialState對應的StateInfo
	StateInfo curStateInfo = mStateInfo.get(mInitialState);
	//從初始狀態mInitialState開始根據父子關係填充mTempStateStack堆疊
	for (mTempStateStackCount = 0; curStateInfo != null; mTempStateStackCount++) {
		mTempStateStack[mTempStateStackCount] = curStateInfo;
		curStateInfo = curStateInfo.parentStateInfo;
	}
	// Empty the StateStack
	mStateStackTopIndex = -1;
	//將mTempStateStack中的狀態按反序方式移動到mStateStack棧中
	moveTempStateStackToStateStack();
}
從上圖可以看出,當初始狀態為S4時,儲存到mTempStateStack的節點為: mTempStateStack={S4,S1,S0}
mTempStateStackCount = 3; mStateStackTopIndex = -1; 然後呼叫函式moveTempStateStackToStateStack將節點以反序方式儲存到mStateStack中 [java] view plain copy print?
  1. privatefinalint moveTempStateStackToStateStack() {  
  2.     //startingIndex= 0
  3.     int startingIndex = mStateStackTopIndex + 1;  
  4.     int i = mTempStateStackCount - 1;  
  5.     int j = startingIndex;  
  6.     while (i >= 0) {  
  7.         if (mDbg) Log.d(TAG, "moveTempStackToStateStack: i=" + i + ",j=" + j);  
  8.         mStateStack[j] = mTempStateStack[i];  
  9.         j += 1;  
  10.         i -= 1;  
  11.     }  
  12.     mStateStackTopIndex = j - 1;  
  13.     return startingIndex;  
  14. }  
private final int moveTempStateStackToStateStack() {
	//startingIndex= 0
	int startingIndex = mStateStackTopIndex + 1;
	int i = mTempStateStackCount - 1;
	int j = startingIndex;
	while (i >= 0) {
		if (mDbg) Log.d(TAG, "moveTempStackToStateStack: i=" + i + ",j=" + j);
		mStateStack[j] = mTempStateStack[i];
		j += 1;
		i -= 1;
	}
	mStateStackTopIndex = j - 1;
	return startingIndex;
}
mStateStack={S0,S1,S4} mStateStackTopIndex = 2
初始化完狀態棧後,SmHandler將向訊息迴圈中傳送一個SM_INIT_CMD訊息 [java] view plain copy print?
  1. sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj))  
sendMessageAtFrontOfQueue(obtainMessage(SM_INIT_CMD, mSmHandlerObj))
該訊息對應的處理如下: [java] view plain copy print?
  1. elseif (!mIsConstructionCompleted &&(mMsg.what == SM_INIT_CMD) && (mMsg.obj == mSmHandlerObj)) {  
  2.     mIsConstructionCompleted = true;  
  3.     invokeEnterMethods(0);  
  4. }  
  5. performTransitions();  
else if (!mIsConstructionCompleted &&(mMsg.what == SM_INIT_CMD) && (mMsg.obj == mSmHandlerObj)) {
	mIsConstructionCompleted = true;
	invokeEnterMethods(0);
}
performTransitions();
訊息處理過程首先呼叫invokeEnterMethods函式將mStateStack棧中的所有狀態設定為啟用狀態,同時呼叫每一個狀態的enter()函式 [java] view plain copy print?
  1. privatefinalvoid invokeEnterMethods(int stateStackEnteringIndex) {  
  2.     for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {  
  3.         if (mDbg) Log.d(TAG, "invokeEnterMethods: " + mStateStack[i].state.getName());  
  4.         mStateStack[i].state.enter();  
  5.         mStateStack[i].active = true;  
  6.     }  
  7. }  
private final void invokeEnterMethods(int stateStackEnteringIndex) {
	for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
		if (mDbg) Log.d(TAG, "invokeEnterMethods: " + mStateStack[i].state.getName());
		mStateStack[i].state.enter();
		mStateStack[i].active = true;
	}
}
最後呼叫performTransitions函式來切換狀態,同時設定mIsConstructionCompleted為true,表示狀態機已經啟動完成,SmHandler在以後的訊息處理過程中就不在重新啟動狀態機了。

狀態切換

SmHandler在處理每個訊息時都會呼叫performTransitions來檢查狀態切換 [java] view plain copy print?
  1. privatesynchronizedvoid performTransitions() {  
  2.   while (mDestState != null){  
  3.     //當前狀態切換了 存在於mStateStack中的State需要改變
  4.     //仍然按照鏈式父子關係來儲存
  5.     //先從當前狀態S3找到 最近的被啟用的parent狀態S0
  6.     //未被啟用的全部儲存起來(S3,S1) 返回S0
  7.     StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);  
  8.     //將mStateStack中 不屬於當前狀態(S3),
  9.     //關係鏈上的State(S5,S2)退出(執行exit方法)
  10.     invokeExitMethods(commonStateInfo);  
  11.     //將S3關係鏈 加入到棧中(S3,S1)
  12.     int stateStackEnteringIndex = moveTempStateStackToStateStack();  
  13.     //將新加入到mStateStack中 未被啟用的State啟用(S3,S1)
  14.     invokeEnterMethods(stateStackEnteringIndex);  
  15.     //將延遲的訊息移動到訊息佇列的前面,以便快速得到處理               
  16.     moveDeferredMessageAtFrontOfQueue();  
  17.   }  
  18. }  
private synchronized void performTransitions() {
  while (mDestState != null){
    //當前狀態切換了 存在於mStateStack中的State需要改變
    //仍然按照鏈式父子關係來儲存
    //先從當前狀態S3找到 最近的被啟用的parent狀態S0
    //未被啟用的全部儲存起來(S3,S1) 返回S0
    StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
    //將mStateStack中 不屬於當前狀態(S3),
    //關係鏈上的State(S5,S2)退出(執行exit方法)
    invokeExitMethods(commonStateInfo);
    //將S3關係鏈 加入到棧中(S3,S1)
    int stateStackEnteringIndex = moveTempStateStackToStateStack();
    //將新加入到mStateStack中 未被啟用的State啟用(S3,S1)
    invokeEnterMethods(stateStackEnteringIndex);
    //將延遲的訊息移動到訊息佇列的前面,以便快速得到處理               
    moveDeferredMessageAtFrontOfQueue();
  }
}
首先介紹一下狀態切換的思路:

以上圖中,初始狀態為S4,現在目標狀態mDestState被設定為S7。前面介紹了儲存在mStateStack陣列中的節點為: mStateStack={S0,S1,S4} mStateStackTopIndex = 2 這是以初始狀態節點為起點遍歷節點樹得到的節點連結串列。 現在要切換到S7狀態節點,則以S7為起始節點,同樣遍歷狀態節點樹,查詢未啟用的所有節點,並儲存到mTempStateStack陣列中 mTempStateStack={S7,S2,S0}
mTempStateStackCount = 3
接著呼叫mStateStack中除S0節點外的其他所有節點的exit函式,並且將每個狀態節點設定為未啟用狀態,因此S4,S1被設定為未啟用狀態;將切換後的狀態節點連結串列mTempStateStack移動到mStateStack, mStateStack={S0,S2,S7}
mStateStackTopIndex = 2 並呼叫節點S2,S7的enter函式,同時設定為啟用狀態。 理解了整個狀態切換過程後,就能更好地理解程式碼,首先根據目標狀態建立狀態節點鏈路表 [java] view plain copy print?
  1. privatefinal StateInfo setupTempStateStackWithStatesToEnter(State destState) {  
  2.     mTempStateStackCount = 0;  
  3.     StateInfo curStateInfo = mStateInfo.get(destState);  
  4.     do {  
  5.         mTempStateStack[mTempStateStackCount++] = curStateInfo;  
  6.         if (curStateInfo != null) {  
  7.             curStateInfo = curStateInfo.parentStateInfo;  
  8.         }  
  9.     } while ((curStateInfo != null) && !curStateInfo.active);  
  10.     return curStateInfo;  
  11. }  
private final StateInfo setupTempStateStackWithStatesToEnter(State destState) {
	mTempStateStackCount = 0;
	StateInfo curStateInfo = mStateInfo.get(destState);
	do {
		mTempStateStack[mTempStateStackCount++] = curStateInfo;
		if (curStateInfo != null) {
			curStateInfo = curStateInfo.parentStateInfo;
		}
	} while ((curStateInfo != null) && !curStateInfo.active);
	return curStateInfo;
}
然後彈出mStateStack中儲存的原始狀態 [java] view plain copy print?
  1. privatefinalvoid invokeExitMethods(StateInfo commonStateInfo) {  
  2.     while ((mStateStackTopIndex >= 0) &&  
  3.             (mStateStack[mStateStackTopIndex] != commonStateInfo)) {  
  4.         State curState = mStateStack[mStateStackTopIndex].state;  
  5.         if (mDbg) Log.d(TAG, "invokeExitMethods: " + curState.getName());  
  6.         curState.exit();  
  7.         mStateStack[mStateStackTopIndex].active = false;  
  8.         mStateStackTopIndex -= 1;  
  9.     }  
  10. }  
private final void invokeExitMethods(StateInfo commonStateInfo) {
	while ((mStateStackTopIndex >= 0) &&
			(mStateStack[mStateStackTopIndex] != commonStateInfo)) {
		State curState = mStateStack[mStateStackTopIndex].state;
		if (mDbg) Log.d(TAG, "invokeExitMethods: " + curState.getName());
		curState.exit();
		mStateStack[mStateStackTopIndex].active = false;
		mStateStackTopIndex -= 1;
	}
}
將新建立的狀態節點連結串列儲存到mStateStack棧中 [java] view plain copy print?
  1. privatefinalint moveTempStateStackToStateStack() {  
  2.     //startingIndex= 0
  3.     int startingIndex = mStateStackTopIndex + 1;  
  4.     int i = mTempStateStackCount - 1;  
  5.     int j = startingIndex;  
  6.     while (i >= 0) {  
  7.         if (mDbg) Log.d(TAG, "moveTempStackToStateStack: i=" + i + ",j=" + j);  
  8.         mStateStack[j] = mTempStateStack[i];  
  9.         j += 1;  
  10.         i -= 1;  
  11.     }  
  12.     mStateStackTopIndex = j - 1;  
  13.     return startingIndex;  
  14. }  
private final int moveTempStateStackToStateStack() {
	//startingIndex= 0
	int startingIndex = mStateStackTopIndex + 1;
	int i = mTempStateStackCount - 1;
	int j = startingIndex;
	while (i >= 0) {
		if (mDbg) Log.d(TAG, "moveTempStackToStateStack: i=" + i + ",j=" + j);
		mStateStack[j] = mTempStateStack[i];
		j += 1;
		i -= 1;
	}
	mStateStackTopIndex = j - 1;
	return startingIndex;
}
初始化入棧的所有新狀態,並設定為啟用狀態 [java] view plain copy print?
  1. privatefinalvoid invokeEnterMethods(int stateStackEnteringIndex) {  
  2.     for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {  
  3.         if (mDbg) Log.d(TAG, "invokeEnterMethods: " + mStateStack[i].state.getName());  
  4.         mStateStack[i].state.enter();  
  5.         mStateStack[i].active = true;  
  6.     }  
  7. }  
private final void invokeEnterMethods(int stateStackEnteringIndex) {
	for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
		if (mDbg) Log.d(TAG, "invokeEnterMethods: " + mStateStack[i].state.getName());
		mStateStack[i].state.enter();
		mStateStack[i].active = true;
	}
}
如何設定目標狀態呢?StateMachine提供了transitionTo函式來切換狀態 [java] view plain copy print?
  1. protectedfinalvoid transitionTo(IState destState) {  
  2.     mSmHandler.transitionTo(destState);  
  3. }  
protected final void transitionTo(IState destState) {
	mSmHandler.transitionTo(destState);
}
該函式直接呼叫SmHandler的transitionTo函式來實現,SmHandler的transitionTo函式定義如下: [java] view plain copy print?
  1. privatefinalvoid transitionTo(IState destState) {  
  2.     mDestState = (State) destState;  
  3.     if (mDbg) Log.d(TAG, "transitionTo: destState=" + mDestState.getName());  
  4. }  
private final void transitionTo(IState destState) {
	mDestState = (State) destState;
	if (mDbg) Log.d(TAG, "transitionTo: destState=" + mDestState.getName());
}
這裡只是簡單地設定了mDestState變數,並未真正更新狀態棧mStateStack,在前面介紹了SmHandler在每次處理訊息時都會自動更新一次mStateStack,無論mDestState變數值是否改變。由此可知目標狀態的設定與狀態棧的更新是非同步的。

訊息處理


StateMachine處理的核心就是SmHandler,就是一個Handler,執行在單獨執行緒中。Handler是用來非同步處理派發訊息,這裡使用Handler管理各個狀態,派發訊息處理到各個狀態中去執行。StateMachine提供了多個訊息傳送介面,通過這些介面函式可以將訊息傳送到SmHandler中。 [java] view plain copy print?
  1. publicfinalvoid sendMessage(int what) {  
  2.     // mSmHandler can be null if the state machine has quit.
  3.     if (mSmHandler == nullreturn;  
  4.     mSmHandler.sendMessage(obtainMessage(what));  
  5. }  
public final void sendMessage(int what) {
	// mSmHandler can be null if the state machine has quit.
	if (mSmHandler == null) return;
	mSmHandler.sendMessage(obtainMessage(what));
}
SmHandler將處理通過SmHandler傳送的訊息,處理過程如下: [java] view plain copy print?
  1. publicfinalvoid handleMessage(Message msg) {  
  2.     /** Save the current message */
  3.     mMsg = msg;  
  4.     if (mIsConstructionCompleted) {  
  5.         //派發當前訊息到state中去處理
  6.         processMsg(msg);  
  7.     } elseif (!mIsConstructionCompleted &&  
  8.             (mMsg.what == SM_INIT_CMD) && (mMsg.obj == mSmHandlerObj)) {  
  9.         /** Initial one time path. */
  10.         mIsConstructionCompleted = true;  
  11.         invokeEnterMethods(