Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android View框架總結(九)KeyEvent事件分發機制

Android View框架總結(九)KeyEvent事件分發機制

編輯:關於Android編程

本篇開始分析按鍵消息事件分發(PS:本篇文章中源碼均是android 6.0,請知曉)先看下Agenda:

ViewRootImpl中的dispatchInputEvent方法 View.dispatchKeyEvent方法 ViewGroup.dispatchKeyEvent方法 Activity.dispatchKeyEvent方法 按鍵消息事件時序圖

ViewRootImpl中的dispatchInputEvent方法

WMS中接受到消息後,會調用ViewRootImpl中的dispatchInputEvent方法,
如下:
ViewRootImpl.java -> dispatchInputEvent()

這裡寫圖片描述

下面看ViewRootHandler的handleMessage方法:
ViewRootImpl$ViewRootHandler.java -> handleMessage()

這裡寫圖片描述

以上獲取msg中的event,及receiver後,接著調用enqueueInputEvent方法
ViewRootImpl.java -> enqueueInputEvent()<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxpbWcgYWx0PQ=="這裡寫圖片描述" src="/uploadfile/Collfiles/20160829/201608290930451281.png" title="\" />

以上方法,由於默認是false,會執行2:
ViewRootImpl.java -> scheduleProcessInputEvents()

這裡寫圖片描述

以上方法,再給Handler發一條MSG_PROCESS_INPUT_EVENTS(處理的消息)
ViewRootImpl$ViewRootHandler.java -> handleMessage()

這裡寫圖片描述

ViewRootImpl.java -> doProcessInputEvents()

這裡寫圖片描述

上面有個循環操作,就是把QueuedInputEvent傳遞到deliverInputEvent方法中,主要的作用,就是把上面來的按鍵消息放到隊列中去。
ViewRootImpl.java -> deliverInputEvent()

這裡寫圖片描述
這裡寫圖片描述

ViewRootImpl提供一個setView方法,是一個public的,會把mView(也就是DecorView),WMS調用這個方法,注意ViewRootImpl並不是一個View,它實際上是一個Handler,它的作用如下:

向DecorView分發收到的用戶發起的event事件,如按鍵,觸屏,軌跡球等事件;(這個是在內部類中實現,下面會說)

與WindowManagerService交互,完成整個Activity的GUI的繪制。

看下setView方法

這裡寫圖片描述

上面有兩個內部類,ViewPostImeInputStage,
ViewRootImpl.java$ViewPostImeInputStage

這裡寫圖片描述

在看processKeyEvent之前,先看onProcess方法:
ViewRootImpl$ViewPostImeInputStage.java -> processKeyEvent

這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

ViewRootImpl.java -> handleDispatchWindowAnimationStopped()

這裡寫圖片描述

上面有些代碼比較長,了解下就行,主要是明白processKeyEvent方法:
KeyEvent是InputEvent的子類,而InputEvent是一個事件的基類。
處理接收的事件及分發事件的過程,那麼問題來了?view或者viewGroup是如何收到按鍵消息派發下來的呢?ViewRootImpl內部類ViewPostImeInputStage中的processKeyEvent()方法中有這麼一段
if (mView.dispatchKeyEvent(event)) {//mView是DecorView(書名),但本質上也是View(乳名)
return FINISH_HANDLED;
}
另外鍵盤消息派發到view或ViewGroup中,在ViewRootImpl另一個內部類ViewPreImeInputStage中的processKeyEvent()方法中也有這麼一段如下:

這裡寫圖片描述

View.dispatchKeyEvent方法

可以看到從這開始就把按鍵消息派發到了view中去,然後看view中的dispatchKeyEvent():

這裡寫圖片描述

KeyEvent.java -> dispatch()

這裡寫圖片描述
這裡寫圖片描述

ViewGroup.dispatchKeyEvent方法

再來看下ViewGroup中的dispatchKeyEvent()

這裡寫圖片描述

上面代碼總結為:ViewGroup是重寫了View的dispatchKeyEvent,如果有子view時,分發按鍵消息到子view中去。沒有,直接由父view分發。

Activity.dispatchKeyEvent方法

到這就完了麼?沒有,Activity中dispatchKeyEvent,這不是個重寫方法:

這裡寫圖片描述

以上代碼總結為:先讓actionbar優先處理keyEvent,然後通過window處理,處理不了,到window上的DecorView處理。window和decorview的關系,相當於一個是窗戶,一個是粘在窗戶上的紙。所以,decorview可理解為窗戶上的紙。Activity的dispatchKeyEvent,是用於處理KeyEvent相關,子類可以重寫攔截所以的key event消息在分發到window這一層去的時候,所以我們最好做一些正常的處理流程。
主要過程如下:
1、調用onUserInteraction(),可重載該函數在消息派發前做一些處理
2、回調Activity包含的Window對象的superDispatchKeyEvent,該函數繼而調用mDecor.superDispatchKveyEent,該函數繼而又調用super.dispatchKeyEvent,DecorView的父類是FrameLayout,而FrameLayout未重載dispatchKeyEvent,因此最終調用ViewGroup的dispatchKeyEvent
3、如果DecorView未消耗消息,則調用event的dispatch()函數,這裡的第一個參數receiver是Activity對象

寫到這,有一個疑問?就是一個消息怎麼從window派發到viewRoot中去呢?或者說ViewRoot中的按鍵消息是從哪來的?
ViewRoot中有一個內部類: W,W是一個Binder子類(static class W extends IWindow.Stub ),用於接收global window manager的各種消息, 如按鍵消息, 觸摸消息等。 ViewRoot有一個W類型的成員mWindow,ViewRoot在構造中創建一個W的instance並賦值給mWindow(mWindow = new W(this);)。 ViewRoot是Handler的子類, W會通過Looper把消息傳遞給ViewRoot。

按鍵消息事件時序圖

一張圖,總結上面的流程:

這裡寫圖片描述

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