android12 ViewRootImpl分析

ViewRootImpl 是 Android 视图系统中一个极其核心的内部类,它不是一个普通的 View,而是连接窗口管理器(WindowManager)和 View 树的"枢纽" 。你可以把它理解为一个窗口的"总管家",负责驱动整个 View 树的测量、布局、绘制 ,以及接收和分发所有的输入事件

1. 入口与创建:从 WindowManager.addView 开始

每个需要显示在屏幕上的窗口(如 Activity、Dialog、Toast),最终都会通过 WindowManager.addView()DecorView(视图树的根)添加到系统中。

  • WindowManagerGlobal 会为这个窗口创建一个 ViewRootImpl 实例。

  • 随后调用其 setView() 方法,这一步至关重要:

    • 保存 View 根 :将传入的 DecorView 赋值给 ViewRootImplmView 成员变量,作为后续操作的对象。
    • 向系统添加窗口 :通过 IWindowSession 这个跨进程通信(AIDL)接口,向系统服务 WindowManagerService (WMS) 请求添加一个窗口。
    • 初始化输入通道 :建立一个 InputChannel,为后续接收来自系统 InputFlinger 的输入事件做准备。
scss 复制代码
//frameworks/base/core/java/android/view/WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow, int userId) {
    ...
    final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
    if (parentWindow != null) {
        //当前窗口为子窗口,需要让父窗口对当前窗口布局参数进行一些修改
        parentWindow.adjustLayoutParamsForSubWindow(wparams);
    } 
    ...

    ViewRootImpl root;
    View panelParentView = null;
    synchronized (mLock) {
        ...
        //同一个view不允许添加两次
        int index = findViewLocked(view, false);
        if (index >= 0) {
           ...
        }
        ...
        //创建ViewRootImpl
        root = new ViewRootImpl(view.getContext(), display);
        view.setLayoutParams(wparams);
        //保存到全局变量中
        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);

        try {
            //将View设置给ViewRootImpl,将触发真正的窗口添加过程
            root.setView(view, wparams, panelParentView, userId);
        } catch (RuntimeException e) {
            // BadTokenException or InvalidDisplayException, clean up.
            if (index >= 0) {
                removeViewLocked(index, true);
            }
            throw e;
        }
    }
}


//frameworks/base/core/java/android/view/ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
              int userId) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
                ...
                //注册监听,监听屏幕变化(如横竖屏、折叠屏状态)
                mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
                //保存视图布局方向
                mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
                //处理未捕获的按键事件
                mFallbackEventHandler.setView(view);
                 //复制 Window 属性
                 mWindowAttributes.copyFrom(attrs);
                  ...
   //强制设置`PRIVATE_FLAG_USE_BLAST`(BLAST是Android 10+引入的新Surface合成架构)
                 mWindowAttributes.privateFlags |=
                          WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
  
                 attrs = mWindowAttributes;
                 ...
                 if (view instanceof RootViewSurfaceTaker) {
                     //允许应用自己管理Surface,而不是由WindowManager绘制
                      ...
                 }
                 ...
                 if (mSurfaceHolder == null) {
                      //启用硬件加速
                      //只有非自绘Surface的窗口才会尝试开启硬件加速(GPU渲染)
                      enableHardwareAcceleration(attrs);
                      ...
                      
                 }
                 ...
                 //请求首次布局
                 requestLayout();
                  
               //创建InputChannel,用于接收输入事件(触摸/按键),此时还是空壳
                 InputChannel inputChannel = null;
                 if ((mWindowAttributes.inputFeatures
                          & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                      inputChannel = new InputChannel();
                  }
                  ...
  
                 try {
                      ...
                     // 通过 Binder请求WMS添加窗口,携带参数inputChannel
                     res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
                              getHostVisibility(), mDisplay.getDisplayId(), userId,
                              mInsetsController.getRequestedVisibility(), inputChannel, mTempInsets,
                              mTempControls);
                    ...
                      
                 } 
                 ...
                 //处理添加窗口返回结果
                 if (res < WindowManagerGlobal.ADD_OKAY) {
                  //表示添加失败,根据不同错误码抛出对应的运行时异常
                  //常见的失败原因:Activity已退出、Token无效、权限不足、窗口类型重复等
                 ...
                 //创建`WindowInputEventReceiver`,接收原始输入事件,
                 //启动应用内的分发流程
                  if (inputChannel != null) {
                      if (mInputQueueCallback != null) {
                          mInputQueue = new InputQueue();
                          mInputQueueCallback.onInputQueueCreated(mInputQueue);
                      }
                      mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
                              Looper.myLooper());
  
                      ...
                  }
                 //ViewRootImpl将作为view的Parent
                 view.assignParent(this);
                 ...
           
              }
         }
}

