Android StateMachine使用

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);//變更狀態
            }
        }


參考鏈接

[Android] 狀態機 StateMachine 源碼剖析

Android StateMachine

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章