Android之Window与WIndowManager

内存溢出
• 阅读 3706

基本概念

  • Window、PhoneWindow

顶层窗口样式和行为的抽象类, 概括了Android窗口的基本属性和基本功能。该类实例的getDecorView()方法返回的DecorView被用来作为顶层视图添加到WM中。

创建时机: ActivityThread.handleLaunchActivity ---> ActivityThread.performLaunchActivity --->Activity.attach

  • WindowManager、WindowManagerImpl、WindowManagerGlobal

WindowManager与一个特定的Display相关联

  • WindowManagerService

对系统中的所有窗口进行管理。WindowManager是运行在Application process中的, WindowManagerService是在system_server进程中运行, 两者的通信是通过中间的会话层IWindowSession来进行的。

添加一个根View到WindowManager中

{
    final WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
    WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                wm.getDefaultDisplay().getWidth(),wm.getDefaultDisplay().getHeight());
    lp.type = WindowManager.LayoutParams.TYPE_APPLICATION;
    lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
    lp.format = PixelFormat.TRANSLUCENT;
    wm.addView(maskView, lp);
}

相关类简化结构

public class PhoneWindow extends Window{
    private DecorView mDecor;
}

public interface ViewManager{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

public interface WindowManager extends ViewManager {
    public static class LayoutParams extends ViewGroup.LayoutParams{
        //X position for this window
        public int x;
        public int y;
        public int type;
        public int flags;
    }
}

public final class WindowManagerImpl implements WindowManager {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    private final Display mDisplay;
    
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }
}


public final class WindowManagerGlobal {
    //表示View树的根节点
    private final ArrayList<View> mViews = new ArrayList<View>();
    //表示ViewRootImpl,一个根view对应一个ViewRootImpl
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    //表示根view的WindowManager.LayoutParams
    private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<WindowManager.LayoutParams>();
            
    public void addView(View view, ViewGroup.LayoutParams params,Display display, Window parentWindow) {

         final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
         ...
         ViewRootImpl root = new ViewRootImpl(view.getContext(), display);
         view.setLayoutParams(wparams);
        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);
        ...
        //通过ViewRootImpl来更新界面并完成Window的添加过程
        root.setView(view, wparams, panelParentView);
    }
}


public final class ViewRootImpl implements ViewParent{
    
   public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
           //1、完成异步刷新请求,重绘界面
           requestLayout();
           ...
           //2、通过WindowSession最终完成window的添加过程, WindowSession内部通过WindowManagerService来实现Window的添加
           int res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
   }
}

Window的创建过程

Activity对应的PhoneWindow创建过程及添加时机

首先看下ActivityThead中的两个重要的方法:

       performLaunchActivity( );
       handleResumeActivity( );

创建时机:

在performLaunchActivity中,会调用activity.attach方法建立一个window。

Activity的View附属到Window上:setContentView()

添加时机:

在handleResumeActivity方法中启动activity的时候,首先会调用Activity的onResume方法,>接着调用Activity的makeVisible方法,在该方法中将主窗口加入到WindowManager中

代码如下:

void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        wm.addView(mDecor, getWindow().getAttributes());//实际上是把主窗口的顶级view加入到WindowMangaer
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
}

Dialog的Window创建过程

  1. 创建窗口:构造函数中

  2. 初始化DecorView并将Dialog的View添加到DecorView中:setContentView()

  3. 将DecorView添加到Window中并显示:show()

public class Dialog implements DialogInterface, ... {
    
    Dialog(Context context,int themeResId, boolean createContextThemeWrapper) {
        if (createContextThemeWrapper) {
            mContext = new ContextThemeWrapper(context, themeResId);
        } else {
            mContext = context;
        }
    
        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    
        final Window w = new PhoneWindow(mContext);
        mWindow = w;
        w.setCallback(this);
        w.setOnWindowDismissedCallback(this);
        w.setWindowManager(mWindowManager, null, null);
        w.setGravity(Gravity.CENTER);
    
        mListenersHandler = new ListenersHandler(this);
    }
    
    public void setContentView(@LayoutRes int layoutResID) {
        mWindow.setContentView(layoutResID);
    }
    public void show() {
        mDecor = mWindow.getDecorView();
        mWindowManager.addView(mDecor, l);
    }
}

Window添加过程

实际上是根视图的添加过程,在WindowManager层已经没有Window的概念,Window的概念存在于UI层,是对于Activity、Dialog、Toast等而言的。

  1. WindowManager.addView():调用2

  2. WindowManagerGlobal.addView():

    1. 创建ViewRootImpl

    2. 调用3

  3. ViewRootImpl.setView():

    1. requestLayout()

    2. mWindowSession.addToDisplay

总结

通过WindowManager.addView(View view, ViewGroup.LayoutParams params)可以看到:Window是一个抽象的概念,它以View的形式存在(不同于PhoneWindow,该Window是顶层View样式和行为的抽象类),但同时Activity、Dialog、Toast等又必须通过Window与View建立关联。根View一一对应ViewRootImpl,WindowManager内部通过ViewRootImpl进行Window(即根View)的添加、删除、更新,而ViewRootImpl内部通过WindowSession和WindowManagerService通信,最终WindowManagerService完成根View的添加、删除、更新。

