Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android核心分析(15)--------Android輸入系統之輸入路徑詳解

Android核心分析(15)--------Android輸入系統之輸入路徑詳解

編輯:Android開發實例

Android用戶事件輸入路徑

 

1 輸入路徑的一般原理

 

      按鍵,鼠標消息從收集到最終將發送到焦點窗口,要經歷怎樣的路徑,是Android GWES設計方案中需要詳細考慮的問題。按鍵,鼠標等用戶消息消息的處理可分為不同的情況進行判定:

(1)用戶輸入根據系統狀況是否應該派送。如在ScreenOff的情況下,在按鍵屬於特殊按鍵的情況下等

(2)是否有攔截Listener

(3)對按鍵事件來講,是否存在輸入法

(4)是否是焦點終點

(5)是否為焦點切換按相關鍵

這些情況都是設計輸入路徑需要考慮的基本條件。

1.1一般的輸入路徑設計

該輸入路徑實際上是指的按鍵消息(MSG_KEYDOWN,MSG_KEYUP, MSG_LongPress)的輸入路徑,即從活動主窗口到焦點窗口所經歷的路程。

將信息輸入路徑分為兩步:

Step 1)窗口管理器將信息發送到活動窗口

Step 2)活動窗口通過缺省處理函數將該消息一層層的傳遞到焦點。

這樣應用程序可以在活動View的處理函數中來預先處理用戶輸入信息,從而增強應用對用戶信息的控制力。

傳遞路徑是通過View的缺省處理函數Onxxx來完成。通過ActiveView ->focus->focus->focus的鏈條關系,一級一級的將按鍵消息MSG_KEYDOWN,MSG_KEYUP, MSG_CHAR等傳遞到focus窗口。

此時用戶按鍵輸入先發送到輸入法窗口,經過輸入法管理器處理,過濾後將輸入法產生的結果放置到焦點View。

1.3輸入系統整體流程

下面示意圖是Android輸入系統的數據流途徑,通過WM的輸入系統線程收集消息,分發到Focus Activity消息隊列,然後通過消息系統派發。

 

 

2 Android輸入路徑詳細描述

 

  2.1 第一步:用戶數據收集及其初步判定

     KeyInputQ在WindowMangerService中建立一個獨立的線程InputDeviceReader,使用Native函數readEvent來讀取Linux Driver的數據構建RawEvent,放入到KeyQ消息隊列中。

preProcessEvent()@[email protected]這個是在輸入系統中的第一個攔截函數原型。KeyQ重載了preProcessEvent()@WindowManagerService.java。在該成員函數中進行如下動作:

(1) 根據PowerManager獲取的Screen on,Screen off狀態來判定用戶輸入的是否WakeUPScreen。

(2) 如果按鍵式應用程序切換按鍵,則切換應用程序。

(3) 根據WindowManagerPolicy覺得該用戶輸入是否投遞。

2.2 第二步 消息分發第一層面

InputDispatcherThread從KeyQ中讀取Events,找到Window Manager中的Focus Window,通過Focus Window記錄的mClient接口,將Events專遞到Client端。

如何將KeyEvent對象傳到Client端:

在前面的章節(窗口管理ViewRoot,Window Manager Proxy)我們已經知道:在客戶端建立Window Manager Proxy後,添加窗口到Window Manager service時,帶了一個跟客戶ViewRoot相關的IWindow接口實例過去,記錄在WindowState中的mClient成員變量中。通過IWindow這個AIDL接口實例,Service可以訪問客戶端的信息,IWindow是Service連接View橋梁。

看看在Client ViewRootKeyEvent的分發過程

IWindow:dispatchKey(event)

dispatchKey(event)@[email protected]@ViewRoot.java

       ViewRoot.dispatchKey(event)@ViewRoot.java

                     message>

                     sendMessageAtTime(msg)@[email protected]

至此我們通過前面的Looper,Handler詳解章節的分析結論,我們可以知道Key Message已經放入到應用程序的消息隊列。

2.3第三步:應用消息隊列分發

   消息的分發,在Looper,Handler詳解章節我們分析了Looper.loop()在最後後面調用了handleMesage.

          …

           ActivityThread.main()

                Looper.loop()

                  ViewRoot$RootHandler().dispatch()

                      handleMessage

                          ....

      注意到在分發的調用msg.target.dispatch(),而這個target在第二層將消息sendMessageAtTime到消息隊列時填入了mag.target=this即為msg.target=ViewRoot實例。所有此時handleMessage就是ViewRoot重載的handleMessage函數。

[email protected]@ViewRoot.java

       deliverkeyEvent

            如果輸入法存在,dispatchKey到輸入法服務。

            否則[email protected]

     在這裡需要強調的是,輸入法的KeyEvent的攔截並沒有放入到Window Manager Service中,而是放入到了客戶端的RootView中來處理。

2.4第四步:向焦點進發,完成焦點路徑的遍歷。

分發函數調用棧

[email protected]

mView.dispatchKeyEvent:mView是與ViewRoot相對應的Top-Level View.如果mView是一個ViewGroup則分發消息到他的mFocus。

mView.dispatchKeyEvent @ViewGroup  ([email protected])

               Event.dispatch

                        mFocus.dispatchKeyEevnet

    如果此時的mFocu還是一個ViewGroup,這回將事件專遞到下一層的焦點,直到mFocus為一個View。通過這輪調用,就遍歷了焦點Path,至此,用戶事件傳遞完成一個段落。

2.5第五步 缺省處理

如果事件在上述Focus View沒有處理掉,並且為方向鍵之類的焦點轉換相關按鍵,則轉移焦點到下一個View。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved