Android布局控件View ViewRootImpl WindowManagerService关系

目录
  • 1. View,ViewRoot和WindowManager简单介绍
    • 1.1 View和ViewGroup
    • 1.2 ViewRootImpl
    • 1.3 WindowManager
  • 2. ViewRootImpl的起源
    • 2.1 ViewRootImpl创建时机
    • 2.2 ViewRootImpl通知注册Window
  • 3.ViewRootImpl与WindowManagerService的通信
    • 3.1 WindowSession
    • 3.2 IWindow
  • 4. ViewRootImpl与View

1. View,ViewRoot和WindowManager简单介绍

1.1 View和ViewGroup

Android的基本布局控件,结构是树装,ViewGroup实现了ViewParent接口,每个View内部保留一个ViewParent变量,代表他的父节点

1.2 ViewRootImpl

ViewRoot概念的具体实现类,也实现了ViewParent接口,每个View树顶级ViewParent就是这个类,主要管理

  • View树的measure,layout,draw
  • 向WindowManagerService注册Window
  • 接收WindowManagerService的事件回调

1.3 WindowManager

具体实现类WindowManagerImpl,不过最终任务委托给了WindowManagerGlobal对象,负责建立WindowManagerService连接和通信

ViewRootImpl的功能相当于中介,左手掌握的顶级View,右手掌握WindowManger通信

2. ViewRootImpl的起源

2.1 ViewRootImpl创建时机

这个和WindowManager是有点关联的,起点一般是Activity调用resume的时机,这个具体是在ActivityThread类中的

public final class ActivityThread {
    final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            decor.setVisibility(4);
            wm = a.getWindowManager();
            LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            l.type = 1;
            l.softInputMode |= forwardBit;
            if (r.mPreserveWindow) {
                a.mWindowAdded = true;
                r.mPreserveWindow = false;
                ViewRootImpl impl = decor.getViewRootImpl();
                if (impl != null) {
                    impl.notifyChildRebuilt();
                }
            }
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    // 核心
                    wm.addView(decor, l);
                } else {
                    a.onWindowAttributesChanged(l);
                }
            }
        } else if (!willBeVisible) {
            r.hideForNow = true;
        }
    }
}

wm.addView()函数是入口,wm实际是WindowManager对象,WindowManager真正做工作的类是WindowManagerGlobal

addView()实际上是添加的DecorView ,从r.window获取(Activity的话window实现类是PhoneWindow)

public final class WindowManagerGlobal {
    public void addView(View view, android.view.ViewGroup.LayoutParams params, Display display, Window parentWindow) {
                // 省略非必要代码
                ViewRootImpl root = new ViewRootImpl(view.getContext(), display);
                view.setLayoutParams(wparams);
                this.mViews.add(view);
                this.mRoots.add(root);
                this.mParams.add(wparams);
                try {
                    root.setView(view, wparams, panelParentView);
                } catch (RuntimeException var13) {
                    if (index >= 0) {
                        this.removeViewLocked(index, true);
                    }
                    throw var13;
                }
            }
        }
    }
}

这时候创建了ViewRootImpl对象,并把View,ViewRootImpl和windowManagerParam保存到WindowManagerGlobal的集合中,root.setView() 负责接力下一棒

2.2 ViewRootImpl通知注册Window

public final class ViewRootImpl implements ViewParent, Callbacks, DrawCallbacks {
public void setView(View view, LayoutParams attrs, View panelParentView) {
    synchronized(this) {
        if (this.mView == null) {
            this.mView = view;
            // 省略代码
            try {
                this.mOrigWindowType = this.mWindowAttributes.type;
                this.mAttachInfo.mRecomputeGlobalAttributes = true;
                this.collectViewAttributes();
                /**
                * 核心
                */
                res = this.mWindowSession.addToDisplay(this.mWindow, this.mSeq, this.mWindowAttributes, this.getHostVisibility(), this.mDisplay.getDisplayId(), this.mAttachInfo.mContentInsets, this.mAttachInfo.mStableInsets, this.mAttachInfo.mOutsets, this.mInputChannel);
            } catch (RemoteException var19) {
                this.mAdded = false;
                this.mView = null;
                this.mAttachInfo.mRootView = null;
                this.mInputChannel = null;
                this.mFallbackEventHandler.setView((View)null);
                this.unscheduleTraversals();
                this.setAccessibilityFocus((View)null, (AccessibilityNodeInfo)null);
                throw new RuntimeException("Adding window failed", var19);
            } finally {
                if (restore) {
                    attrs.restore();
                }
            }
        }
    }
}
}

