• Android:Window相关理解



    一、Window概述

    Window概念

    • window是一个抽象类,主要用来处理窗口的展示与行为策略(比如触摸,点击等)。
    • window是View的直接管理者
    • window类的实例应该是作为顶级view,被添加到windowManager的顶级视图。(PhoneWindow)
    • window提供了标准的UI策略,如背景,标题区域,默认密钥处理等。
    • widnow唯一的实现类是android.view.PhoneWindow,如果要使用window就必须通过android.view.PhoneWindow。

    Window和DecorView

    • 一个Activity对应一个PhoneWindow,PhoneWidnow会处理这个activity中的ui展示和 用户的行为(如触摸,点击等)。
    • PhoneWidnow不是一个View对象,通过将PhoneWindow添加到windowManager中,PhoneWindow能够将要处理的行为事件传递给DecorView。
    • DecorView继承自FrameLayout,是除了Window之外最顶级的视图。
    • ContentView就是我们通常使用activity.setContentView()中设置的View。它所对应的id是R.id.content。
      在这里插入图片描述

    二、Window属性和类型

    添加窗口是通过WindowManagerGlobal的addView方法操作的,这里有三个必要参数。view,params,display。 display : 表示要输出的显示设备。 view : 表示要显示的View,一般是对该view的上下文进行操作。(view.getContext()) params : 类型为WindowManager.LayoutParams,即表示该View要展示在窗口上的布局参数。其中有一个重要的参数type,用来表示窗口的类型。

    Window的类型

    应用窗口

    Activity 对应的窗口类型是应用窗口, 所有 Activity 默认的窗口类型是 TYPE_BASE_APPLICATION。 WindowManager 的 LayoutParams 的默认类型是 TYPE_APPLICATION。 Dialog 并没有设置type,所以也是默认的窗口类型即 TYPE_APPLICATION

    子窗口

    子窗口不能单独存在,它需要附属在特定的父Window之中,常见的存在便是PopWindow,之所以称其为子窗口,是因为其的存在或出现依附于父窗口,父窗口显现子窗口才能出现,反之亦然

    系统窗口

    系统窗口跟应用窗口不同,不需要对应 Activity。跟子窗口不同,不需要有父窗口。一般来讲,系统窗口应该由系统来创建的,常见的系统窗口有音量调节栏、Toast弹窗和系统状态栏,屏保等。

    Window的属性

    这里介绍日常开发中我们或多或少会用到的Window属性

    type参数
    • type参数,表示Window是什么类型,同时起到Z-order参数的作用,表示Window的层级,一般从0~9999,数值越大,越容易覆盖在屏幕上方

    应用窗口的type属性值
    应用程序Window的type值范围是[1-99],什么是应用程序Window,比如Activity所展示的页面,在WindowManager#LayoutParams中定义了如下应用程序的type值

    // 应用程序 Window 的开始值\
    public static final int FIRST_APPLICATION_WINDOW = 1;
    // 应用程序 Window 的基础值\
    public static final int TYPE_BASE_APPLICATION   = 1;\
    // 普通的应用程序\
    public static final int TYPE_APPLICATION        = 2;\
    // 特殊的应用程序窗口,当程序可以显示 Window 之前使用这个 Window 来显示一些东西\
    public static final int TYPE_APPLICATION_STARTING = 3;\
    // TYPE_APPLICATION 的变体,在应用程序显示之前,WindowManager 会等待这个 Window 绘制完毕\
    public static final int TYPE_DRAWN_APPLICATION = 4;\
    // 应用程序 Window 的结束值\
    public static final int LAST_APPLICATION_WINDOW = 99;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    子窗口的type属性值
    表示子Window,它的范围是[1000,1999],这些Window会按照Z-Order顺序依附于父Window上,而且他们的坐标是相当于父Window的,例如PopupWindow和一些Dialo

    /**
     * 子Window的开始值,该Window的token必须设置在他们依附的父Window
     */
    public static final int FIRST_SUB_WINDOW = 1000;
    
    /**
     * 应用程序Window上面的面板
     */
    public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;
    
    /**
     * 用于显示多媒体(比如视频)的Window,这些Windows会显示在他们依附的Window后面
     */
    public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;
    
    /**
     * 应用程序Window上面的子面板
     */
    public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;
    
    /** 
     * 当前Window的布局和顶级Window布局相同时,不能作为子代的容器
     */
    public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;
    
    /**
     * 用于在媒体Window上显示覆盖物
     * @hide
     */
    @UnsupportedAppUsage
    public static final int TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW + 4;
    
    /**
     * 依附在应用Window上和它的子面板Window上的子面板
     * @hide
     */
    public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;
    
    /**
     * 子Window的结束值
     */
    public static final int LAST_SUB_WINDOW = 1999;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    系统窗口的属性值
    系统Window的范围是[2000,2999],常见的系统的Window有Toast、输入法窗口、系统音量条窗口、系统错误窗口等,对应type的值如下

    // 系统Window类型的开始值\
    public static final int FIRST_SYSTEM_WINDOW     = 2000;\
    \
    // 系统状态栏,只能有一个状态栏,它被放置在屏幕的顶部,所有其他窗口都向下移动\
    public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW;\
    \
    // 系统搜索窗口,只能有一个搜索栏,它被放置在屏幕的顶部\
    public static final int TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1;\
    \
    @Deprecated\
    // API 已经过时,用 TYPE_APPLICATION_OVERLAY 代替\
    public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2;\
    \
    @Deprecated\
    // API 已经过时,用 TYPE_APPLICATION_OVERLAY 代替\
    public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;\
    \
    // 已经从系统中被移除,可以使用 TYPE_KEYGUARD_DIALOG 代替\
    public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4;\
    \
    @Deprecated\
    // API 已经过时,用 TYPE_APPLICATION_OVERLAY 代替\
    public static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5;\
    \
    @Deprecated\
    // API 已经过时,用 TYPE_APPLICATION_OVERLAY 代替\
    public static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;\
    \
    @Deprecated\
    // API 已经过时,用 TYPE_APPLICATION_OVERLAY 代替\
    public static final int TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7;\
    \
    // 系统对话框窗口\
    public static final int TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8;\
    \
    // 锁屏时显示的对话框\
    public static final int TYPE_KEYGUARD_DIALOG    = FIRST_SYSTEM_WINDOW+9;\
    \
    @Deprecated\
    // API 已经过时,用 TYPE_APPLICATION_OVERLAY 代替\
    public static final int TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10;\
    \
    // 输入法窗口,位于普通 UI 之上,应用程序可重新布局以免被此窗口覆盖\
    public static final int TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11;\
    \
    // 输入法对话框,显示于当前输入法窗口之上\
    public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;\
    \
    // 墙纸\
    public static final int TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13;\
    \
    // 状态栏的滑动面板\
    public static final int TYPE_STATUS_BAR_PANEL   = FIRST_SYSTEM_WINDOW+14;\
    \
    // 应用程序叠加窗口显示在所有窗口之上\
    public static final int TYPE_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 38;\
    \
    // 系统Window类型的结束值\
    public static final int LAST_SYSTEM_WINDOW      = 2999;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    需要注意的是,使用系统窗口需要申请相应权限Manifest.permission.SYSTEM_ALERT_WINDOW

    Flag属性

    除了Type属性以外,Flag属性用以控制Window的一些行为特征,如出现时Window后方是否会变暗

    // 当 Window 可见时允许锁屏\
    public static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON     = 0x00000001;\
    \
    // Window 后面的内容都变暗\
    public static final int FLAG_DIM_BEHIND        = 0x00000002;\
    \
    @Deprecated\
    // API 已经过时,Window 后面的内容都变模糊\
    public static final int FLAG_BLUR_BEHIND        = 0x00000004;\
    \
    // Window 不能获得输入焦点,即不接受任何按键或按钮事件,例如该 Window 上 有 EditView,点击 EditView 是 不会弹出软键盘的\
    // Window 范围外的事件依旧为原窗口处理;例如点击该窗口外的view,依然会有响应。另外只要设置了此Flag,都将会启用FLAG_NOT_TOUCH_MODAL\
    public static final int FLAG_NOT_FOCUSABLE      = 0x00000008;\
    \
    // 设置了该 Flag,将 Window 之外的按键事件发送给后面的 Window 处理, 而自己只会处理 Window 区域内的触摸事件\
    // Window 之外的 view 也是可以响应 touch 事件。\
    public static final int FLAG_NOT_TOUCH_MODAL    = 0x00000020;\
    \
    // 设置了该Flag,表示该 Window 将不会接受任何 touch 事件,例如点击该 Window 不会有响应,只会传给下面有聚焦的窗口。\
    public static final int FLAG_NOT_TOUCHABLE      = 0x00000010;\
    \
    // 只要 Window 可见时屏幕就会一直亮着\
    public static final int FLAG_KEEP_SCREEN_ON     = 0x00000080;\
    \
    // 允许 Window 占满整个屏幕\
    public static final int FLAG_LAYOUT_IN_SCREEN   = 0x00000100;\
    \
    // 允许 Window 超过屏幕之外\
    public static final int FLAG_LAYOUT_NO_LIMITS   = 0x00000200;\
    \
    // 全屏显示,隐藏所有的 Window 装饰,比如在游戏、播放器中的全屏显示\
    public static final int FLAG_FULLSCREEN      = 0x00000400;\
    \
    // 表示比FLAG_FULLSCREEN低一级,会显示状态栏\
    public static final int FLAG_FORCE_NOT_FULLSCREEN   = 0x00000800;\
    \
    // 当用户的脸贴近屏幕时(比如打电话),不会去响应此事件\
    public static final int FLAG_IGNORE_CHEEK_PRESSES    = 0x00008000;\
    \
    // 则当按键动作发生在 Window 之外时,将接收到一个MotionEvent.ACTION_OUTSIDE事件。\
    public static final int FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000;\
    \
    @Deprecated\
    // 窗口可以在锁屏的 Window 之上显示, 使用 Activity#setShowWhenLocked(boolean) 方法代替\
    public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;\
    \
    // 表示负责绘制系统栏背景。如果设置,系统栏将以透明背景绘制,\
    // 此 Window 中的相应区域将填充 Window#getStatusBarColor()和 Window#getNavigationBarColor()中指定的颜色。\
    public static final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000;\
    \
    // 表示要求系统壁纸显示在该 Window 后面,Window 表面必须是半透明的,才能真正看到它背后的壁纸\
    public static final int FLAG_SHOW_WALLPAPER = 0x00100000;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    软硬键盘

    表示Window软键盘输入区域的显示模式,比如我们在微信聊天时,我们希望点击输入框软键盘弹起来的时候,能把输入框也顶上去,这样就可以看见自己输入的内容了。

    // 没有指定状态,系统会选择一个合适的状态或者依赖于主题的配置
    public static final int SOFT_INPUT_STATE_UNCHANGED = 1;
    
    // 当用户进入该窗口时,隐藏软键盘
    public static final int SOFT_INPUT_STATE_HIDDEN = 2;
    
    // 当窗口获取焦点时,隐藏软键盘
    public static final int SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3;
    
    // 当用户进入窗口时,显示软键盘
    public static final int SOFT_INPUT_STATE_VISIBLE = 4;
    
    // 当窗口获取焦点时,显示软键盘
    public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;
    
    // window会调整大小以适应软键盘窗口
    public static final int SOFT_INPUT_MASK_ADJUST = 0xf0;
    
    // 没有指定状态,系统会选择一个合适的状态或依赖于主题的设置
    public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00;
    
    // 当软键盘弹出时,窗口会调整大小,例如点击一个EditView,整个layout都将平移可见且处于软件盘的上方
    // 同样的该模式不能与SOFT_INPUT_ADJUST_PAN结合使用;
    // 如果窗口的布局参数标志包含FLAG_FULLSCREEN,则将忽略这个值,窗口不会调整大小,但会保持全屏。
    public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;
    
    // 当软键盘弹出时,窗口不需要调整大小, 要确保输入焦点是可见的,
    // 例如有两个EditView的输入框,一个为Ev1,一个为Ev2,当你点击Ev1想要输入数据时,当前的Ev1的输入框会移到软键盘上方
    // 该模式不能与SOFT_INPUT_ADJUST_RESIZE结合使用
    public static final int SOFT_INPUT_ADJUST_PAN = 0x20;
    
    // 将不会调整大小,直接覆盖在window上
    public static final int SOFT_INPUT_ADJUST_NOTHING = 0x30;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    其他参数
    • x与y属性:指定Window左上角的位置。
    • alpha:Window的透明度。
    • gravity:Window在屏幕中的位置,使用的是Gravity类的常量。
    • format:Window的像素格式,值定义在PixelFormat中。

    三、WindowManager.addView()

    下面我们了解Window的添加过程,也就是WindowManager的addView()过程

    我们先来看Window的内部机制图
    在这里插入图片描述
    对相关机制涉及到的类进行一番解读

    • ViewManager是个接口,用来规定View的一些控制行为
    public interface ViewManager
    {
        public void addView(View view, ViewGroup.LayoutParams params);
        public void updateViewLayout(View view, ViewGroup.LayoutParams params);
        public void removeView(View view);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • WindowManager继承自ViewManager,并通过注解向外暴露可以获取的方式
    public interface ViewManager
    {
        public void addView(View view, ViewGroup.LayoutParams params);
        public void updateViewLayout(View view, ViewGroup.LayoutParams params);
        public void removeView(View view);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • WindowManagerImpl是WindowManager的代理类,可以通过getSystemService获取,来看WindowManagerImpl中的addView()
    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
    	applyDefaultToken(params);
    	mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 这里调用mGlobal.addView()去进行View的添加控制,需要注意的是,WindowManagerGlobal是一个全局单例类,实际上就是使用桥接模式将所有View的控制委托给WindowManagerGlobal进行控制
    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow, int userId) {
        //判断参数的合法性    
        if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }
        if (display == null) {
            throw new IllegalArgumentException("display must not be null");
        }
        if (!(params instanceof WindowManager.LayoutParams)) {
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }
    
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        //如果是子Window,需要对参数做额外调整
        if (parentWindow != null) {
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
            final Context context = view.getContext();
            if (context != null
                    && (context.getApplicationInfo().flags
                            & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
                wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            }
        }
    
        //ViewRootImpl实例
        ViewRootImpl root;
        View panelParentView = null;
    
        synchronized (mLock) {
            // 省略
            //创建ViewRootImpl实例,并且设置参数
            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);
            //分别记录View树 ViewRootImpl和Window参数,见分析1
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
            
            try {
                //最后通过ViewRootImpl来添加Window,见分析2
                root.setView(view, wparams, panelParentView, userId);
            } catch (RuntimeException e) {
               ...
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 由于WindowManagerGlobal是单例,它是真正WindowManager的逻辑实现类,所以需要把要处理的Window等都记录起来,这里使用了几个数据结构进行控制,注意到ViewRootImpl和Window其实是对应的关系,最后通过ViewRootImpl.setView()方法控制View的添加
    private final ArrayList<View> mViews = new ArrayList<View>();
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>();
    
    • 1
    • 2
    • 3
    • 调用ViewRootImpl的setView()方法
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
            int userId) {
        synchronized (this) {
                ...
                //分析1,在被添加到WindowManager之前调用一次
                requestLayout();
                ...
                //通过WindowSession来完成IPC调用,完成创建Window
                try {
                    mOrigWindowType = mWindowAttributes.type;
                    mAttachInfo.mRecomputeGlobalAttributes = true;
                    collectViewAttributes();
                    adjustLayoutParamsForCompatibility(mWindowAttributes);
                    controlInsetsForCompatibility(mWindowAttributes);
                    res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), userId,
                            mInsetsController.getRequestedVisibilities(), inputChannel, mTempInsets,
                            mTempControls);
                    if (mTranslator != null) {
                        mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);
                        mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls);
                    }
                } catch (RemoteException e) {
                    mAdded = false;
                    mView = null;
                    mAttachInfo.mRootView = null;
                    mFallbackEventHandler.setView(null);
                    unscheduleTraversals();
                    setAccessibilityFocus(null, null);
                    throw new RuntimeException("Adding window failed", e);
                } finally {
                    if (restore) {
                        attrs.restore();
                    }
                }
    
              ...
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 上面代码是ViewRootImpl的setView方法部分逻辑,它主要干俩件事,第一件事就是更新界面,在注释分析1的地方,通过调用requestLayout来完成异步刷新请求,方法实现如下
    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread();
            mLayoutRequested = true;
            scheduleTraversals();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 其中scheduleTraversal方法就是View绘制的入口,接着会通过mWindowSession的addToDisplay方法来完成Window的添加过程,那这个mWindowSession是什么类的实例呢,通过查看源码可知,mWindowSession是一个IWindowSession对象,而IWindowSession是一个IBinder接口,所以mWindowSession只是一个Binder对象,而实现类在WindowManagerService中,这里通过mWindowSession完成了IPC通信。
      然后真正添加Window的逻辑就交由WindowManagerService(简称WMS)了,由于WMS比较复杂,这里就不过多深入了。

    ViewRootImpl在其中起到的作用就是View和WindowManagerService的桥梁,在该类中对View进行了绘制,同时又通过IPC通信让WMS创建了Window

    对于其中几个重要的类,进行梳理如下

    • ViewRootImpl,在调用addView时会创建实例,这也就说明一个View树对应一个ViewRootImpl,同时它是Window和View之间的桥梁,一边负责View的绘制,一边负责IPC通信到WMS创建Window。

    • IWindowSession实例,它是APP范围内单例,是一个Binder,负责和WMS通信。这里为什么一个一个应用就一个实例呢,这是因为WMS是系统服务,它要服务很多个APP,而一个APP又有多个Window,所以每个Window都要WMS来管理,则太多了,这样WMS只需要和APP的IWindowSession进行通信即可。

    • WindowManagerGlobal实例,前面我们调用WindowManager的addView方法时,会调用该类的单例,它可以看成是WindowManager的实现单例。

    关于IWindowSession通信过程如下
    在这里插入图片描述

    总结

    以上便是笔者关于Window的相关理解

  • 相关阅读:
    中创算力:打造区块链产业生态,助力郑州创建国家级区块链先导区​
    嵌入式系统开发笔记80:应用Qt Designer进行主界面设计
    AE(自动编码器)与VAE(变分自动编码器)的区别和联系?
    【QT--使用百度地图API显示地图并绘制路线】
    Axios前后端交互规范
    Python开发工具PyCharm使用教程:自定义 IDE
    Estimation with Bootstrap
    【数据结构Note5】- 树和二叉树(知识点超细大全-涵盖常见算法 排序二叉树 线索二叉树 平衡二叉树 哈夫曼树)
    小谈设计模式(11)—模板方法模式
    springboot vue婚纱摄影师作品展示网站系统javaweb项目
  • 原文地址:https://blog.csdn.net/qjyws/article/details/126811710