StateMachine狀態機初識

StateMachine狀態機的介紹中,以下的這篇部落格講得已經很全面了。
http://www.cnblogs.com/bastard/archive/2012/06/05/2536258.html

為了更加方便的理解,個人簡單的畫了一張時序圖:

StateMachine狀態機

具體的使用:

要實現自己的StateMachine並讓它跑起來,需要做以下幾個工作:
一 . 實現自己的State子類。
StateMachine已經幫我們做了大部分工作,現在每當一個事件訊息進到State子類的時候,會按順序執行enter()–>processMessage()–>exit()。當然,這個順序是在State之間不互相跳轉的情況下,如果在enter()或者processMessage()的時候跳轉到其他的State,則會執行其他State的enter()–>processMessage()–>exit()。

public class State implements IState {
@Override
public void enter() {
}
@Override
public void exit() {
}  
@Override
public boolean processMessage(Message msg) {
return false;
}   
}   

二 . 把自己的State加入到StateMachine中,並設定預設的State。
見時序圖的addState(),setInitialState()。
三 . 啟動StateMachine。
見時序圖start()。這個時候狀態機已經跑起來了,樹形層次結構儲存State和狀態機的StateStack都已經建立好。
四 . 派發事件訊息。
使用者需要通過sendMessage()派發事件訊息,這個事件訊息的處理,會先由預設的State處理,如果它處理得過來,就return,如果處理不過來,那就跳轉到別的State來處理。這些邏輯都需要在自定義的State中設定好,所以要實現自己的StateMachine,自定義的State之間的事件訊息的處理和各個State之間的跳轉關係尤為重要。

例子1

使用者:DcAsyncChannel.java
狀態機:DataConnection.java

各個State的繼承者:
DcDefaultState
DcInactiveState
DcInactiveState
DcActiveState
DcDisconnectingState
DcDisconnectionErrorCreatingConnection

各個State之間的關係圖:
這裡寫圖片描述

DataConnection.java中的自定義State實現,以下只列出兩個State及其部分程式碼:

private class DcActiveState extends State {
...
public boolean processMessage(Message msg) {
switch (msg.what) {
case EVENT_CONNECT:......
case EVENT_DISCONNECT: transitionTo(mDisconnectingState);......
case EVENT_LOST_CONNECTION: transitionTo(mInactiveState);......
case EVENT_DATA_CONNECTION_ROAM_ON:......
case EVENT_DATA_CONNECTION_ROAM_OFF:......
case EVENT_BW_REFRESH_RESPONSE:......
case EVENT_IPV4_ADDRESS_REMOVED:......
case EVENT_IPV6_ADDRESS_REMOVED:......
case EVENT_VOICE_CALL:......
case EVENT_FALLBACK_RETRY_CONNECTION:......
case EVENT_SETUP_DATA_CONNECTION_DONE:......
}
}
}
private class DcDefaultState extends State {
switch (msg.what) {
case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: 
case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
case DcAsyncChannel.REQ_IS_INACTIVE: 
case DcAsyncChannel.REQ_GET_CID:
case DcAsyncChannel.REQ_GET_APNSETTING:
case DcAsyncChannel.REQ_GET_APNTYPE: 
case DcAsyncChannel.REQ_GET_LINK_PROPERTIES:
case DcAsyncChannel.REQ_SET_LINK_PROPERTIES_HTTP_PROXY: 
case DcAsyncChannel.REQ_GET_NETWORK_CAPABILITIES:
case DcAsyncChannel.REQ_RESET: transitionTo(mInactiveState);
case EVENT_CONNECT:
case EVENT_DISCONNECT: deferMessage(msg);
case EVENT_DISCONNECT_ALL: deferMessage(msg);
case EVENT_TEAR_DOWN_NOW:
case EVENT_LOST_CONNECTION:
case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED:
case EVENT_DATA_CONNECTION_ROAM_ON:
case EVENT_DATA_CONNECTION_ROAM_OFF:
case EVENT_IPV4_ADDRESS_REMOVED:
case EVENT_IPV6_ADDRESS_REMOVED:
case EVENT_ADDRESS_REMOVED:
case EVENT_VOICE_CALL:
}
}

DataConnection.java中把State加入到StateMachine,並設定預設State

addState(mDefaultState);
addState(mInactiveState, mDefaultState);
addState(mActivatingState, mDefaultState);
addState(mActiveState, mDefaultState);
addState(mDisconnectingState, mDefaultState);
addState(mDisconnectingErrorCreatingConnection, mDefaultState);
setInitialState(mInactiveState);
dc.start();

DcAsyncChannel.java中發起事件訊息:

sendMessage(DataConnection.EVENT_CONNECT,
new ConnectionParams(apnContext, profileId, rilRadioTechnology, onCompletedMsg,
connectionGeneration));
sendMessage(DataConnection.EVENT_DISCONNECT,
new DisconnectParams(apnContext, reason, onCompletedMsg));
sendMessage(DataConnection.EVENT_DISCONNECT_ALL,
new DisconnectParams(null, reason, onCompletedMsg));
sendMessage(DataConnection.EVENT_VOICE_CALL, bInVoiceCall ? 1 : 0,
bSupportConcurrent ? 1 : 0);

可以在radio.log中看到它們狀態之間的跳轉:

08-12 19:02:52.465863  1134  1399 D DC-1    : DcDefaultState: FULL_CONNECTION reply connected
08-12 19:02:52.477583  1134  1399 D DC-1    : DcInactiveState: msg.what=EVENT_CONNECT
08-12 19:02:52.661152  1134  1399 D DC-1    : DcActivatingState: msg={what=EVENT_SETUP_DATA_CONNECTION_DONE when=-1ms [email protected] target=Handler (com.android.internal.util.StateMachine$SmHandler) {dbd924d} replyTo=null}
08-12 19:03:23.140182  1134  1399 D DC-1    : DcActiveState msg.what=EVENT_DISCONNECT RefCount=1
08-12 19:03:23.290534  1134  1399 D DC-1    : DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE RefCount=0
08-12 19:03:23.332824  1134  1399 D DC-1    : DcInactiveState nothandled msg.what=EVENT_IPV4_ADDRESS_REMOVED

例子2

使用者:ConnectivityService.java
狀態機:NetworkMonitor.java

各個State的繼承者:
DefaultState 預設狀態
EvaluatingState 驗證狀態
ValidatedState 驗證通過狀態
LingeringState 休閒狀態,表示網路的驗證位是真實的,並且曾經是滿足特定NetworkRequest的最高得分網路,但是此時另一個網路滿足了NetworkRequest的更高分數,在斷開連線前的一段時間前,該網路被“固定”為休閒狀態。
CaptivePortalState 強制門戶狀態
MaybeNotifyState 可能通知狀態,表示使用者可能已被通知需要登入。 在退出該狀態時,應該小心清除通知。

各個State之間的關係圖:
這裡寫圖片描述

程式碼略.