ViewRootImpl保存和View对象,这里我们也可以发现 每一个顶级View都会对应一个ViewRootImpl对象,this.mWindowSession.addToDisplay() 通过WindowSession通知WindowManagerService注册Window

3.ViewRootImpl与WindowManagerService的通信

3.1 WindowSession

ViewRootImpl向WindowManagerService发送信息的类,实际上是一个AIDL接口

public interface IWindowSession extends IInterface {}

ViewRootImpl通过WindowManagerGlobal.getWindowSession() 获取WindowSession对象

public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    // Emulate the legacy behavior.  The global instance of InputMethodManager
                    // was instantiated here.
                    // TODO(b/116157766): Remove this hack after cleaning up @UnsupportedAppUsage
                    InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
                    IWindowManager windowManager = getWindowManagerService();
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            });
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowSession;
        }
    }

前面注册Window的时候就用到的的就是WindowSession对象的addToDisplay

3.2 IWindow

这个也是一个AIDL接口文件,主要是用于WindowManagerService向ViewRootImpl发送消息,ViewRootImpl调用mWindowSession.addToDisplay注册窗口,会把IWindow这个信使带给WindowManagerService

public final class ViewRootImpl implements ViewParent, Callbacks, DrawCallbacks {
    static class W extends android.view.IWindow.Stub {
        private final WeakReference<ViewRootImpl> mViewAncestor;
        private final IWindowSession mWindowSession;
        W(ViewRootImpl viewAncestor) {
            this.mViewAncestor = new WeakReference(viewAncestor);
            this.mWindowSession = viewAncestor.mWindowSession;
        }
        public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout, boolean alwaysConsumeNavBar, int displayId) {
           // 省略实现
        }
        public void moved(int newX, int newY) {
            // 省略实现
        }
        public void dispatchAppVisibility(boolean visible) {
            // 省略实现
        }
        public void dispatchGetNewSurface() {
            // 省略实现
        }
        public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
            // 省略实现
        }
        private static int checkCallingPermission(String permission) {
            // 省略实现
        }
        public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
            // 省略实现
        }
        public void closeSystemDialogs(String reason) {
           // 省略实现
        }
        public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, boolean sync) {
          // 省略实现
        }
        public void dispatchWallpaperCommand(String action, int x, int y, int z, Bundle extras, boolean sync) {
          // 省略实现
        }
        public void dispatchDragEvent(DragEvent event) {
          // 省略实现
        }
        public void updatePointerIcon(float x, float y) {
        // 省略实现
        }
        public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, int localValue, int localChanges) {
            // 省略实现
        }
        public void dispatchWindowShown() {
            // 省略实现
        }
        public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
           // 省略实现
        }
        public void dispatchPointerCaptureChanged(boolean hasCapture) {
            // 省略实现
        }
    }
}

我们比较熟悉的可能就是WindowFocusChanged这个函数

4. ViewRootImpl与View

这两个关系紧密,我们最容易接触到的是ViewRootImpl控制者View的刷新

void scheduleTraversals() {
    if (!this.mTraversalScheduled) {
        this.mTraversalScheduled = true;
        this.mTraversalBarrier = this.mHandler.getLooper().getQueue().postSyncBarrier();
        this.mChoreographer.postCallback(2, this.mTraversalRunnable, (Object)null);
        if (!this.mUnbufferedInputDispatch) {
            this.scheduleConsumeBatchedInput();
        }
        this.notifyRendererOfFramePending();
        this.pokeDrawLockIfNeeded();
    }
}

scheduleTraversals是刷新方法的起点:

主线程Handler设置同步屏障(postSyncBarrier),让刷新任务先执行

注册mChoreographer.postCallback()接收界面更新的同步消息

接收到刷新的同步消息后,执行mTraversalRunnable的run方法,调用ViewRootImpl.doTraversal()

void doTraversal() {
    if (this.mTraversalScheduled) {
        this.mTraversalScheduled = false;
        this.mHandler.getLooper().getQueue().removeSyncBarrier(this.mTraversalBarrier);
        if (this.mProfile) {
            Debug.startMethodTracing("ViewAncestor");
        }
        this.performTraversals();
        if (this.mProfile) {
            Debug.stopMethodTracing();
            this.mProfile = false;
        }
    }
}

