背景
項目遇到點擊事件和動畫開始時機時序問題,在這整理點擊事件產(chǎn)生過程,作備忘。
- 以下假設已經(jīng)理解單次 Activity.dispatchTouchEvent 流程,包括 ViewGroup 和 View 處理
- 已知 android.view.View.OnClickListener#onClick 的執(zhí)行時機和 android.view.View#onTouchEvent 不是同一 Message
- Java 層輸入事件的入口在哪里?
問題
- 從主線程消息隊列的角度看,從 MessageQueue.next 開始到收到 MotionEvent.Down 和 MotiveEvent.Up 事件的主要流程是怎么樣的?
時序圖

OnClick 來源
- 由于 Android UI 設計成事件驅(qū)動,主線程會一直在 android.os.Looper#loop 中取 MessageQueue 中的 Message 出來執(zhí)行
- MessageQueue 每次取一條消息時,先進入 native 層執(zhí)行 native 消息隊列中的消息,再取 Java 層的消息出來執(zhí)行
- 執(zhí)行 android.os.MessageQueue#nativePollOnce 時進入 native 層,對應 android_os_MessageQueue_nativePollOnce 函數(shù),這時的目的是輪詢 native 層消息隊列是否有需要執(zhí)行的消息
- 接下來 Looper#pollOnce 中遍歷所有注冊到其中的 LooperCallback,回調(diào)他們的 handleEvent 方法
- NativeInputEventReceiver 從 InputConsumer 中遍歷當前需要處理的輸入事件
- 拿到 MotionEvent 后通過 JNIEnv 對象調(diào)用 CallVoidMethod 進入 ART 虛擬機
- JNIEnv 對象把方法信息交給反射模塊,查找到 InputEventReceiver 類和 ArtMethod 對象,把信息交給 ArtMethod 對象
- ArtMethod 配置調(diào)用參數(shù),并進入?yún)R編執(zhí)行階段,執(zhí)行 android.view.InputEventReceiver#dispatchInputEvent 對應的機器碼
- 這時進入了 java 層 android.view.InputEventReceiver#dispatchInputEvent 最后分發(fā)給 Activity 對象
- 如果從 DOWN 到 UP 時間很短,那么 NativeInputEventReceiver 會回調(diào)兩次 CallVoidMethod 把事件傳遞給 Activity 對象
總結(jié)
- 了解了主線程在 native 層如何回調(diào) Activity.dispatchTouchEvent 的
- 下一個問題,InputConsumer 如何取到輸入事件的?用戶點擊屏幕,驅(qū)動層先知道這個信息,然后分發(fā)給應用層。但是源碼在哪里?