日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

ViewRootImpl如何負責管理繪制視圖樹和刷新界面

來源: 責編: 時間:2024-05-22 17:14:37 154觀看
導讀ViewRootImpl位于視圖層次結構的頂部,負責View和WindowManager之間的通信。視圖繪制:負責調用View樹的繪制流程,包括測量(measure)、布局(layout)和繪制(draw)等操作。監聽View樹的改變,并根據需要觸發相應的繪制操作,確保界面的

ViewRootImpl位于視圖層次結構的頂部,負責View和WindowManager之間的通信。89o28資訊網——每日最新資訊28at.com

  1. 視圖繪制:負責調用View樹的繪制流程,包括測量(measure)、布局(layout)和繪制(draw)等操作。監聽View樹的改變,并根據需要觸發相應的繪制操作,確保界面的及時更新。
  2. 事件分發:負責將輸入的各種事件(如觸摸事件、按鍵事件等)分發給正確的View處理。根據觸摸事件的位置信息,逐層遍歷View樹,找到最合適的View來處理事件。將處理結果返回給系統,以便進行后續的處理,如滾動、點擊等。
  3. 窗口管理:承擔Android窗口管理的一部分職責。負責創建和管理窗口,將窗口與ViewRootImpl進行綁定。當窗口需要顯示或隱藏時,ViewRootImpl會相應地調整界面的顯示狀態。

ViewRootImpl關聯了多個類和接口,IWindowSession、Choreographer及其FrameCallback接口等。IWindowSession用于客戶端和WindowManagerService之間進行窗口管理操作的接口,允許ViewRootImpl與WindowManagerService進行通信,執行如添加、刪除、更新窗口等操作。89o28資訊網——每日最新資訊28at.com

scheduleTraversals

scheduleTraversals()方法負責將一次視圖遍歷(traversal)排期到其調度計劃中,但并不會立即執行遍歷操作。方法被許多操作所調用,比如當視圖的大小、位置等屬性發生變化時,或者當調用requestLayout()、invalidate()等方法時,都會觸發scheduleTraversals()。作用是將視圖的測量、布局和繪制操作(即遍歷操作)放入待執行隊列中,并注冊一個底層的刷新信號監聽器。89o28資訊網——每日最新資訊28at.com