//添加窗口流程
//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
        int displayId, int requestUserId, InsetsState requestedVisibility,
        InputChannel outInputChannel, InsetsState outInsetsState,
        InsetsSourceControl[] outActiveControls) {
    //清空输出参数:防止返回脏数据
    Arrays.fill(outActiveControls, null);
    int[] appOp = new int[1];
    final boolean isRoundedCornerOverlay = (attrs.privateFlags
            & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0;
    //检查调用者是否有权限添加指定类型的窗口。
    //不同类型的窗口需要不同权限,如 `TYPE_SYSTEM_ALERT`
    //需要 `SYSTEM_ALERT_WINDOW` 权限。
    int res = mPolicy.checkAddPermission(attrs.type, isRoundedCornerOverlay, attrs.packageName,
            appOp);
    //如果权限不足,直接返回错误码。
    if (res != ADD_OKAY) {
        return res;
    }

    WindowState parentWindow = null;
    //获取调用者的PID和UID
    final int callingUid = Binder.getCallingUid();
    final int callingPid = Binder.getCallingPid();
    //临时清除调用者的 Binder 身份,让后续操作以系统身份执行(用于权限绕过,
    //之后 `restoreCallingIdentity` 恢复)
    final long origId = Binder.clearCallingIdentity();
    final int type = attrs.type;

    synchronized (mGlobalLock) {
        if (!mDisplayReady) {
            throw new IllegalStateException("Display has not been initialialized");
        }
        //根据 `displayId` 获取对应的显示器内容对象。
        final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);
        //显示器不存在。
        if (displayContent == null) {
            return WindowManagerGlobal.ADD_INVALID_DISPLAY;
        }
        //应用无权访问
        if (!displayContent.hasAccess(session.mUid)) {
            return WindowManagerGlobal.ADD_INVALID_DISPLAY;
        }
        //`mWindowMap` 是 WMS 维护的 `IBinder -> WindowState` 映射表
        //检查窗口是否重复添加
        if (mWindowMap.containsKey(client.asBinder())) {
            return WindowManagerGlobal.ADD_DUPLICATE_ADD;
        }
        //如果是子窗口
        if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) {
            parentWindow = windowForClientLocked(null, attrs.token, false);
            //子窗口必须依附于一个父窗口,父窗口必须存在
            if (parentWindow == null) {
                return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
            }
            //父窗口不能是子窗口(不允许嵌套子窗口)
            if (parentWindow.mAttrs.type >= FIRST_SUB_WINDOW
                    && parentWindow.mAttrs.type <= LAST_SUB_WINDOW) {
                return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN;
            }
        }
        //私有演示窗口:只能在私有显示器上添加
        if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) {
           
            return WindowManagerGlobal.ADD_PERMISSION_DENIED;
        }
        //演示窗口:显示器必须支持公开演示
        if (type == TYPE_PRESENTATION && !displayContent.getDisplay().isPublicPresentation()) {
            
            return WindowManagerGlobal.ADD_INVALID_DISPLAY;
        }

        int userId = UserHandle.getUserId(session.mUid);
        //如果请求的用户 ID 与调用者不同,
        if (requestUserId != userId) {
            try {
                //校验调用者是否有权限切换到该用户。
                //多用户场景下,确保窗口添加到正确的用户空间
                mAmInternal.handleIncomingUser(callingPid, callingUid, requestUserId,
                        false /*allowAll*/, ALLOW_NON_FULL, null, null);
            } catch (Exception exp) {
                return WindowManagerGlobal.ADD_INVALID_USER;
            }
            
            userId = requestUserId;
        }

        ActivityRecord activity = null;
        final boolean hasParent = parentWindow != null;
        //获取WindowToken
        WindowToken token = displayContent.getWindowToken(
                hasParent ? parentWindow.mAttrs.token : attrs.token);
        //子窗口复用父窗口的 Token:保证同一窗口组的 Token 一致
        final int rootType = hasParent ? parentWindow.mAttrs.type : type;

        boolean addToastWindowRequiresToken = false;

        final IBinder windowContextToken = attrs.mWindowContextToken;
        //Token不存在
        if (token == null) {
            ...
            if (hasParent) {
                //子窗口复用父窗口的 Token
                token = parentWindow.mToken;
            } else if (mWindowContextListenerController.hasListener(windowContextToken)) {
                final IBinder binder = attrs.token != null ? attrs.token : windowContextToken;
                ...
                //创建WindowToken
                token = new WindowToken.Builder(this, binder, type)
                        .setDisplayContent(displayContent)
                        .setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow)
                        .setRoundedCornerOverlay(isRoundedCornerOverlay)
                        .setFromClientToken(true)
                        .setOptions(options)
                        .build();
            } else {
                final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
                //创建WindowToken
                token = new WindowToken.Builder(this, binder, type)
                        .setDisplayContent(displayContent)
                        .setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow)
                        .setRoundedCornerOverlay(isRoundedCornerOverlay)
                        .build();
            }
        } 
        //Token存在
        else if (rootType >= FIRST_APPLICATION_WINDOW
                && rootType <= LAST_APPLICATION_WINDOW) {
            //应用窗口,token是 `ActivityRecord`(即 Activity 的 Token)
            activity = token.asActivityRecord();
            //ActivityRecord不存在
            if (activity == null) {
                return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
            } else if (activity.getParent() == null) {
               ...
            }
            //输入法窗口,Token 类型必须匹配
        } else if (rootType == TYPE_INPUT_METHOD) {
            if (token.windowType != TYPE_INPUT_METHOD) {
                return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
            }
             //语音交互窗口,Token 类型必须匹配
        } else if (rootType == TYPE_VOICE_INTERACTION) {
            if (token.windowType != TYPE_VOICE_INTERACTION) {
                return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
            }
            //壁纸窗口,Token 类型必须匹配
        } else if (rootType == TYPE_WALLPAPER) {
            if (token.windowType != TYPE_WALLPAPER) {
                return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
            }
        } else if (rootType == TYPE_ACCESSIBILITY_OVERLAY) {
            if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) {
                return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
            }
            //Toast 窗口,需要 Token
        } else if (type == TYPE_TOAST) {
            
            addToastWindowRequiresToken = doesAddToastWindowRequireToken(attrs.packageName,
                    callingUid, parentWindow);
            if (addToastWindowRequiresToken && token.windowType != TYPE_TOAST) {
                return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
            }
            //快捷设置对话框,Token 类型必须匹配
        } else if (type == TYPE_QS_DIALOG) {
            if (token.windowType != TYPE_QS_DIALOG) {
                
                return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
            }
        } else if (token.asActivityRecord() != null) {
            
            attrs.token = null;
            //创建 WindowToken
            token = new WindowToken.Builder(this, client.asBinder(), type)
                    .setDisplayContent(displayContent)
                    .setOwnerCanManageAppTokens(session.mCanAddInternalSystemWindow)
                    .build();
        }

        //创建 WindowState
        final WindowState win = new WindowState(this, session, client, token, parentWindow,
                appOp[0], attrs, viewVisibility, session.mUid, userId,
                session.mCanAddInternalSystemWindow);
       // 客户端进程已死亡
       if (win.mDeathRecipient == null) {
            return WindowManagerGlobal.ADD_APP_EXITING;
        }

        if (win.getDisplayContent() == null) {
            return WindowManagerGlobal.ADD_INVALID_DISPLAY;
        }

        final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
        //根据显示器策略调整窗口参数(如系统栏可见性)。
        displayPolicy.adjustWindowParamsLw(win, win.mAttrs);
        win.updateRequestedVisibility(requestedVisibility);
         //做最后的策略校验(如是否允许在锁屏上添加窗口等)
        res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid);
        if (res != ADD_OKAY) {
            return res;
        }
        //创建一对 `InputChannel`(服务端和客户端),通过 SocketPair 建立连接。
        //服务端通道由 WMS 持有,用于向应用发送输入事件。
        //客户端通道通过 `outInputChannel` 返回给应用进程(`ViewRootImpl` 使用)
        final boolean openInputChannels = (outInputChannel != null
                && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
        if  (openInputChannels) {
            win.openInputChannel(outInputChannel);
        }

        if (type == TYPE_TOAST) {
            //每个 UID 同时只能显示一个 Toast
            if (!displayContent.canAddToastWindowForUid(callingUid)) {
                return WindowManagerGlobal.ADD_DUPLICATE_ADD;
            }
            
            if (addToastWindowRequiresToken
                    || (attrs.flags & FLAG_NOT_FOCUSABLE) == 0
                    || displayContent.mCurrentFocus == null
                    || displayContent.mCurrentFocus.mOwnerUid != callingUid) {
               //发送延迟消息,在 Toast 超时后自动隐藏窗口。
                mH.sendMessageDelayed(
                        mH.obtainMessage(H.WINDOW_HIDE_TIMEOUT, win),
                        win.mAttrs.hideTimeoutMilliseconds);
            }
        }

        //WindowContext(Android 11+):允许在非 Activity 上下文中创建窗口
        if (!win.isChildWindow()
                && mWindowContextListenerController.hasListener(windowContextToken)) {
            // 校验窗口类型匹配
            final int windowContextType = mWindowContextListenerController
                    .getWindowType(windowContextToken);
            if (type != windowContextType) {
                return WindowManagerGlobal.ADD_INVALID_TYPE;
            }
            final Bundle options = mWindowContextListenerController
                    .getOptions(windowContextToken);
           // 注册监听器,使 WindowToken 能响应配置变化
            mWindowContextListenerController.registerWindowContainerListener(
                    windowContextToken, token, callingUid, type, options);
        }


        res = ADD_OKAY;
        //BLAST(Buffered Layer Stack):Android 12 引入的新渲染架构标志
        if (mUseBLAST) {
            res |= WindowManagerGlobal.ADD_FLAG_USE_BLAST;
        }
        //如果当前没有焦点窗口,记录此窗口
        if (displayContent.mCurrentFocus == null) {
            displayContent.mWinAddedSinceNullFocus.add(win);
        }
        //某些窗口类型(如系统窗口)不参与点击外部关闭 Task 的判断
        if (excludeWindowTypeFromTapOutTask(type)) {
            displayContent.mTapExcludedWindows.add(win);
        }
        //将窗口与 DisplayContent 关联,并设置 SurfaceControl
        win.attach();
        //将窗口注册到 WMS 的全局映射表中
        mWindowMap.put(client.asBinder(), win);
        ...

        final ActivityRecord tokenActivity = token.asActivityRecord();
        //设置 Starting Window
        if (type == TYPE_APPLICATION_STARTING && tokenActivity != null) {
            tokenActivity.mStartingWindow = win;
        }

        boolean imMayMove = true;
        //将窗口添加到 `WindowToken` 的窗口列表中
        win.mToken.addWindow(win);
        //通知 `DisplayPolicy` 添加窗口(更新系统 UI 布局,如状态栏、导航栏)。
        displayPolicy.addWindowLw(win, attrs);
        
        //输入法窗口处理
        if (type == TYPE_INPUT_METHOD) {
            //设置当前输入法窗口
            displayContent.setInputMethodWindowLocked(win);
            imMayMove = false;
        } else if (type == TYPE_INPUT_METHOD_DIALOG) {
            //计算输入法目标
            displayContent.computeImeTarget(true /* updateImeTarget */);
            imMayMove = false;
        } else {
            //壁纸窗口处理
            if (type == TYPE_WALLPAPER) {
               //标记需要重新布局壁纸 displayContent.mWallpaperController.clearLastWallpaperTimeoutTime();
                displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
            } else if (win.hasWallpaper()) {
                ////标记需要重新布局壁纸 
                displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
            } else if (displayContent.mWallpaperController.isBelowWallpaperTarget(win)) {
                
                displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
            }
        }

        final WindowStateAnimator winAnimator = win.mWinAnimator;
        //标记需要执行入场动画
        winAnimator.mEnterAnimationPending = true;
        //标记窗口是否正在执行入场动画
        winAnimator.mEnteringAnimation = true;
        //检查当前 Activity 是否有"窗口替换"的需求(即 `mReplacingWindow` 不为空)
        //,如果有,则创建一个 `WindowTransition` 来驱动新旧窗口的过渡动画
        if (activity != null && activity.isVisible()
                && !prepareWindowReplacementTransition(activity)) {
            //它会检查 Activity 是否处于"正在重启"状态(`mRelaunching` 标志),
            //如果是,则确保一个  **"空过渡"(None Transition)**  被设置。这个"空过
            //渡"的目的是让 WMS 知道"这个 Activity 要重新绘制,需要等待它的窗口绘制
            //完成后再显示",防止出现白屏或闪屏。
            prepareNoneTransitionForRelaunching(activity);
        }
        
         ...
        //标记输入窗口需要更新
        //`InputMonitor` 是 WMS 中管理**输入系统状态**的核心类,
        //负责维护所有窗口的输入信息,并与系统的 `InputDispatcher`(输入分发器)通信
        displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();

        boolean focusChanged = false;
        if (win.canReceiveKeys()) {
            //更新焦点窗口
            //焦点变化会影响输入法显示、按键分发等
            focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
                    false /*updateInputWindows*/);
            if (focusChanged) {
                imMayMove = false;
            }
        }

        if (imMayMove) {
            //计算输入法目标:如果没有焦点变化,仍可能需要重新计算输入法目标窗口
            displayContent.computeImeTarget(true /* updateImeTarget */);
        }

       //计算窗口的 Z-order 层级
        win.getParent().assignChildLayers();

        if (focusChanged) {
          //通知InputMonitor更新输入焦点 displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus,
                    false /*updateInputWindows*/);
        }
        
        //通知系统输入子系统(InputFlinger)更新窗口信息(用于触摸事件分发)
        displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
        //如果窗口可见且屏幕方向需要变化,发送配置变更通知
        if (win.isVisibleOrAdding() && displayContent.updateOrientation()) {
            displayContent.sendNewConfiguration();
        }

        // 新系统栏(状态栏、导航栏)的 Insets 信息
        displayContent.getInsetsStateController().updateAboveInsetsState(
                win, false /* notifyInsetsChanged */);
        //通过 `outActiveControls` 将控制信息返回给应用
        getInsetsSourceControls(win, outActiveControls);
    }
    //恢复调用者身份
    Binder.restoreCallingIdentity(origId);

    return res;
}

