閱讀450 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Android狀態機(藍牙)

https://blog.csdn.net/wsb1321/article/details/8021620

Android係統中對於WIFI,藍牙模塊運用了狀態機來管理狀態。搜索了下4.0中的狀態機有以下文件:

./frameworks/base/wifi/java/android/net/wifi/WpsStateMachine.java
./frameworks/base/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
./frameworks/base/wifi/java/android/net/wifi/WifiStateMachine.java
./frameworks/base/core/java/android/net/dhcp/DhcpStateMachine.java
./frameworks/base/core/java/android/net/DhcpStateMachine.java
./frameworks/base/core/java/android/server/BluetoothAdapterStateMachine.java

以上的類都是繼承於./frameworks/base/core/java/com/android/internal/util/StateMachine.java。

係統為了好管理,將一個模塊的不同狀態封裝成State,而StateMachine就是用來管理這些State的。

看一下State類中提供的主要方法有:

 @Override
    public void enter() {
    }

    /* (non-Javadoc)
     * @see com.android.internal.util.IState#exit()
     */
    @Override
    public void exit() {
    }

    /* (non-Javadoc)
     * @see com.android.internal.util.IState#processMessage(android.os.Message)
     */
    @Override
    public boolean processMessage(Message msg) {
        return false;
    }

 @Override
    public String getName() {
        String name = getClass().getName();
        int lastDollar = name.lastIndexOf('$');
        return name.substring(lastDollar + 1);
    }

再回到StateMachine.java這個文件,在這個文件開始有一大堆的英文說明該類的作用和實現過程。下麵結合自己的理解梳理下這段內容:


用法準備條件:首先根據需要要生成我們的State, 比如  private class PowerOff extends State{}(引用源代碼中管理Bt的一個狀態),我們定義的這個類必須繼承State這個類並根據需要實現相應的方法,其中的processMessage這個方法必須實現(如果不重寫這個方法,那我們的狀態機將沒有任何意義)。enter()方法是當我們進入該狀態的時候第需要調用的(像程序代碼中的構造函數),exit()是退出該狀態的時候調用(像析構函數)。


當準備好State後,就在調用addState(State state, State parent)將我們的狀態添加進StateMachine。


到這裏首先看下StateMachine還有些什麼內容。

內部類:SmHandler(大部分處理都是通過這個類完成),ProcessedMessageInfo,ProcessedMessages。在SmHandler中又包含內部類StateInfo,成員StateMachine(mSm),HashMap<State, StateInfo> mStateInfo,mStateStack,mDeferredMessages,State mInitialState,  State mDestState, rivate ArrayList<Message> mDeferredMessages。

啟動狀態機的步驟:

1.首先需要通過addState添加上麵準備好的State實例,每一個State都可以添加一個自身的State和一個parentState。add的方法最中是通過調用SmHandler的StateInfo addState(State state, State parent)方法。這個方法會將他的狀態以及他的父狀態的信息取出來並放到mStateInfo這個hashMap表中的(首先會從mStateInfo中通過State找一下是否存在該狀態的相關信息,不存在才會put)。

2.添加完所有的狀態後就調用setInitialState設置一個初始狀態, 最終調用的是SmHandler的setInitialState給mInitialState賦值。

3當經過1,2步驟後就要調用StateMachine:start()函數啟動狀態機機,start函數最終調用的是SmHandler:completeConstruction ,這個函數主要是調用exit退出當前狀態並更新記錄的State的堆棧信息(mStateStack中的State)並掉用State的enter函數,正式進入新的狀態。

4.當我們通過StateMachine:sendMessage發送消息的時候,StateMachine就會找到當前的State調用其processMessage來做相應的處理動作。如果當前狀態在處理完相應的事務後需要切換到新的狀態就需要調用transitionTo(IState destState)設置mDestState的值。

注意:上麵說過一個State可能包含一個Parent State,如果在當前的State中沒有能處理發送來的msg的時候,就要向上找其父State來處理,依次向上遍曆,如果所有的State都不能處理的話就會調用SmHandler:unhandledMessage來處理。


另外兩個方法:deferMessage和sendMessageAtFrontOfQueue,在代碼中可以通過deferMessage向mDeferredMessages這種存放暫時不處理的消息。在每此處理完新舊狀態更新的時候就要調用sendMessageAtFrontOfQueue將mDeferredMessages中的消息優先發送出去(有可能是在A狀態deferMessage的消息,切換到B狀態後才發送出去,此時就應該B狀態去處理這個消息),每次發送完就會清空mDeferredMessages一次。


圖表解釋:

        mP0

        /        \

       mP1   mS0

      /         \

    mS2     mS1

    /         \        \

   mS3  mS4  mS5 ---> initial state


如上圖,添加了mS5至mP0的8個狀態, 其中mS1是mS5的父狀態,mP1是mS1的父狀態,依次類推。上圖可以看出mS5是初始狀態,當啟用狀態機的收回調用StateMachine:start()----->SmHandler:completeConstruction(),這函數裏麵會調用invokeEnterMethods從而依次調用mP0--mP1--mS1--mS5的enter函數,並將他們每一個對應的StateInfo的active置為true。最後調用的是mS5,所以當前的狀態進入mS5。此時如果外麵有消息通過StateMachine:sendMessage發送進來,首先就會mS5----mP0依次調用processMessage的方法來出來當前消息直到處理成功(如果mS5就處理成功就跳出了,就不會進入mS1, 以此類推)。


假設現在mP0----mS5處理發送來的消息成功,並且transitionTo(mS4),往上遍曆發現有共同祖先mP1,那麼就會依次調用mS5---mS1的exit函數,依次調用mS2---mS4的enter函數從而進入mS4狀態。現在處於active的狀態就是mS4,mS2,mP1,mP0了,下次來消息的時候就該mS4來處理了。


StateMachine的基本原理就是這樣,StateMachine基本線路就在SmHandler的中handleMessage函數。 下一篇將會結合藍牙狀態機的轉換進行具體的介紹。







最後更新:2017-04-03 12:55:35

  上一篇:go Android 如何把Launcher桌麵的每一屏修改為x*x(例如5*5)的布局
  下一篇:go 二分搜索-切蛋糕