????關于Android的事件分發(fā)機制,網(wǎng)上的文章快爛大街了, 大多數(shù)文章都是在千篇一律的講activity, viewgroup, view之間的分發(fā)機制, 對于事件的源頭卻沒有提及. 比如, 當手指觸碰屏幕的一瞬間, 手機是怎么知道手指觸碰的哪里, 是觸碰的back鍵, 還是home鍵, 還是哪個坐標點, 是點擊事件, 還是滑動事件等等, 也就是說, Android系統(tǒng)的事件采集是怎樣的. 接下來是怎么把這些采集的事件信息進行處理的, 由誰來處理, 處理完成后又是由誰最后分發(fā)給到具體的activity的?
????有人可能會說, 作為一個普通的Android應用層開發(fā)者, 不需要掌握這些也可以啊, 我不想知道事件是怎么來的, 我只知道事件是怎么分發(fā)的, 我能夠在程序中控制事件就可以了. 的確, 事實是這樣, 不了解這些不影響應用層的開發(fā), 但是如果掌握了這些, 那就太有意思了, 可以做很多有意思的事情, 比如說, 按鍵精靈類的app為什么能夠記憶你的操作, 而且還能夠自動模擬你的操作而解放你的雙手? 其實, 這類app的原理無非就是通過某個辦法來采集到你的所有的操作過程, 即事件采集, 這樣他就記憶下來了, 當需要自動模擬事件的時候, 它會把這些采集到的信息經(jīng)過處理, 轉(zhuǎn)變成可執(zhí)行信息,這樣就能夠?qū)崿F(xiàn)模擬人的雙手來進行自動模擬操作了.
????因為要想講清楚整個事件的采集,處理及分發(fā)過程, 篇幅過大, 因此準備用一個系列文章來講, 本文是系列文章的開篇, 那么先講采集.
(一) 原始事件信息
打開模擬器, 或者用usb把手機連接上電腦并打開手機上面的開發(fā)者模式, (這里為了截圖方便用了模擬器)打開cmd, 輸入adb shell getevent回車, 然后點擊模擬器或者手機后, 就會看到有N多行的/dev/input/event......輸出. 其實, 這些信息就是最原始的事件信息.
(注:嚴格來說最原始的信息肯定是由硬件捕獲到的, 這里所說的原始信息是經(jīng)過硬件處理后返回給framework層的信息)
再看一下, 我們能否通過cmd命令來控制手機來模擬操作事件呢? 重新打開cmd, 或者Ctrl + c退出剛才的命令, 重新執(zhí)行adb shell input keyevent 4 , 發(fā)現(xiàn)手機自動執(zhí)行了返回鍵
(二) 信息分析
以上簡單的演示了下采集信息和發(fā)送信息, 接下來開始解析信息.cmd重新執(zhí)行adb shell getevent -t -l, 再次點擊手機的某個app, 顯示出的信息是這樣的:
前面[ 13236.364793]顯示的是時間, 是手機或模擬器開機后到命令執(zhí)行時的時間間隔, 后面顯示的是具體命令, 其中, /dev/input/event1表示的是屏幕的輸入事件, 第一個ABS_MT_TRACKING_ID 表示采集信息開始, 后一個ABS_MT_TRACKING_ID表示采集信息結束, ABS_MT_PRESSURE表示的是屏幕感受到的壓力值, SYN_REPORT 表示的是同步數(shù)據(jù), 最重要的是ABS_MT_POSITION_X和ABS_MT_POSITION_Y, 毫無疑問, 這個就是表示屏幕感受到的觸碰坐標位置. 最右邊的一列是16進制的值.
其他的信息我們可以先忽略, 最主要的是要記錄時間和坐標點, 接下來就是把采集到的坐標點轉(zhuǎn)換成10進制的坐標點, x坐標采集到的值是00005487,轉(zhuǎn)換10進制是21639, 同理, y坐標轉(zhuǎn)換前是00006b5b, 轉(zhuǎn)換后是27483, 接下來需要根據(jù)公式來獲取到真正的應用層能識別的坐標系, 具體公式為:
x = (x-xmin) * 手機像素寬 / (xmax-xmin) ;
y = (y-ymin) * 手機像素高 / (ymax-ymin);
手機像素我們可以通過代碼獲取當前手機的像素, 但是xmin和xmax, 以及ymin和ymax是什么呢?我們還是通過cmd用adb shell getevent -p命令來獲取. 執(zhí)行命令后,拉到最下方, 看到如下圖示:
我們找到0035和0036的行, 即
0035 : value 0, min 0, max 32767, fuzz 0, flat 0, resolution 0
0036 : value 0, min 0, max 32767, fuzz 0, flat 0, resolution 0
0035所在的行就是x信息, 0036所在的行就是y信息, 每行的min值和max值對應上面公式的min和max, 所以我這里最終轉(zhuǎn)換成的x, y坐標結果如下: (我的模擬器經(jīng)過代碼獲取的寬高分辨率分別是480, 728)
x = (21639 - 0) * 480 / (32767 - 0) = 317
y = (27483 - 0) * 728 / (32767 - 0) = 610
即當點擊手機桌面屏幕的(317, 610)坐標, 就打開了這個app, 那么我們接下來驗證一下, 通過cmd來發(fā)送命令, 來模擬點擊事件, 看看模擬器或者手機是不是能打開這個app呢?
重新打開cmd, 執(zhí)行adb shell input tap 317 610命令, 結果如下:
我們成功的通過命令來模擬點擊桌面應用了. 其實整個過程就是一個采集信息梅肤,處理信息键科,發(fā)送信息的過程腥光。
到這里, 其實我們就可以自己開發(fā)出來一個類似按鍵精靈類的簡單版app了, 大體思路就是在app中給一個按鈕,用來觸發(fā)信息采集, 之后用戶的一切觸碰屏幕操作都進行錄入, 再給一個結束采集的按鈕, 觸發(fā)按鈕就結束信息錄入, 并開始處理信息, 包括每個動作的屬性(是點擊, 還是滑動, 還是長按等等), 相鄰動作的時間間隔, 等等, 然后保存起來, 最后再給一個自動模擬事件的按鈕, 當觸發(fā)時, 程序開始自動讀取保存的事件信息并執(zhí)行模擬事件了.
以上, 是我們?nèi)藶榈倪M行事件采集, 處理, 發(fā)送. 那么Android系統(tǒng)內(nèi)部是怎么做的呢? 是誰負責把這個事件信息處理后轉(zhuǎn)換成為各種KeyEvent或者MotionEvent的, 以及最終是怎么傳遞到的activity中的, 請關注系列文章之后的文章枫弟。