Android R窗口Window的requestlayout过程大揭秘

Android R窗口Window的requestlayout过程大揭秘

Android应用程序窗口设计系列博客:

Android应用程序窗口设计之Window及WindowManager的创建
Android应用程序窗口设计之setContentView布局加载的实现
普法Android的Token前世今生以及在APP,AMS,WMS之间传递
Android应用程序窗口设计之窗口的添加
Android应用程序窗口设计之建立与WMS服务之间的通信过程
Android窗口设计之Dialog、PopupWindow、系统窗口的实现
Android应用程序建立与AMS服务之间的通信过程

引言

该系列博客尘封很久很久了,是时候该再续前缘,重新上路了!我挑着担啊,你牵着马!好了言归正传,好记得前面的博客Android应用程序窗口设计之窗口的添加,我们重点分析了应用端通过一顿猛如虎一样的操作之后请求到了WMS的addWindow方法,然后在WMS方法中为应用端窗口在WMS端建立的对应的关系,最终建立了下面的的对应关系图:

Android R窗口Window的requestlayout过程大揭秘

在前面的博客的Android应用程序窗口设计之窗口的添加的2.6章节,我们对requestLayout()只是简单的描述了下它(这里调用异步刷新请求,最终会调用performTraversals方法来完成View的绘制在向WMS添加窗口前进行UI布局)。过了这么久了,是时候把它捡起来好好分析分析了!朋友们药不能停啊!好了开干!

时间如梭,写该系列博客还是在很久之前,并且使用的还是Android 7.1源码,这里为了跟上时代的进步,所以做出一个重大决定,该系列后续博客分析都将会在Android 11(R)上的基础分析!

注意:本篇的介绍是基于Android 11.xx平台为基础的,其中涉及的代码路径如下:

frameworks/base/core/java/android/view/
    --- WindowManager.java
    --- View.java
    --- ViewManager.java
    --- ViewRootImpl.java
    --- Window.java
    --- Display.java
    --- WindowManagerImpl.java
    --- WindowManager.java
    --- WindowManagerGlobal.java
    --- IWindowManager.aidl
    --- IWindow.aidl
    --- IWindowSession.aidl
    --- Surface.java
    --- SurfaceControl.java

frameworks/base/services/core/java/com/android/server/wm/
    --- WindowManagerService.java
    --- AppWindowToken.java
    --- WindowState.java
    --- Session.java
    --- WindowToken.java
    --- WindowStateAnimator.java

一.回到梦开始的地方ViewRootImpl.requestlayout()

还记得以前Android面试经常会问的Android自定义控件 requestLayout / invalidate的区别吗?如果用一句话来概括就是requestLayout 是用来设置 FORCE_LAYOUT 标志,invalidate 用来设置 dirty 标志。所以 requestLayout 会触发 measure 和 layout,invalidate 只会触发 draw。而自定义空间的requestLayout方法最终会触发ViewRootImpl.requestlayout()方法,这里我们来好好盘盘它!

好了,不多说!直接上源码,开撸才够味!


public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
        ...

    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {

            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }

    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;

            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
            ...

            performTraversals();
            ...

        }
    }

    final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
        final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }
    @UnsupportedAppUsage
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;

            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();

            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }

1.关于Handler同步屏障,我们这里只需要知道设置了同步屏障之后,Handler只会处理异步消息。再换句话说,同步屏障为Handler消息机制增加了一种简单的优先级机制,异步消息的优先级要高于同步消息。我们在调用requestLayout()方法之后,并不会马上开始进行绘制任务,而是会给主线程设置一个同步屏幕,并设置Vsync信号监听。当Vsync信号的到来,会发送一个异步消息到主线程Handler,执行我们上一步设置的绘制监听任务,并移除同步屏障。并且我们通常使用Handler发送的都是同步消息。

2.关于Choreographer编舞者,这里也不重点介绍,我们这里只需要知道它是一种Android的机制,是Android系统为了通知应用端可以进行绘制的一种机制。关于它,如果后面有机会,我们可以重点熟悉熟悉了解它!