2. 绘制流程的引擎:scheduleTraversals 与 VSync

绘制流程的启动,实际上是由 requestLayout()invalidate() 等操作触发的,它们最终都会调用到 scheduleTraversals() 方法。scheduleTraversals() 的核心工作包括:

  1. 发送同步屏障:在 Handler 的消息队列中插入一个同步屏障,保证后续的绘制消息(异步消息)能被优先处理,提高 UI 响应速度。
  2. 注册 VSync 回调 :向 Choreographer(编舞者)注册一个 CALLBACK_TRAVERSAL 类型的回调。Choreographer 负责接收系统的垂直同步(VSync)信号,并按照输入 > 动画 > 遍历(绘制) 的优先级顺序执行回调。
  3. 等待信号 :当下一个 VSync 信号到来时,Choreographer 就会执行之前注册的 mTraversalRunnable,进而调用到 doTraversal(),最终触发整个绘制流程的核心方法 performTraversals()
scss 复制代码
//frameworks/base/core/java/android/view/ViewRootImpl.java
public void requestLayout() {
    if (!mHandlingLayoutInLayoutRequest) {
        ...
        scheduleTraversals();
    }
}


void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        //MessageQueue 中插入一个同步屏障 。这个屏障的作用是:
        //所有同步消息都不会被执行,只有异步消息可以绕过屏障继续执行
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        //注册一个执行 View 的测量、布局、绘制的CallBack
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    //通知 `ThreadedRenderer`(硬件加速渲染器)即将有新的帧需要渲染。
    //`ThreadedRenderer` 是 Android 硬件加速的核心组件,负责将绘制指令转换为 GPU 命令
        notifyRendererOfFramePending();
       //Android 系统有一个"Draw Lock"机制,用于防止设备在应用正在
       //绘制关键帧时进入休眠
        pokeDrawLockIfNeeded();
    }
}