this.performTraversals()内部调用performMeasure, performLayout, performDraw View树的measure,layout和draw实现刷新

以上就是Android布局控件View ViewRootImpl WindowManagerService关系的详细内容,更多关于Android布局控件的资料请关注我们其它相关文章!

(0)

相关推荐

  • Android开发InputManagerService创建与启动流程

    目录 前言 启动流程 创建输入系统 启动输入系统 输入系统就绪 结束 前言 之前写过几篇关于输入系统的文章,但是还没有写完,后来由于工作的变动,这个事情就一直耽搁了.而现在,在工作中,遇到输入系统相关的事情也越来越多,其中有一个非常有意思的需求,因此是时候继续分析 InputManagerService. InputManagerService 系统文章,基于 Android 12 进行分析. 本文将以 IMS 简称 InputManagerService. 启动流程 InputManagerS

  • Android Service启动绑定流程详解

    目录 前言 一.Service 的启动流程 二.Service的绑定 三.Service的Context 总结 前言 本文基于Android 11,参考<Android进阶解密>一书资料.了解Service的启动和绑定流程,以及Service的Context创建过程. 由于基于分析流程,忽略很多细节分支.各位在看源码的时候,要尽可能忽略细节,分析整体流程之后,还有精力的话再去看细节.例如有些属性是在后面赋值的,如果在前面追究,难哦. 另:阅读这种流程需要很大的耐心和毅力.建议在心情愉悦想要学习

  • Android O对后台Service限制详解

    目录 Service问题 什么是前台应用 前台Service和后台Service 后台Service限制 解决后台Service限制 Service问题 Service没有界面,运行于后台,它会消耗设备资源,并且可能会导致不好的用户体验,例如资源占用过多,导致设备运行不流畅.为了缓解这个问题,Android O版本(Android 8.0, API 26)对后台Service强加了一些限制.注意,只是对后台Service加了限制,前台Service不受影响. 什么是前台应用 在解释后台Servi

  • android 微信抢红包工具AccessibilityService实现详解

    目录 1.目标 2.实现流程 1.流程分析(这里只分析在桌面的情况) 2.实现步骤 1.收到通知 以及 点击通知栏 2.点击红包 3.点击开红包 4.退出红包详情页 3.遇到问题 4.完整代码 MyNotificationListenerService MyAccessibilityService 5.总结 你有因为手速不够快抢不到红包而沮丧? 你有因为错过红包而懊恼吗? 没错,它来了... 1.目标 使用AccessibilityService的方式,实现微信自动抢红包(吐槽一下,网上找了许多

  • Android NotificationListenerService 通知服务原理解析

    目录 前言 NotificationListenerService方法集 NotificationListenerService接收流程 通知消息发送流程 NotificationListenerService注册 总结 前言 在上一篇通知服务NotificationListenerService使用方法 中,我们已经介绍了如何使用NotificationListenerService来监听消息通知,在最后我们还模拟了如何实现微信自动抢红包功能. 那么NotificationListenerSe

  • Android NotificationListenerService通知监听服务使用

    目录 前言 NotificationListenerService的使用 启动服务 实现自动抢红包功能 最后 前言 本篇我们将介绍如何利用NotificationListenerService实现类似智能手表通知同步.微信自动抢红包等功能.实现这些功能的原理其实就是监听系统的通知服务,接下来我们来看该如何实现. NotificationListenerService的使用 创建NotificationListenerService 在Android中如果我们想要监听系统的通知,就需要实现一个服务

  • Android布局控件View ViewRootImpl WindowManagerService关系

    目录 1. View,ViewRoot和WindowManager简单介绍 1.1 View和ViewGroup 1.2 ViewRootImpl 1.3 WindowManager 2. ViewRootImpl的起源 2.1 ViewRootImpl创建时机 2.2 ViewRootImpl通知注册Window 3.ViewRootImpl与WindowManagerService的通信 3.1 WindowSession 3.2 IWindow 4. ViewRootImpl与View 1

  • Android布局控件DrawerLayout实现完美侧滑效果

    drawerLayout其实是一个布局控件,跟LinearLayout等控件是一样的,但是drawerLayout带有滑动的功能.只要按照drawerLayout的规定布局方式写完布局,就能有侧滑的效果. 1)在DrawerLayout中,第一个子View必须是显示内容的view,并且设置它的layout_width和layout_height属性是match_parent. 2)第二个view是抽屉view,并且设置属性layout_gravity="left|right",表示是从

  • Android 布局控件之LinearLayout详细介绍

    LinearLayout是线性布局控件,它包含的子控件将以横向或竖向的方式排列,按照相对位置来排列所有的widgets或者其他的containers,超过边界时,某些控件将缺失或消失.因此一个垂直列表的每一行只会有一个widget或者是container,而不管他们有多宽,而一个水平列表将会只有一个行高(高度为最高子控件的高度加上边框高度).LinearLayout保持其所包含的widget或者是container之间的间隔以及互相对齐(相对一个控件的右对齐.中间对齐或者左对齐). API说明

  • Android布局控件之常用linearlayout布局

    LinearLayout是线性布局控件,它包含的子控件将以横向或竖向的方式排列,按照相对位置来排列所有的widgets或者其他的containers,超过边界时,某些控件将缺失或消失.因此一个垂直列表的每一行只会有一个widget或者是container,而不管他们有多宽,而一个水平列表将会只有一个行高(高度为最高子控件的高度加上边框高度).LinearLayout保持其所包含的widget或者是container之间的间隔以及互相对齐(相对一个控件的右对齐.中间对齐或者左对齐). xml属性

  • Android控件View打造完美的自定义侧滑菜单

    一.概述 在App中,经常会出现侧滑菜单,侧滑滑出View等效果,虽然说Android有很多第三方开源库,但是实际上咱们可以自己也写一个自定义的侧滑View控件,其实不难,主要涉及到以下几个要点: 1.对Android中Window类中的DecorView有所了解 2.对Scroller类实现平滑移动效果 3.自定义ViewGroup的实现 首先来看看效果图吧:     下面现在就来说说这里咱们实现侧滑View的基本思路吧,这里我采用的是自定义一个继承于RelativeLayout的控件叫做XC

  • Android控件View的文字周围添加图标

    在Android控件View的文字周围添加图标,供大家参考,具体内容如下 在控件TextView文字周围放置图片(基于TextView的Button也能实现),减少多布局组合嵌套. 优点:使用LinearLayout对ImageView和TextView组合布局固然可行, 但是布局文件会冗长许多. 以TextView为例: 在XML布局文件中设置以下5个属性: drawableTop: 指定文本上方的图形. drawableBottom: 指定文本下方的图形. drawableLeft: 指定文

  • 使用PlatformView将 Android 控件view制作成Flutter插件

    目录 引言 1. FlutterPlugin 创建 2. 创建 Android 控件 3. 注册 Android 控件 4. 封装 Android 层通信交互 ‘CustomViewController’ 代码说明 5. 在 flutter 中如何使用已注册的 Android 控件(view) 代码说明 如何使用这个View 6. 附上 example 完整代码 引言 小编最近在项目中实现相机识别人脸的功能,将 Android 封装的控件 view 进行中转,制作成 FlutterPlugin

  • Android编程布局控件之AbsoluteLayout用法实例分析

    本文实例讲述了Android编程布局控件之AbsoluteLayout用法.分享给大家供大家参考,具体如下: AbsoluteLayout是绝对布局管理器,指的是指定组件的左上角绝对坐标来指定组件的布局 <?xml version="1.0" encoding="utf-8"?> <AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"

  • Android开发 -- 控件的显示与隐藏 setVisibility View.VISIBLE View.INVISIBLE View.GONE

    在Android中setVisibility作为显示和隐藏的属性,一般我们呢都是在代码中进行操作,例如: [code]<span style="white-space:pre">  </span>this.mItem.setVisibility(View.VISIBLE);[code] 其能够被设置的值有三个,分别是: View.VISIBLE    可见 View.INVISIBLE    不可见,但是它原来占用的位子还在 View.GONE  不可见,并且不

  • Android设置控件阴影的三种方法

    本文实例为大家分享了Android设置控件阴影的方法,供大家参考,具体内容如下 第一种方式:elevation View的大小位置都是通过x,y确定的,而现在有了z轴的概念,而这个z值就是View的高度(elevation),而高度决定了阴影(shadow)的大小. View Elevation(视图高度) View的z值由两部分组成,elevation和translationZ(它们都是Android L新引入的属性). eleavation是静态的成员,translationZ是用来做动画.

随机推荐