1. StateMachineJar的封裝
把源碼的如下3個文件,提取爲jar包使用就可以
frameworks/base/core/java/com/android/internal/util/StateMachine.java
frameworks/base/core/java/com/android/internal/util/State.java
frameworks/base/core/java/com/android/internal/util/IState.java
2. 使用示例
StateMachine的基本使用必須按如下四個步驟進行,缺一不可:
- 繼承StateMachine,StateMachine類的構造函數是Protect訪問權限,所以只能通過繼承實現實例化
- 通過addState方法構造狀態層次結構(樹形結構,可多棵),狀態層次結構根據狀態轉移圖構建,各種狀態需要繼承State類,實現自己相應業務邏輯
- 通過setInitialState設置初始狀態
- 調用start方法啓動狀態機
其他常用API如下表所示:
Method | Description |
---|---|
quit() | 停止狀態機,會進入QuttingState |
sendMessage(Message msg) | 發送一個消息,供各狀態處理 |
deferMessage(Message msg) | 發送一個延遲消息,在下一次狀態轉換時,纔會被放入消息隊列 |
transitionTo(IState state) | 轉移至相應狀態 |
transitionToHaltingState() | 進入HaltingState |
示例:
繼承StateMachine並初始化
package com.mtest.statemachine;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.bluesky.statemachinejar.State;
import com.bluesky.statemachinejar.StateMachine;
import com.mtest.statemachine.state.ErrorState;
import com.mtest.statemachine.state.ExitState;
import com.mtest.statemachine.state.IdleState;
import com.mtest.statemachine.state.NormalState;
import com.mtest.statemachine.state.StartRecgState;
import java.util.HashMap;
import java.util.Map;
public class FaceStateMachine extends StateMachine {
private static final String NAME = "FaceStateMachine";
private static final String TAG = "FaceStateMachine";
/*定義的幾個狀態機狀態,包括初始狀態,開始識別,識別正常,識別異常,退出識別*/
public static final int IDLE_STATE = 1;
public static final int START_RECG_STATE = 2;
public static final int RECG_NORMAL_STATE = 3;
public static final int RECG_ERROR_STATE = 4;
public static final int RECG_EXIT_STATE = 5;
private static volatile FaceStateMachine sFaceStateMachine;
private Map<String, State> mStateMap = new HashMap<>();
/*繼承的StateMachine,super需要添加狀態機名字,並且運行在主線程*/
protected FaceStateMachine() {
super(NAME, Looper.getMainLooper());
initStateMachine();
}
/*狀態機這裏採用單例模式,用於管理*/
public static FaceStateMachine get() {
synchronized (FaceStateMachine.class) {
if (sFaceStateMachine == null) {
synchronized (FaceStateMachine.class) {
sFaceStateMachine = new FaceStateMachine();
}
}
}
return sFaceStateMachine;
}
/*
* 構造狀態機需要添加初始狀態,StateMachine是樹結構的狀態機,因此要添加父節點
* setInitialState:設置初始狀態 start開始狀態機
* */
private void initStateMachine() {
IdleState idleState = new IdleState();
StartRecgState startRecg = new StartRecgState();
addInitStateMachine(idleState);
addInitStateMachine(startRecg);
addInitStateMachine(new NormalState(), startRecg);
addInitStateMachine(new ExitState(), startRecg);
addInitStateMachine(new ErrorState(), startRecg);
setInitialState(idleState);
start();
}
/*
* 調用addState完成添加狀態機,可以直接添加,也可以添加父類關係
*
* mStateMap用於保存,狀態State的集合,通過getState()獲取狀態名,用於切狀態
* */
private void addInitStateMachine(State childState) {
mStateMap.put(childState.getClass().getSimpleName(),childState);
addState(childState);
}
private void addInitStateMachine(State childState, State parentState) {
mStateMap.put(childState.getClass().getSimpleName(),childState);
addState(childState, parentState);
}
public State getState(String name) {
return mStateMap.get(name);
}
/*
* 如果不添加sendMessage,直接調用transitionTo,根本就不會執行切狀態
*
* */
/*模擬發送消息*/
public void doSendEventByStartRecg() {
Log.d(TAG , "doSendEventByStartRecg:");
transitionTo(getState(StartRecgState.class.getSimpleName()));
sendMessage(START_RECG_STATE);
}
}
base狀態機
package com.mtest.statemachine.state;
import android.os.Message;
import android.util.Log;
import com.bluesky.statemachinejar.State;
import com.bluesky.statemachinejar.StateMachine;
import com.mtest.statemachine.FaceStateMachine;
/*用於自己創建的狀態機基類,作爲所有state繼承用*/
public class BaseState extends State {
public static final String TAG = BaseState.class.getSimpleName();
/*
* 狀態機進程時候執行,像初始化
* */
@Override
public void enter() {
super.enter();
Log.d(TAG,"enter...");
}
/*退出時候執行,釋放資源*/
@Override
public void exit() {
super.exit();
Log.d(TAG,"exit...");
}
/*
*消息處理,發送消息後才能切換狀態機,不知道爲什麼
* */
@Override
public boolean processMessage(Message msg) {
switch (msg.what) {
case FaceStateMachine.START_RECG_STATE:
Log.d(TAG, "processMessage: START_RECG_STATE");
break;
case FaceStateMachine.RECG_NORMAL_STATE:
Log.d(TAG, "processMessage: RECG_NORMAL_STATE");
break;
case FaceStateMachine.RECG_ERROR_STATE:
Log.d(TAG, "processMessage: RECG_ERROR_STATE");
break;
case FaceStateMachine.RECG_EXIT_STATE:
Log.d(TAG, "processMessage: RECG_EXIT_STATE");
break;
default:
break;
}
return StateMachine.NOT_HANDLED;
}
@Override
public String getName() {
return super.getName();
}
}
定義一個狀態
package com.mtest.statemachine.state;
import android.os.Message;
import android.util.Log;
import com.mtest.presenter.StateMessageHander;
import com.mtest.statemachine.FaceStateMachine;
public class ExitState extends BaseState{
public static final String TAG = ExitState.class.getSimpleName();
@Override
public void enter() {
super.enter();
Log.d(TAG, "ExitState: enter");
StateMessageHander.getInstance().sendEmptyMessage(StateMessageHander.DO_RECG_EXIT_STATE);
}
@Override
public void exit() {
super.exit();
}
@Override
public boolean processMessage(Message msg) {
switch (msg.what) {
case FaceStateMachine.START_RECG_STATE:
Log.d(TAG, "processMessage: START_RECG_STATE");
//FaceStateMachine.get().transitionTo(FaceStateMachine.get().getState());
break;
case FaceStateMachine.RECG_NORMAL_STATE:
Log.d(TAG, "processMessage: RECG_NORMAL_STATE");
break;
case FaceStateMachine.RECG_ERROR_STATE:
Log.d(TAG, "processMessage: RECG_ERROR_STATE");
break;
case FaceStateMachine.RECG_EXIT_STATE:
Log.d(TAG, "processMessage: RECG_EXIT_STATE");
break;
default:
break;
}
return super.processMessage(msg);
}
}
3. 使用注意
通常,我們會在 State.processMessage 內部,通過調用 transitionTo 函數執行一次狀態轉換,而調用這個函數只是將你要轉換的狀態存入一個臨時的對象中:
protected final void transitionTo(IState destState) {
mSmHandler.transitionTo(destState);
}
private final void transitionTo(IState destState) {
mDestState = (State) destState;
}
複製代碼真正的狀態轉換將發生在 SmHandler.handleMessage 函數執行之後:
public final void handleMessage(Message msg) {
if (!mHasQuit) {
...
performTransitions(msgProcessedState, msg);//變更狀態
}
}
參考鏈接