//VSYNC信号请求:Choreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL)
//具体调用看我的文章 # android 12 中的VSYNC请求
private void scheduleVsyncLocked() {
     ...
     //mDisplayEventReceiver = FrameDisplayEventReceiver
     //它通过 JNI 向系统的 `SurfaceFlinger` 注册 VSync 监听。
     mDisplayEventReceiver.scheduleVsync();
     ...
}

//VSync 信号到达 → `onVsync()` → `doFrame()` →  `doCallbacks()`
//具体调用看我的文章 # android 12 中的VSYNC请求
void doTraversal() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        //移除同步屏障
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
        ...
        //核心绘制流程
        performTraversals();
        ...
       
    }
}

3. 三大流程:performTraversals 详解

performTraversals()ViewRootImpl 最核心的方法,它会按顺序执行一次完整的 View 树刷新:

测量 (Measure)performMeasure() , 从根 DecorView 开始,自上而下地递归调用每个子 View 的 measure() 方法,以确定每个 View 应该占据的宽度和高度。

布局 (Layout)performLayout() ,在上一步确定好尺寸后,自顶向下地递归调用每个 View 的 layout() 方法,确定每个 View 在父容器中的具体位置。

绘制 (Draw)performDraw() ,将 View 树的内容绘制到屏幕上。在硬件加速开启的情况下(Android 默认开启),它会通过 ThreadedRenderer 将绘制指令交给 GPU 处理,否则会通过 CPU 进行软件绘制。

