http://blog.csdn.net/yanbober/article/details/46361191
http://blog.csdn.net/yanbober/article/details/45970721
https://mp.weixin.qq.com/s/zNXi6g7AAWz3lzxocXwZyg
http://blog.csdn.net/yhaolpz/article/details/68936932
Window:是一个抽象类,提供了绘制窗口的一组通用API。
PhoneWindow:是Window的具体继承实现类。而且该类内部包含了一个DecorView对象。每个Activity都有。
DecorView:是PhoneWindow的内部类,是FrameLayout的子类,是对FrameLayout进行功能的修饰(所以叫DecorXXX),是所有应用窗口的根View。
WindowManagerGlobal:他是个单例对象,这个单例每个应用程序只有唯一的一个。它维护了本应用程序内所有Window的DecorView,以及与每一个DecorView对应关联的ViewRootImpl。WindowManager只是一个代理,实际的管理功能是通过WindowManagerGlobal实现的
ViewRootImpl:ViewRootImpl不是一个View,而是负责管理视图的,它能够和系统的WindowManagerService进行交互,并且管理着DecorView的绘制和窗口状态,它是视图树绘制的起点。
Window是个抽象概念:每一个Window对应着一个View和ViewRootImpl,Window通过ViewRootImpl来和View建立联系,View是Window存在的实体,只能通过WindowManager来访问Window。
WindowManager的实现是WindowManagerImpl其再委托给WindowManagerGlobal来对Window进行操作,其中有四个List分别储存对应的View、ViewRootImpl、WindowManger.LayoutParams和正在被删除的View
Window的实体是存在于远端的WindowMangerService中,所以增删改Window在本端是修改上面的几个List然后通过ViewRootImpl重绘View,通过WindowSession(每个应用一个)在远端修改Window。
Activity创建Window:Activity会在attach()中创建Window并设置其回调(onAttachedToWindow()、dispatchTouchEvent()),Activity的Window是由Policy类创建PhoneWindow实现的。然后通过Activity#setContentView()调用PhoneWindow的setContentView。
1. 创建一个DecorView的对象mDecor,该mDecor对象将作为整个应用窗口的根视图。
2. 依据Feature等style theme创建不同的窗口修饰布局文件,并且通过findViewById获取Activity布局文件该存放的地方(窗口修饰布局文件中id为content的FrameLayout)。
3. 将Activity的布局文件添加至id为content的FrameLayout内。
4. 当setContentView设置显示OK以后会回调Activity的onContentChanged方法。Activity的各种View的findViewById()方法等都可以放到该方法中,系统会帮忙回调。
在setContentView过程中,我们最后调用了LayoutInflator来生成对应的View。
1. inflate(xmlId, null); 只创建temp的View,然后直接返回temp。
2. inflate(xmlId, parent); 创建temp的View,然后执行root.addView(temp,params);最后返回root。
3. inflate(xmlId, parent, false); 创建temp的View,然后执行temp.setLayoutParams(params);然后再返回temp。
4. inflate(xmlId, parent, true); 创建temp的View,然后执行root.addView(temp,params);最后返回root。
5. inflate(xmlId, null, false); 只创建temp的View,然后直接返回temp。
6. inflate(xmlId, null, true); 只创建temp的View,然后直接返回temp。
需要注意:
1、View的layout_width和layout_height设置的是View在ViewGroup即父布局布局中的大小的
2、因此,如果没有父布局parent,则我们设置的子布局就正确处理
Context的WindowManager对每个APP来说是一个全局单例的,而Activity的WindowManager是每个Activity都会新创建一个的(其实你从上面分析的两个实例化WindowManagerImpl的构造函数参数传递就可以看出来,Activity中Window的WindowManager成员在构造实例化时传入给WindowManagerImpl中mParentWindow成员的是当前Window对象,而ContextImpl的static块中单例实例化WindowManagerImpl时传入给WindowManagerImpl中mParentWindow成员的是null值)。
Activity的WindowManager当Activity结束时WindowManager就无效了,而application的WindowManager在app退出时都一直存在。
Activity实际并不会去控制UI视图,它主要是去控制生命周期和处理事件,真正的视图控制是Window。
WindowManager 是一个接口,它的真正实现是WindowManagerImpl 类WindowManagerImpl 并没有直接实现 Window 的三大操作(addView,updateViewLayout,removeView),而是交给了 WindowManagerGlobal 来处理。
执行过程:
在Dialog中我们接收到activity传入的context,然后去获取windowManager,去创建window然后再与与windowMnager关联,这样我们dialog就可以在activity的基础上进行显示。
Show()中通过获取window的decorView我们添加相应的布局就完成了。
Dismiss()中将decor从window中移除,并释放,然后将window展示关闭就完成了。
Dialog的实质无非也是使用WindowManager的addView、updateViewLayout、removeView进行一些操作展示。
PopWindow的实质无非也是使用WindowManager的addView、updateViewLayout、removeView进行一些操作展示。与Dialog不同的地方是没有新new Window而已(也就没法设置callback,无法消费事件,也就是前面说的PopupWindow弹出后可以继续与依赖的Activity进行交互的原因)。
在dialog中,我们新建了一个window,window对象可以添加监听等方法,新window就覆盖在了原来window之上。而popupwindow是直接通过windowManager来添加view,也就是在当前的window层做了相应的操作。
这里的windowmManager是application产生的。也就用了windowMManager的addView方法和removeView来做的相应的处理。
所以:
在使用Toast时context参数尽量使用getApplicationContext(),可以有效的防止静态引用导致的内存泄漏。