Android中的Activity、Dialog、Toast、PopupWindow、菜单、状态栏都是通过Window来实现对应的View的,视图都对应一个Window。

从WmS的角度看,一个窗口并不是Window类,而是一个View类

参考:
http://blog.csdn.net/geloin/article/details/42779025

点赞
收藏
评论区
推荐文章
Souleigh ✨ Souleigh ✨
4年前
JavaScript - 关于 var、let、const 的区别使用
一、var在ES5中,顶层对象的属性和全局变量是等价的,用var声明的变量既是全局变量,也是顶层变量注意:顶层对象,在浏览器环境指的是window对象,在Node指的是global对象var a  10;console.log(window.a) // 10使用var声明的变量存在变量提升的情况console.log(a) // undefine
Karen110 Karen110
4年前
一篇文章带你了解JavaScript弹出框
在JavaScript中,可以创建对话框或弹出窗口来与用户进行交互。JavaScript具有三种不同类型的弹出框:警告框,确认框和提示框。一、警告框警告框是最简单的弹出框。它使可以向用户显示一条短消息。还包括“确定”按钮,用户必须单击此“确定”按钮才能继续。window.alert()语法:window.alert("msg")方法可以在没有窗口的前缀被写
刘望舒 刘望舒
4年前
Android解析WindowManager(三)Window的添加过程
Android框架层Android系统服务WindowManagercategories:Android框架层本文首发于微信公众号「刘望舒」前言在此前的系列文章中我们学习了WindowManager体系和Window的属性,这一篇我们接着来讲Window的添加过程。建议阅读此篇文章前先阅读本系列的前两篇文章。<!more1.概述WindowMana
刘望舒 刘望舒
4年前
Android解析WindowManagerService(二)WMS的重要成员和Window的添加过程
Android框架层Android系统服务WindowManagerServiceAndroid框架层本文首发于微信公众号「后厂技术官」<!more前言在本系列的上一篇文章中,我们学习了WMS的诞生,WMS被创建后,它的重要的成员有哪些?Window添加过程的WMS部分做了什么呢?这篇文章会给你解答。1.WMS的重要成员所谓WMS的重要成员是指WM
刘望舒 刘望舒
4年前
Android解析WindowManager(二)Window的属性
Android框架层Android系统服务WindowManagercategories:Android框架层本文首发于微信公众号「刘望舒」前言在上一篇文章我们学习了WindowManager体系,了解了Window和WindowManager之间的关系,这一篇我们接着来学习Window的属性。<!more1.概述上一篇文章中我们讲过了Window
九路 九路
3年前
Android窗口管理框架:Android应用视图的管理者Window
Android窗口管理框架:Android应用视图的管理者Window文章目录一窗口类型二窗口参数三窗口模式四窗口回调五窗口实现从这篇文章开始,我们来分析和Window以及WindowManager相关的内容,Abstractbaseclassforatoplevelwindowlookandbehaviorpolic
刘望舒 刘望舒
4年前
Android解析WindowManagerService(三)Window的删除过程
Android框架层Android系统服务WindowManagerServiceAndroid框架层本文首发于微信公众号「后厂技术官」前言在本系列文章中,我提到过:Window的操作分为两大部分,一部分是WindowManager处理部分,另一部分是WMS处理部分,Window的删除过程也不例外,本篇文章会介绍Window的删除过程,包括了两大处理
Wesley13 Wesley13
3年前
Android动态Java代码调整window大小
Android调整window大小举一个例子,设置当前的APP所需要的屏幕高度为设备高度的一半:WindowwindowgetActivity().getWindow();WindowManager.LayoutParamswindowLayoutParamswindow.ge
Stella981 Stella981
3年前
Android项目如果要将自己写的类写成要单独打成jar包?
<p<h需求条件:</h1</p<p自己没做过android,公司android开发临时有事请假了,老板说让我研究研究,反正都是java。我心里“XXXXXX”。这篇用来自己做个记录,老手请略过,Android新手临时替岗而已。前提是自己的类中含有用到Android的类库</p<p<h解决方案:</h1</p这module新建的时候
Stella981 Stella981
3年前
Android自动化性能收集
<h1Android自动化性能收集</h1<pAndroid功能测试自动化框架较多,UIAutomator,Robotium,Appium等。Case执行过程中,可能希望收集手机的性能指标,包括内存、cpu、流量等。使用javashellbat简单实现了android手机性能收集。</p<h2简述</h2<p过程很简单:</p
Stella981 Stella981
3年前
JavaScriptLocation对象
简单介绍:说明:location对象是window属性,也是document属性所以它提供了与当前窗口中加载的文档有关信息和导航功能,属性名称属性说明hash返回url中的hash(后跟零或多个字符),如果不包含散列则返回空字符串host返回服务器名称和端口号hostname返回不带端口号的服务器名称href返
内存溢出
内存溢出
Lv1
此夜曲中闻折柳,何人不起故园情。
文章
4
粉丝
0
获赞
0