標籤:android開發 frameworks 源碼
對於android的觸摸事件,一直以來都有點模糊,所以決定搞搞清楚.這裡一共分三部分來解決這個問題:第一部分:觸摸事件是如何起源的.第二部分:view是如何處理觸摸事件的.第三部分:viewgroup是如何分發和處理觸摸事件的.
這一次先看第一部分:觸摸事件是如何起源的.
要理解這個問題,首先應該知道下面三點:
- 每一個需要顯示到手機上的視圖最總都是通過WindowManager.addview()的方式來實現的,比如我們常用的activity/popwindow/狀態列/鎖屏/來鬧鐘介面等!
- 在WindowManager.addview()過程中實際上是調用WindowManagerGlobal.addView(),在這個方法裡面是通過建立一個ViewRootImpl的對象,最後將需要顯示的視圖view加入到這個ViewRootImpl.也就是說顯示的視圖起源於ViewRootImpl.
- 一個activity的視圖起源於一個DecorView:DecorView其實是一個FrameLayout,我們在activity中通過setContentView()添加的顯示view最終都是會加入這個DecorView裡面的.
下面來看看觸摸事件流程,看看觸摸事件是如何流入視圖的view的:
(1)每一個顯示的視窗都是需要通過WindowManager.addview()來添加進去的,這個過程中會為這個顯示的view建立一個該view與系統互動的ViewRootImpl.這裡的觸摸事件就是開始從ViewRootImpl來的.
(2)ViewRootImpl中定義了一個WindowInputEventReceiver來接收觸摸事件.然後把觸摸事件傳遞給mView.在activity中mView就是DecorView
(3)通過ViewRootImpl最後調用了view的dispatchPointerEvent(MotionEvent event).這樣觸摸事件就傳遞給了顯示的view了
我們知道,對於activity來說,ViewRootImpl首先時把觸摸事件傳遞給了DecorView的dispatchPointerEvent().下面來看看DecorView的dispatchPointerEvent源碼:
public boolean dispatchTouchEvent(MotionEvent ev) {
final Callback cb = getCallback();
return cb != null && !isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev)//會首先調用Callback的dispatchTouchEvent方法.
: super.dispatchTouchEvent(ev);
}
這裡要知道這個Callback對象那裡來的.來看看getCallback()的源碼,在Window裡面定義如下:
public final Callback getCallback() {
return mCallback;//看到了吧,其實很簡單,直接返回mCallback即可.
}
那麼mCallback是在何時賦值的呢?我們知道,建立一個activity就會為這個activity建立他的window,在activity中你會發現:原來activity已經implements了這個Callback
通過activity的代碼你會發現其實在建立window的時候就給這個window的mCallback賦值了:
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);//這裡的this就是當前的activity
所以最終DecorView調用 dispatchTouchEvent會調用到activity的dispatchTouchEvent()方法.
(4)來看看activity的dispatchTouchEvent做來些什麼:
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {//會調用Window的superDispatchTouchEvent方法,如果返回true,則結束,否則調用這個activity的onTouchEvent方法
return true;
}
return onTouchEvent(ev);
}
(5)所以來看看 Window的superDispatchTouchEvent方法.Window是一個虛類,其實作類別是PhoneWindow
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);//實際上是調用DecorView的superDispatchTouchEvent方法
}
(6)來看看DecorView的superDispatchTouchEvent的
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);//看到了吧,最終還是調用了DecorView的dispatchTouchEvent方法
}
(7)綜上所述:觸摸事件從 ViewRootImpl開傳遞出來,最終會調用顯示視圖view的最父(最後面的/最老的)view的dispatchTouchEvent.如果返回false,就會調用activity的onTouchEvent()方法.
從上面的分析可以看出,觸摸事件都是從dispatchTouchEvent開始的,所以要理解觸摸事件的流程其實就要從view的dispatchTouchEvent開始.
android觸摸事件流程(一)