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

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

ViewRootImpl解析

2019-11-09 18:38:02
字體:
供稿:網(wǎng)友

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

(1)將DecorView傳遞給WindowManagerSerive。

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

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

        此外,ViewRootImpl中還包含了兩個需要重點關(guān)注的內(nèi)部類:

(1)final class ViewRootHandler extends Handler

用于向DecorView分發(fā)事件

(2)static class W extends IWindow.Stub

W是ViewRootImpl的一個嵌入類,也是一個Binder服務(wù)。通過mWindowsession.addToDisplay函數(shù)傳入WMS,用來在WMS中通過Binder回調(diào)。

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的創(chuàng)建在ActivityThread中,調(diào)用棧如下:   ActivityThread#handleResumeActivity()->WindowManagerImpl#addView()->WindowManagerGlobal#addView()->ViewRootImpl(view.getContext(),Display)。      1.1 構(gòu)造函數(shù)選取ViewRootImpl構(gòu)造函數(shù)的一部分源碼如下:
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主要調(diào)用WMS中一些方法。        第二、三句中的W繼承于IWindow.Stub,后者繼承于Binder又實現(xiàn)了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內(nèi)部會通過requestLayout來完成異步刷新請求,requestLayout最終會調(diào)用performTraversals方法來完成View的繪制。        接著,會通過WindowSession最終來完成Window的添加過程。上面的代碼中,mWindowSession類型是IWindowSession,它是一個Binder對象,真正的實現(xiàn)類是Session,也就是說這其實是一次IPC過程,遠(yuǎn)程調(diào)用了Session中的addToDisPlay方法。        由此可知,接下去Window的添加請求就交給WindowManagerService去處理了。addView大概一個過程如下:WindowManager——>WindowManagerGobal——>ViewRootImpl——>Session——>WindowManagerService

2、完成View的繪制過程

         整個View樹的繪圖流程是在ViewRootImpl類的performTraversals()方法中進行的,該函數(shù)做的執(zhí)行過程主要是根據(jù)之前設(shè)置的狀態(tài),判斷是否重新計算視圖大小(measure)、是否重新放置視圖的位置(layout)、以及是否重繪 (draw),其核心也就是通過判斷來選擇順序執(zhí)行這三個方法中的哪個,如下:
private void performTraversals() {          ......          //最外層的根視圖的widthMeasureSpec和heightMeasureSpec由來          //lp.width和lp.height在創(chuàng)建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方法會經(jīng)過measure、layout和draw三個過程才能將一個View繪制出來,所以View的繪制是ViewRootImpl完成的。       另外當(dāng)手動調(diào)用invalidate,postInvalidate,requestInvalidate也會最終調(diào)用performTraversals,來重新繪制View。其中requestLayout()方法會調(diào)用measure過程和layout過程,不會調(diào)用draw過程,也不會重新繪制任何View包括該調(diào)用者本身。

3、向DecorView分發(fā)事件

        這里的事件不僅僅包括MotionEvent,還有KeyEvent。我們知道View的時間分發(fā)順序為Activity——>Window——>View,那么Activity的事件來源在哪里呢?這是個需要思考的問題,答案和ViewRootImpl有很大的關(guān)系。        首先,事件的根本來源來自于硬件,經(jīng)過native層,然后會經(jīng)過InputEventReceiver接受事件,然后交給ViewRootImpl,將事件傳遞給DecorView,DecorView再交給PhoneWindow,PhoneWindow再交給Activity。這樣看來,整個體系的事件分發(fā)順序為: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方法去分發(fā)處理。可以看到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;          .................     }  (未完待續(xù))
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 广州市| 保山市| 寿阳县| 徐汇区| 大名县| 铁力市| 剑阁县| 东乌| 望江县| 黄浦区| 宁夏| 邹平县| 黎城县| 江油市| 洞口县| 诏安县| 互助| 陈巴尔虎旗| 靖江市| 龙陵县| 大石桥市| 泸西县| 宁夏| 浦北县| 勐海县| 兴山县| 阜新市| 垣曲县| 简阳市| 长沙市| 六安市| 那曲县| 运城市| 永顺县| 尚志市| 阳谷县| 鄂尔多斯市| 阿坝县| 蓬溪县| 溆浦县| 时尚|