1.1…ViewRootImpl.performTraversals()拉开应用绘制三部曲的章程

虽然这里我提到了了应用绘制三部曲,但是很遗憾我们今天的重点也不是它,我们今天的重点是ViewRootImpl,如何向WMS服务请求relayoutWindow布局,主要是填充Surface,构建对应的Window的BufferLayer。好了,不多说了,我们直接看代码!


public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
        ...

    private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
            boolean insetsPending) throws RemoteException {
            ...

        int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
                (int) (mView.getMeasuredWidth() * appScale + 0.5f),
                (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
                insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
                mTmpFrame, mTmpRect, mTmpRect, mTmpRect, mPendingBackDropFrame,
                mPendingDisplayCutout, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
                mTempControls, mSurfaceSize, mBlastSurfaceControl);
            ...

    }

        private void performTraversals() {
            ...

            relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
            ...

           performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
           ...

           performLayout(lp, mWidth, mHeight);
           ...

           performDraw();

           ...

        }
        ...

}

performTraversals的四大步骤,每一步都很重要,如果要详细捯饬清楚真的是没有个三天三夜是真的搞不清楚,但是这里我们仅仅只重点关心relayoutWindow()向WMS发起布局请求。而这里的通信的关键Session的类关系如下,而我们这里的mWindowSession是Session的代理端,所以它最终会调用到Session的服务端Session。

Android R窗口Window的requestlayout过程大揭秘

二.WMS开启处理应用端发起的布局请求

Android不愧是是C/S架构的集大成者,应用端的相关操作基本兜兜转转最后都会到达服务端,这里也不例外。这个章节我们来开始分析WMS怎么处理应用端发起的布局请求。


    @Override
    public int relayout(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewFlags, int flags, long frameNumber,
            Rect outFrame, Rect outContentInsets, Rect outVisibleInsets,
            Rect outStableInsets, Rect outBackdropFrame,
            DisplayCutout.ParcelableWrapper cutout, MergedConfiguration mergedConfiguration,
            SurfaceControl outSurfaceControl, InsetsState outInsetsState,
            InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
            SurfaceControl outBLASTSurfaceControl) {
        ...

        int res = mService.relayoutWindow(this, window, seq, attrs,
                requestedWidth, requestedHeight, viewFlags, flags, frameNumber,
                outFrame, outContentInsets, outVisibleInsets,
                outStableInsets, outBackdropFrame, cutout,
                mergedConfiguration, outSurfaceControl, outInsetsState, outActiveControls,
                outSurfaceSize, outBLASTSurfaceControl);
        ..

        return res;
    }

    public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewVisibility, int flags,
            long frameNumber, Rect outFrame, Rect outContentInsets,
            Rect outVisibleInsets, Rect outStableInsets, Rect outBackdropFrame,
            DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
            SurfaceControl outSurfaceControl, InsetsState outInsetsState,
            InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
            SurfaceControl outBLASTSurfaceControl) {
                ...

                if (shouldRelayout) {
                ...

                    result = createSurfaceControl(outSurfaceControl, outBLASTSurfaceControl,
                            result, win, winAnimator);
                ...

                }
                ...

            }

三.写在最后

到这里本篇博客Android R窗口Window的requestlayout过程大揭秘真的就宣告结束了,相信很多读者看到这篇博客,会有一个感觉是不是我的技术和写作水平退步了,咋感觉这篇博客写了,咋感觉又没有写。是的我也有这个感觉,因为我这篇博客是为了后续引出应用Surface创建而添加的一个博客,所以写得简单也是清理之中的,因为该篇博客是一个过渡主要是为了后续的博客不唐突而添加的。望各位见谅!欢迎读者继续关注!好了,青山不改绿水长流先到这里了。如果本博客对你有所帮助,麻烦关注或者点个赞,

Original: https://blog.csdn.net/tkwxty/article/details/127799832
Author: IT先森
Title: Android R窗口Window的requestlayout过程大揭秘

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/657956/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球