<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                HSM(對應的類是StateMachine)和AsyncChannel是Android Java Framework中兩個重要的類。不過,它們目前還僅由Framework內部使用,SDK中并沒有包含它們。這兩個類的作用如下。 * HSM在傳統狀態機對所有狀態都一視同仁的基礎上做了一些改變,使得狀態和狀態之間有了層級關系。HSM中的狀態層級關系與Java中父子類的派生和繼承關系類似,即在父狀態中實現generic的功能,而在子狀態中實現一些特定的處理。不過,和Java中類派生不同的是,HSM中父子狀態對應的是毫無派生關系的兩個類,所以使用時需要創建兩個對象。而Java中子類則從其父類派生,實際使用時創建一個子類對象即可,該子類對象就能完成父類的工作。 * AsyncChannel用于兩個Handler之間的通信。具體的通信方式為源Handler通過sendMessage向目標Handler發送消息,而目標Handler通過replyToMessage回復源Handler處理結果。注意,這兩個Handler可位于同一個進程,也可分屬兩個不同的進程。 本節先來介紹HSM。 >[info] 注意 由于HSM和AsyncChannel并非本書的主題,故本章僅介紹它們的用法。對實現原理感興趣的讀者不妨在了解它們用法的基礎上,自行研究相關代碼。 **1、HSM使用** HSM對應的類叫StateMachine,下面通過一個例子來介紹其用法。 **HSM示例** ~~~ // 此例來源于StateMachine.java文件中的注釋 // StateMachineTest是StateMachine的子類 class StateMachineTest extends StateMachine { StateMachineTest(String name) { super(name); // 為狀態機添加一個狀態。代碼中一般用縮進的方式表達層級關系 addState(mP0); // 添加一個狀態mS0,其父狀態為mP0 addState(mS0, mP0); addState(mP1, mP0); addState(mS1,mP1); // 添加一個狀態mS1,其父狀態為mP1 addState(mS5,mS1) addState(mS2, mP1); addState(mS3, mS2); addState(mS4, mS2); // setInitialState函數用于設置狀態機的初始狀態,本例中該狀態是mS5 setInitialState(mS5); }// StateMachineTest構造函數結束 } ~~~ 上述代碼中StateMachineTest所涉及的狀態及層級關系如圖5-2所示。 :-: ![](https://box.kancloud.cn/b4077a513480ef36c28e65d4442f9c47_493x366.jpg) 圖5-2 HSM示例中狀態關系 圖5-2中,mS5是初始狀態,由代碼中的setInitialState函數設置。接著來看StateMachineTest的代碼。 **HSM示例** ~~~ // 接上面的代碼。P0從State類派生。在HSM中,狀態由類State來表達 class P0 extends State { /* enter代表一個狀態的Entry Action,SM進入此狀態時將調用其EA。 exit代表一個狀態的Exit Action,SM退出某狀態時將調用其EXA。 */ public void enter() { ......// do sth here } public void exit() { ......// do sth here } /* 除了EA和EXA外,每個State中最重要的函數就是processMessage了。 在HSM中,外界和HSM交互的方式就是向其sendMessage。Message由當前State的processMessage 函數來處理。如果當前State成功處理此message,則返回HANDLED。否則返回NOT_HANDLED。 在Message處理中,如果子狀態返回NOT_HANDLED,則其父狀態的processMessage將被調用。 如果當前狀態及祖先狀態都不能處理,則HSM的unhandledMessage將被調用。而HSM的派生類 可重載unhandledMessage函數以處理這個不能被當前狀態及祖先狀態處理的消息。 */ public boolean processMessage(Message message) { return HANDLED; // P0能處理任何Message } } class P1 extends State { ......// 實現P1的enter,exit和processMessage函數 } class S0 extends State { ......// 實現S0的enter,exit和processMessage函數 } ......// S1到S4的定義 class S5 extends State { public void enter() { ......// 實現S5的enter函數 } public void exit() { ......// 實現S5的exit函數 } public boolean processMessage(Message message) { switch(message.what){ case: TRANSITION_CMD: transitionTo(mS4);// 切換狀態時,需要調用此函數 break; case: TRANSITON_CMD_DEFER_MSG: // deferMessage用于保留某個消息。而被保留的消息將留待到下一個狀態中去處理 deferMessage(message); transitionTo(mS1); break; default: break; } return HANDLED; } } ......// StateMachine其他一些可重載函數。以后碰到它們時再介紹 // 定義各個狀態對應的對象 private P0 mP0 = new P0(); private P1 mP1 = new P1(); private S0 mS0 = new S0(); private S1 mS1 = new S1(); private S2 mS2 = new S2(); private S3 mS3 = new S3(); private S4 mS4 = new S4(); private S5 mS5 = new S5(); // 定義消息 final static int TRANSITION_CMD = 0; final static int TRANSITON_CMD_DEFER_MSG = 1; // 主函數 public void main() throws Exception { StateMachineTest smTest = new StateMachineTest("StateMachineTest"); smTest.start(); // 啟動狀態機 synchronized (sm5) { // 外界只能通過obtainMessage以及sendMessage發送消息給SM去執行 smTest.sendMessage(obtainMessage(TRANSITION_CMD)); smTest.sendMessage(obtainMessage(TRANSITON_CMD_DEFER_MSG)); ...... } ...... } ~~~ 上面代碼介紹了HSM中一些重要的API。 * addState:添加一個狀態。同時還可指定父狀態。 * transitionTo:將狀態機切換到某個狀態。 * obtainMessage:由于HSM內部是圍繞一個Handler來工作的,所以外界只能調用HSM的obtainMessage以獲取一個Message[^①]。 * sendMessage:發送消息給HSM。HSM中的Handler會處理它。 * deferMessage:保留某個消息。該消息將留待下一個新狀態中去處理。其內部實現就是把這些被deferred的message保存到一個隊列中。當HSM切換到新狀態后,這些deferred消息將被移到HSM內部Handler所對應消息隊列的頭部,從而新狀態能首先處理這些deferred消息。 * start:啟動狀態機。 * 停止狀態機可使用quit或quitNow函數。這兩個函數均會發送SM_QUIT_CMD消息給HSM內部的Handler,不過效果略有區別。當使用quit時,SM_QUIT_CMD添加在消息隊列尾;而使用quitNow時,SM_QUIT_CMD被添加到消息隊列頭。 HSM中狀態和狀態之間的層級關系體現在哪些方面呢?以上述代碼為例: * SM啟動后,初始狀態的EA將按派生順序執行。即其祖先狀態的EA先執行,子狀態的EA后執行。以示例代碼中的初始狀態mS5為例。當HSM的start調用完畢后,EA調用順序為mP0、mP1、mS1、mS5。 * 當State發生切換時,舊State的exit先執行,新State的enter后執行,并且新舊State派生樹上對應的State也需要執行exit或enter函數。以mS5切換到mS4為例,在此切換過程中,首先執行的是EXA,其順序是mS5,mS1。注意,EXA執行的終點是離mS4和mS5最近的一個公共(即同時是mS4和mS5的祖先)祖先State(此處是mP1),但公共祖先狀態的EXA不會執行。然后執行的是EA,其順序是mS2、mS4。同理,公共祖先的EA也不會執行。細心的讀者可以發現,HSM中EA和EXA執行順序和C++類構造/析構函數執行順序類似。EA執行順序由祖先類開始直至子孫類,而析構函數的執行先從子孫類開始,直到祖先類。 * State處理Message時,如果子狀態不能處理(返回NOT_HANDLED),則交給父狀態去處理。這一點也和C++中類的派生函數類似。 HSM的介紹就到此為止,感興趣的讀者可自行研究HSM的實現。 **2、AsyncChannel使用** AsyncChannel用于兩個Handler之間的通信,其用法包含兩種不同的應用模式(usagemodel)。 * 簡單的request/response模式下,Server端無須維護Client的信息,它只要處理來自Client的請求即可。連接時,Client調用connectSync(同步連接)或connect(異步連接,連接成功后Client會收到CMD_CHANNEL_HALF_CONNECTED消息)即可連接到Server。 * 與request/response模式相反,AsyncChannel中另外一種應用模式就是Server端維護Client的信息。這樣,Server可以向Client發送自己的狀態或者其他一些有意義的信息。與這種模式類似的應用場景就是第4章介紹的wpa_cli和wpa_supplicant。wpa_cli可以發送命令給WPAS去執行。同時,WPAS也會將自己的狀態及其他一些消息通知給wpa_cli。 在WifiService相關模塊中,第二種應用模式使用得較多。另外,AsyncChannel中Client和Server端在最開始建立連接關系時,可以采用同步或異步的方式。以異步方式為例介紹第二種應用模式中AsyncChannel的使用步驟。 1. Client調用AsyncChannel的connect函數。Client的Handler會收到一個名為CMD_CHANNEL_HALF_CONNECTED消息。 2. Client在處理CMD_CHANNEL_HALF_CONNECTED消息時,需通過sendMessage函數向Server端發送一個名為CMD_CHANNEL_FULL_CONNECTION的消息。 3. Server端的Handler將收到此CMD_CHANNEL_FULL_CONNECTION消息。成功處理它后,Server端先調用AsyncChannel的connected函數,然后通過sendMessage函數向Client端發送CMD_CHANNEL_FULLY_CONNECTED消息(特別注意,詳情見下文)。 4. Client端收到CMD_CHANNEL_FULLY_CONNECTED消息。至此,Client和server端成功建立連接。 5. Client和Server端的兩個Handler可借助sendMessage和replyToMessge來完成請求消息及回復消息的傳遞。注意,只有針對那些需要回復的情況,Server端才需調用replyToMessage。 6. 最后,Client和Server的任意一端都可以調用disconnect函數以結束連接。該函數將導致Client和Server端都會收到CMD_CHANNEL_DISCONNECTED消息。 >[info] 特別說明 上述步驟的描述來自AsyncChannel.java文件中的注釋。但實際上Server端代碼在處理CMD_CHANNEL_FULL_CONNECTION消息時并不能按照上面的描述開展工作。因為AsyncChannel對象一般由客戶端創建,而CMD_CHANNEL_FULL_CONNECTION消息無法攜帶AsyncChannel對象(AsyncChannel對象無法通過Binder進行跨進程傳遞)。所以,Server端并不能獲取客戶端創建的這個AsyncChannel對象,它也就沒辦法調用AsyncChannel的connected函數。 那么,Server端的正確處理應該是什么樣子呢?接下來將通過代碼向讀者展示正確的做法。 下面結合WifiManager中的相關代碼來介紹AsyncChannel中第二種模式涉及的一些重要函數。 WifiManager的init函數中會創建一個AsyncChannel以和WifiService中的某個Handler建立連接關系,代碼如下所示。 **WifiManager.java::init** ~~~ private void init() { /* 該函數內部通過Binder機制調用WifiService的getWifiServiceMessgener函數,返回值 是一個類型為Messagener的對象。Messgener從Parcelable派生,其內部有一個IMessenger 對象用于支持跨進程的Binder通信[^②]。 WifiService中,getWifiServiceMessgener的代碼如下。 public Messenger getWifiServiceMessenger() { ......// 權限檢查 return new Messenger(mAsyncServiceHandler);// 通過Messenger封裝了目標Handler } */ mWifiServiceMessenger = getWifiServiceMessenger(); ...... // 創建一個HandlerThread。對HandlerThread不熟悉的讀者請參考腳注 sHandlerThread = new HandlerThread("WifiManager"); sHandlerThread.start(); // Client中的Handler,它將運行在sHandlerThread線程中 // AsyncChannel對Client Handler運行在什么線程沒有要求 mHandler = new ServiceHandler(sHandlerThread.getLooper()); /* connect是AsyncChannel的重要函數。此處使用的connect函數原型如下: connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) srcContext:為Client端的Context對象,AsyncChannel內部將使用它。 srcHandler:為Client端的Handler。 dstMessgener:是Server端Handler在Client端的代表。 */ mAsyncChannel.connect(mContext, mHandler, mWifiServiceMessenger); ...... } ~~~ connect函數將觸發Client端Handler收到一個CMD_CHANNEL_HALF_CONNECTED消息。馬上來看WIfiManager中ServiceHandler。 Messgener從Parcelable派生,其內部有一個IMessenger對象用于支持跨進程的Binder通信[^②]。 **WifiManager.java::ServiceHandler** ~~~ private class ServiceHandler extends Handler { ......// 此處只關注和AsyncChannel相關的內容 public void handleMessage(Message message) { ...... switch (message.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:// 半連接成功 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { // 向Server端發送CMD_CHANNEL_FULL_CONNECTION消息 mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); }...... break; case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED: // 連接成功 break; case AsyncChannel.CMD_CHANNEL_DISCONNECTED:// 連接關閉 mAsyncChannel = null; getLooper().quit();// 連接關閉,退出線程 break; ...... } ...... } } ~~~ WifiService中的目標Handler是AsyncServiceHandler,其代碼如下所示。 **WifiService::AsyncServiceHandler** ~~~ private class AsyncServiceHandler extends Handler { ...... // 請讀者先看它是如何處理CMD_CHANNEL_FULL_CONNECTION消息的 public void handleMessage(Message msg) { switch (msg.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { // 處理因ac.connect調用而收到的CMD_CHANNEL_HALF_CONNECTED消息 // 該消息攜帶了一個AsyncChannel對象,即ac if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { // 保存這個AsyncChannel對象,用于向Client發送消息 mClients.add((AsyncChannel) msg.obj); /* 注意,Server端可在此處向Client端發送CMD_CHANNEL_FULLY_CONNECTED消息。 例如: AsyncChannel sample = (AsyncChannel) msg.obj; sample.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED); */ } break; } case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { mClients.remove((AsyncChannel) msg.obj); break; } case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {// Server端先收到此消息 /* 新創建一個AsyncChannel對象ac,然后調用它的connect函數。其中: msg.replyTo代表Client端的Handler,也就是WifiManager中ServiceHandler。 connect函數將觸發CMD_CHANNEL_HALF_CONNECTED消息被發送,而且該消息 會攜帶對應的AsyncChannel對象,即此處的ac。 請讀者回到handleMessage的前面去看CMD_CHANNEL_HALF_CONNECTED的處理。 */ AsyncChannel ac = new AsyncChannel();// 創建一個新的AsyncChannel對象 ac.connect(mContext, this, msg.replyTo); break; } ...... } } } ~~~ 根據WifiService的代碼并結合上文“特別說明”,由于Server端無法得到Client端的AsyncChannel對象,所以它干脆自己又新創建了一個AsyncChannel,并connect到客戶端。這樣,Server和Client端實際上有兩個不同的AsyncChannel對象,并且都需要調用connect函數。 >[info] 提示 如果AsyncChannel支持跨進程傳遞,那么Server端只要獲取Client端傳遞過來的AsyncChannel對象,并調用其connected(注意,不是connect)函數即可。 介紹完HSM和AsyncChannel后,馬上來看WifiService的創建和相關的初始化工作。 [^①]:關于Android中Handler的實現原理,讀者可閱讀《深入理解Android:卷Ⅰ》5.4節。 [^②]:關于Java Binder的實現機制,讀者可參考《深入理解Android:卷Ⅱ》第2章。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看