国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

ViewRootImpl解析

2019-11-09 19:07:08
字體:
來源:轉載
供稿:網友

        ViewRootImpl是一個及其重要的類,主要作用如下:

(1)將DecorView傳遞給WindowManagerSerive。

(2)完成View的繪制過程,包括measure、layout、draw過程。

(3)向DecorView分發收到的用戶發起的event事件,如按鍵,觸屏等事件。

        此外,ViewRootImpl中還包含了兩個需要重點關注的內部類:

(1)final class ViewRootHandler extends Handler

用于向DecorView分發事件

(2)static class W extends IWindow.Stub

W是ViewRootImpl的一個嵌入類,也是一個Binder服務。通過mWindowsession.addToDisplay函數傳入WMS,用來在WMS中通過Binder回調。

1、將DecorView傳遞給WMS

在ViewRootImpl.java中,開始的注釋如下:
/**  * The top of a view hierarchy, implementing the needed PRotocol between View  * and the WindowManager.  This is for the most part an internal implementation  * detail of {@link WindowManagerGlobal}.  *  * {@hide}  */          通過這一段注釋,我們知道,ViewRootImpl他是View樹的樹根,但它卻又不是View。ViewRootImpl的創建在ActivityThread中,調用棧如下:   ActivityThread#handleResumeActivity()->WindowManagerImpl#addView()->WindowManagerGlobal#addView()->ViewRootImpl(view.getContext(),Display)。      1.1 構造函數選取ViewRootImpl構造函數的一部分源碼如下:
mWindowSession = WindowManagerGlobal.getWindowSession();  mWindow = new W(this);  mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this);        第一句mWindowSession賦值為WindowManagerGlobal.getWindowSession(),其返回值為一個Session對象,Session的實例化在WMS進程中進行的,ViewRootImpl中有一個Session的代理對象,所以可以通過Session主要調用WMS中一些方法。        第二、三句中的W繼承于IWindow.Stub,后者繼承于Binder又實現了IWindow接口,因此這個W是可以ipC的。第三句中將mWindow賦值給了View.AttachInfo中的mWindow對象,將mWindowSession賦值給了mSession變量。1.2 ViewRootImpl#setView
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {      synchronized (this) {          if (mView == null) {              mView = view;              //略              requestLayout();              //略              try {                  mOrigWindowType = mWindowAttributes.type;                  mAttachInfo.mRecomputeGlobalAttributes = true;                  collectViewAttributes();                  res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,                          getHostVisibility(), mDisplay.getDisplayId(),                          mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,                          mAttachInfo.mOutsets, mInputChannel);              }               //略          }      }  }          首先,在setView內部會通過requestLayout來完成異步刷新請求,requestLayout最終會調用performTraversals方法來完成View的繪制。        接著,會通過WindowSession最終來完成Window的添加過程。上面的代碼中,mWindowSession類型是IWindowSession,它是一個Binder對象,真正的實現類是Session,也就是說這其實是一次IPC過程,遠程調用了Session中的addToDisPlay方法。        由此可知,接下去Window的添加請求就交給WindowManagerService去處理了。addView大概一個過程如下:WindowManager——>WindowManagerGobal——>ViewRootImpl——>Session——>WindowManagerService

2、完成View的繪制過程

         整個View樹的繪圖流程是在ViewRootImpl類的performTraversals()方法中進行的,該函數做的執行過程主要是根據之前設置的狀態,判斷是否重新計算視圖大小(measure)、是否重新放置視圖的位置(layout)、以及是否重繪 (draw),其核心也就是通過判斷來選擇順序執行這三個方法中的哪個,如下:
private void performTraversals() {          ......          //最外層的根視圖的widthMeasureSpec和heightMeasureSpec由來          //lp.width和lp.height在創建ViewGroup實例時等于MATCH_PARENT          int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);          int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);          ......          mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);          ......          mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());          ......          mView.draw(canvas);          ......      }         performTraversals方法會經過measure、layout和draw三個過程才能將一個View繪制出來,所以View的繪制是ViewRootImpl完成的。       另外當手動調用invalidate,postInvalidate,requestInvalidate也會最終調用performTraversals,來重新繪制View。其中requestLayout()方法會調用measure過程和layout過程,不會調用draw過程,也不會重新繪制任何View包括該調用者本身。

3、向DecorView分發事件

        這里的事件不僅僅包括MotionEvent,還有KeyEvent。我們知道View的時間分發順序為Activity——>Window——>View,那么Activity的事件來源在哪里呢?這是個需要思考的問題,答案和ViewRootImpl有很大的關系。        首先,事件的根本來源來自于硬件,經過native層,然后會經過InputEventReceiver接受事件,然后交給ViewRootImpl,將事件傳遞給DecorView,DecorView再交給PhoneWindow,PhoneWindow再交給Activity。這樣看來,整個體系的事件分發順序為:3.1 ViewRootImpl#dispatchInputEvent
public void dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {      SomeArgs args = SomeArgs.obtain();      args.arg1 = event;      args.arg2 = receiver;      Message msg = mHandler.obtainMessage(MSG_DISPATCH_INPUT_EVENT, args);      msg.setAsynchronous(true);      mHandler.sendMessage(msg);  }         InputEvent輸入事件,它有2個子類:KeyEvent和MotionEvent,其中KeyEvent表示鍵盤事件,而MotionEvent表示點擊事件,這里InputEventReceiver譯為輸入事件接收者,顧名思義,就是用于接收輸入事件,然后交給ViewRootImpl的dispatchInputEvent方法去分發處理。可以看到mHandler將邏輯切換到UI線程,代碼如下。
final ViewRootHandler mHandler = new ViewRootHandler();  final class ViewRootHandler extends Handler {           @Override          public void handleMessage(Message msg) {              switch (msg.what) {                       ........                        {                  SomeArgs args = (SomeArgs)msg.obj;                InputEvent event = (InputEvent)args.arg1;                  InputEventReceiver receiver = (InputEventReceiver)args.arg2;                  enqueueInputEvent(event, receiver, 0, true);                  args.recycle();                } break;          .................     }  (未完待續)
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 浦江县| 垦利县| 和顺县| 东方市| 秀山| 九江县| 武冈市| 宾川县| 于田县| 潍坊市| 涞源县| 大安市| 银川市| 自治县| 同心县| 石首市| 碌曲县| 大埔区| 淅川县| 双辽市| 麻江县| 晋州市| 梅河口市| 得荣县| 永仁县| 彭州市| 醴陵市| 那坡县| 阳山县| 宁津县| 潍坊市| 四平市| 陆良县| 咸宁市| 民乐县| 忻城县| 海淀区| 清涧县| 洛浦县| 祁门县| 长子县|