4. 输入事件的中枢:InputStage 责任链

所有触摸、按键事件由系统 InputFlinger 分发给应用进程,ViewRootImpl 是应用内接收事件的入口。它内部设计了一套名为 InputStage责任链来处理事件。

  • ViewRootImplInputChannel 收到原始事件后,会被封装成 QueuedInputEvent 放入队列。
  • 随后,doProcessInputEvents() 方法会从队列中取出事件,并通过 deliverInputEvent() 方法将其交给责任链的第一个节点(mFirstInputStage)处理。
  • InputStage 链上的每个节点(如 ViewPreImeInputStageViewPostImeInputStage)各司其职,依次处理事件的不同阶段。如果某个 Stage 消费了事件,链条就会终止;否则,事件会继续传递给下一个 Stage。最终,事件会被分发给具体的目标 View。

输入事件怎么分发的具体看我的文章# android12 InputManagerService分析之输入事件分发

相关推荐
stevenzqzq19 分钟前
compose项目返回到当前页面闪烁原因分析
android
古法安卓1 小时前
Android-显示流程
android·java·android studio
CircleMouse1 小时前
画一个Android智能手机机器人
android·智能手机·机器人
数据知道2 小时前
PHP 代码审计实战——ThinkPHP、Laravel 历史漏洞模式深度剖析
android·网络·web安全·网络安全·php·laravel
拍客圈3 小时前
换服务器 mozcjpeg 5.0.0
android
蜡台4 小时前
Jetpack Compose 稳定性、重组优化(Stable / @NonRestartableComposable)
android·kotlin·compose·jepack
__Witheart__4 小时前
3588 Android 13 预装apk失败 —— 不再使用apps.mk
android
__Witheart__4 小时前
3588 Android 串口软件提示“没有串口读写权限”
android
搭贝5 小时前
国资报送责任制怎么建?三级责任矩阵设计
android·数据库·人工智能·线性代数·低代码·矩阵·制造