1、View的繼承關系圖
View的繼承關系圖如下:
其中最重要的子類為ViewGroup,View是所有UI元件的基類,而ViewGroup是容納這些元件的容器,同時它也是繼承于View類。而UI元件的繼承關系如上圖,比較常用的元件類用紅色字型标出。
2、事件
2.1 事件類型
當使用者觸摸螢幕,根據不同的動作會産生不同的按鍵事件,如OnClick, OnLongClick, OnTouchEvent等。每個View會重寫相應的回調方法,而具體的回調方法則是在View類中進行了定義,如OnLongClick見View的源碼如下:
public interface OnLongClickListener {
/**
* Called when a view has been clicked and held.
*
* @param v The view that was clicked and held.
*
* @return true if the callback consumed the long click,
* false otherwise.
*/
boolean onLongClick(View v);
}
而具體的事件類型主要有如下三類:
MotionEvent.ACTION_DOWN //按下View,是所有事件的開始
MotionEvent.ACTION_MOVE //滑動事件
MotionEvent.ACTION_UP //與down對應,表示擡起
2.2 事件響應機制
1>注冊一個監聽對象。
2>實作監聽對象的監聽事件,即事件分發時的回調方法。
3>當某一觸發事件到來,在觸發事件中通過注冊過的監聽對象,回調注冊對象的響應事件,來完成使用者自定義實作。
注:具體的實作過程見第三節。
3、View的事件分發
3.1 ViewRootImpl的建立過程分析
這裡介紹一個重要的類:ViewRootImpl類
簡單來說,ViewRootImpl相當于是視窗系統中的MVC模型中的Controller,它的主要職責為:
1. 負責為應用程式視窗視圖建立Surface。
2. 配合WindowManagerService來管理系統的應用程式視窗。
3. 負責管理、布局和渲染應用程式視窗視圖的UI。
ViewRootImpl有兩個建立時機:
1>Activity元件在啟動的時候,系統會為它建立視窗對象(Window),同時,系統也會為這個視窗對象建立ViewRootImpl對象。
2>當Activity元件被激活的時候,系統如果發現與它的應用程式視窗視圖對象所關聯的ViewRoot對象還沒有建立,那麼就會先建立這個ViewRoot對象,以便接下來可以将它的UI渲染出來。
ViewRootImpl的建立時序圖如下:
此處不做詳細分析,由時序圖即可看出大概流程。
3.2 View事件處理對象ViewPostImeInputStage的注冊過程分析
此處先分析ViewRootImpl類的setView方法:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
...
res = mWindowSession.addToDisplay(mWindow, mSeq,
mWindowAttributes,getHostVisibility(),
mDisplay.getDisplayId(),
mAttachInfo.mContentInsets,
mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
...
// Set up the input pipeline.
CharSequence counterSuffix = attrs.getTitle();
mSyntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage =
new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage =
new NativePostImeInputStage(viewPostImeStage,
"aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage =
new EarlyPostImeInputStage(nativePostImeStage);
InputStage imeStage =
new ImeInputStage(earlyPostImeStage,
"aq:ime:" + counterSuffix);
InputStage viewPreImeStage =
new ViewPreImeInputStage(imeStage);
InputStage nativePreImeStage =
new NativePreImeInputStage(viewPreImeStage,
"aq:native-pre-ime:" + counterSuffix);
mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;
...
由以上代碼可知,setView方法中會建立輸入管道,此處采用責任鍊模式,即觸摸事件最終還是要分發給具體的View來處理的,是以最後對事件的處理會由此責任鍊來負責,而此責任鍊在此預先注冊了的InputStage主要有SyntheticInputStage、ViewPostImeInputStage、NativePostImeInputStage、EarlyPostImeInputStage、ImeInputStage、ViewPreImeInputStage、NativePreImeInputStage等。此處隻分析ViewPostImeInputStage,至于其他的自行分析。
本文假設讀者已經預先了解了android的輸入子系統,是以本文不解釋輸入子系統的工作原理。
在Input子系統的native層socket用戶端讀取輸入事件,最終調用InputEventReceiver類子類的onInputEvent()方法,ViewRootImpl的setView方法中初始化了WindowInputEventReceiver對象,它繼承自類InputEventReceiver。
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
其中mInputChannel與Input輸入子系統建立了聯系,是以最終會調用WindowInputEventReceiver的onInputEvent()方法。
3.3 View的事件分發流程分析
在3.2節中分析了處理ViewPostImeInputStage的注冊,以及ViewRootImpl中響應輸入事件的入口,本小節将繼續分析事件的分發流程:
此時序圖分析了View事件中的OnClick事件的分發過程,由圖可知,ViewRootImpl截取到事件後會分發給ViewPostImeInputStage處理,而ViewPostImeInputStage接着将事件分發給具體的View,此時根據View裡面注冊的監聽事件,調用其回調函數,最終響應我們自定義的操作。至此,View的事件分發分析結束。