public void invalidate(boolean invalidateCache) {    invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true);}void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate) {    ...    // Propagate the damage rectangle to the parent view.    final AttachInfo ai = mAttachInfo;    final ViewParent p = mParent;    if (p != null && ai != null && l < r && t < b) {        final Rect damage = ai.mTmpInvalRect;        damage.set(l, t, r, b);        //調用父容器的方法,向上傳遞事件        p.invalidateChild(this, damage);    }    ...}public final void invalidateChild(View child, final Rect dirty) {    .....    ViewParent parent = this;        do {            View view = null;            if (parent instanceof View) {                view = (View) parent;            }            if (drawAnimation) {                if (view != null) {                    view.mPrivateFlags |= PFLAG_DRAW_ANIMATION;                } else if (parent instanceof ViewRootImpl) {                    ((ViewRootImpl) parent).mIsAnimating = true;                }            }            // If the parent is dirty opaque or not dirty, mark it dirty with the opaque            // flag coming from the child that initiated the invalidate            if (view != null) {                if ((view.mViewFlags & FADING_EDGE_MASK) != 0 && view.getSolidColor() == 0) {                    opaqueFlag = PFLAG_DIRTY;                }                if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) {                    view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | opaqueFlag;                }            }            //調用ViewGrup的invalidateChildInParent,如果已經達到最頂層view,則調用ViewRootImpl的invalidateChildInParent。            parent = parent.invalidateChildInParent(location, dirty);            if (view != null) {                // Account for transform on current parent                Matrix m = view.getMatrix();                if (!m.isIdentity()) {                    RectF boundingRect = attachInfo.mTmpTransformRect;                    boundingRect.set(dirty);                    m.mapRect(boundingRect);                    dirty.set((int) Math.floor(boundingRect.left),                              (int) Math.floor(boundingRect.top),                              (int) Math.ceil(boundingRect.right),                              (int) Math.ceil(boundingRect.bottom));                }            }        } while (parent != null);    }}

當VSYNC信號到來時(VSYNC信號是Android系統中用于同步屏幕刷新的信號),系統會從待執行隊列中取出對應的scheduleTraversals()操作,并將其加入到主線程的消息隊列中。然后,主線程會從消息隊列中取出并執行這個操作,進而觸發視圖的測量、布局和繪制流程。89o28資訊網——每日最新資訊28at.com

private void scheduleFrameLocked(long now) {    if (!mFrameScheduled) {        mFrameScheduled = true;        if (USE_VSYNC) {            //這里判斷,當前執行的線程是否是創建該Choreographer的線程,如果是直接執行。否則通過handler 發送到 創建該Choreographer的線程去執行。            if (isRunningOnLooperThreadLocked()) {                scheduleVsyncLocked();            } else {                //這條message 最后處理還是調用到了scheduleVsyncLocked方法                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);                msg.setAsynchronous(true);                mHandler.sendMessageAtFrontOfQueue(msg);            }        } else {            final long nextFrameTime = Math.max(                    mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);            if (DEBUG_FRAMES) {                Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");            }            Message msg = mHandler.obtainMessage(MSG_DO_FRAME);            msg.setAsynchronous(true);            mHandler.sendMessageAtTime(msg, nextFrameTime);        }    }}private void scheduleVsyncLocked() {    mDisplayEventReceiver.scheduleVsync();}public void scheduleVsync() {    if (mReceiverPtr == 0) {        Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event " + "receiver has already been disposed.");    } else {        nativeScheduleVsync(mReceiverPtr);    }}

在這個過程中,performTraversals()方法會被調用。方法會執行實際的測量、布局和繪制操作。首先會調用measureHierarchy()方法進行測量,然后調用performLayout()方法進行布局,最后調用draw()方法進行繪制。這些操作會按照順序執行,以確保視圖能夠正確地顯示在屏幕上。最終通過nativeScheduleVsync()原生方法通知屏幕進行繪制。89o28資訊網——每日最新資訊28at.com

performTraversals

performTraversals()方法負責啟動視圖的測量(measure)、布局(layout)和繪制(draw)流程。當需要創建視圖、視圖參數改變或界面需要刷新時,可能會從根視圖DecorView開始重新進行測量、布局和繪制,這時就會調用到performTraversals()方法。89o28資訊網——每日最新資訊28at.com

private void performTraversals() {    ...    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);    ...    performLayout(lp, desiredWindowWidth, desiredWindowHeight);    ...     performDraw();}void doTraversal() {      //防止重入    if (mTraversalScheduled) {        mTraversalScheduled = false;        //移除同步屏障        mHandler.getLooper().getQueue()                    .removeSyncBarrier(mTraversalBarrier);        performTraversals();    }}

圖片圖片89o28資訊網——每日最新資訊28at.com

  1. 「測量(Measure)」:在這個階段,系統會遍歷整個視圖樹,計算每個視圖的大小。這個過程中會用到MeasureSpec,每個MeasureSpec都包含了一個測量模式和測量大小,測量模式主要有三種:EXACTLY(父視圖已經確定了子視圖的確切大小)、AT_MOST(子視圖的大小有一個最大值限制)和UNSPECIFIED(父視圖對子視圖的大小沒有要求)。
  2. 「布局(Layout)」:在測量完成后,系統會為每個視圖確定其在屏幕上的精確位置。這個過程中,父視圖會根據測量階段得到的子視圖大小以及自身的布局參數,計算出子視圖應該放置的位置。
  3. 「繪制(Draw)」:系統會遍歷整個視圖樹,根據每個視圖的繪制參數(如顏色、形狀等)將其繪制到屏幕上。這個過程中,視圖會按照其在視圖樹中的層次順序進行繪制,先繪制父視圖,再繪制子視圖。
final TraversalRunnable mTraversalRunnable = new TraversalRunnable();void scheduleTraversals() {    if (!mTraversalScheduled) {        //移除同步屏障        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();        mChoreographer.postCallback(                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);               }}void unscheduleTraversals() {    mChoreographer.removeCallbacks(                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);    }}public void postCallback(int callbackType, Runnable action, Object token) {    postCallbackDelayed(callbackType, action, token, 0);}public void postCallbackDelayed(int callbackType,    Runnable action, Object token, long delayMillis) {    ...    postCallbackDelayedInternal(callbackType, action, token, delayMillis);}private void postCallbackDelayedInternal(int callbackType,    Object action, Object token, long delayMillis) {    ....    synchronized (mLock) {        final long now = SystemClock.uptimeMillis();        final long dueTime = now + delayMillis;        //把 任務添加到了mCallbackQueues 回調里面去,等待回調執行。        mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);                    //now=0 ,走進scheduleFrameLocked()方法內        if (dueTime <= now) {            scheduleFrameLocked(now);        } else {            Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);            msg.arg1 = callbackType;            msg.setAsynchronous(true);            mHandler.sendMessageAtTime(msg, dueTime);        }    }}//Choreographer內部類DisplayEventReceiver,重寫了onVsync方法@Overridepublic void onVsync(long timestampNanos, int builtInDisplayId, int frame) {    mTimestampNanos = timestampNanos;    mFrame = frame;    Message msg = Message.obtain(mHandler, this);    // 設置成異步消息    msg.setAsynchronous(true);    mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);}public void run() {    mHavePendingVsync = false;    doFrame(mTimestampNanos, mFrame);}// Choreographervoid doFrame(long frameTimeNanos, int frame) {    ...    doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);}void doCallbacks(int callbackType, long frameTimeNanos) {    CallbackRecord callbacks;    // 從mCallbackQueues取出    callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now / TimeUtils.NANOS_PER_MS);    for (CallbackRecord c = callbacks; c != null; c = c.next) {         c.run(frameTimeNanos);    }}// CallbackRecordpublic void run(long frameTimeNanos) {    if (token == FRAME_CALLBACK_TOKEN) {        ((FrameCallback)action).doFrame(frameTimeNanos);    } else {        // 這里也即是調用了TraservalRunnable的run方法,也即是三個繪制流程        ((Runnable)action).run();    }}

mHandler是當前主線程的handler,當接收到onVsync信號的時候,將自己封裝到Message中,等到Looper處理,最后Looper處理消息的時候就會調用run方法最終從mCallbackQueues取回之前添加的任務再執行run方法,也就是TraservalRunnable的run方法。最終觸發performTraversals方法進行界面刷新。89o28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-90041-0.htmlViewRootImpl如何負責管理繪制視圖樹和刷新界面

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: Vue3 實現最近很火的酷炫功能:卡片懸浮發光

下一篇: 我們忘記了前端基礎知識

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 恩施市| 武功县| 安龙县| 赣榆县| 高州市| 土默特左旗| 库伦旗| 玉龙| 丹棱县| 肥东县| 万荣县| 东乡| 始兴县| 鞍山市| 阿克陶县| 江北区| 大埔区| 黄石市| 成武县| 开封市| 阜阳市| 太湖县| 辽阳县| 进贤县| 昌乐县| 青浦区| 防城港市| 洪江市| 汉阴县| 惠水县| 山丹县| 湘潭县| 青河县| 濮阳县| 盐山县| 瑞丽市| 镇宁| 舞阳县| 昌平区| 绵阳市| 巫溪县|