1、什么是Window和WindowManager
Window是一个抽象类,表示一个窗口,Android中所有的视图都是通过Window来呈现的,不管是Activity,Dialog,Toast,它们的视图都是附加在Window上的,Window是View的直接管理者
Window的唯一子类是PhoneWindow,WindowManager是外界访问Window的入口。
Window有三种类型,分别是应用Window,子Window,系统Window,应用Window对应一个Activity,子Window不能单独存在,它需要附属在特定的父Window中,比如常见的Dialog,系统Window需要声明权限在能创建的Window,比如Toast和系统状态栏都是系统Window。
Window是分层的,每个Window都有对应的z-ordered,层级大的覆盖在层级小的Window上面,
WindowManager常用有三个方法,即添加View,更新View和删除View,这三个方法定义在ViewManager中,而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);
}
2、Window内部机制
Window是一个抽象的概念,每一个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系,Window并不是实际存在的,它是以View的形式存在,View才是Window存在的实体。
(1)Window的添加过程
WindowManager是一个接口,它的真正实现是WindowManagerImpl类
// WindowManagerImpl.class
@Override
public void addView(View view, ViewGroup.LayoutParams params) {
mGlobal.addView(view, params, mDisplay, mParentWindow);
}
WindowManagerImpl将所有的操作交给了WindowManagerGlobal来实现,WindowManagerGlobal内部有几个重要列表:
private final ArrayList<View> mViews = new ArrayList<>();
private final ArrayList<ViewRootImpl> mRoots = new ArrayList<>();
private final ArrayList<ViewManager.LayoutParams> mParams = new ArrayList<>();
private final ArraySet<View> mDyingViews = new ArraySet<>();
mViews保存了所有的Window对应的View,mRoots保存了所有Window对应的ViewRootImpl,mParams保存了所有WIndow对应的布局参数,mDyingViews保存了那些正在被删除的View对象
// addView 方法
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
然后通过ViewRootImpl的setView方法来更新界面和完成Window的添加过程,View的绘制过程是由ViewRootImpl来完成的,最后Window的添加请求就交给WindowManagerService处理。
(2)Window的删除过程
// WindowManagerImpl.class
@Override
public void removeView(View view) {
mGlobal.removeView(view, false);
}
mGlobal.removeView中首先找到要删除View的索引,然后进行删除
(3)Window的更新过程
// WindowManagerImpl.class
@Override
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
mGlobal.updateViewLayout(view, params);
}
mGlobal.updateViewLayout首先更新View的LayoutParams,接着更新ViewRootImpl的LayoutParams,在ViewRootImpl中会通过scheduleTraversal的方法对View重新布局,包括测量,布局和重绘三大过程。
3、Window的创建过程
(1)Activity的Window创建过程
Activity的启动过程最终会由ActivityThread中的performLaunchActivity()来完成整个启动过程,在这个方法中会创建Activity实例对象,并调用它的attach方法为其关联运行中所依赖的一系列上下文环境变量,一是在attach()方法中会创建PhoneWindow
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
二是创建和初始化DecorView,将布局添加到DecorView的mContentParent中(内容栏),然后回调Activity的onContentChanged方法通知Activity视图已经发生变化
三是将添加到Window中,在Activity.handleResumeActivity中,首先调用Activity的onResume,接着调用Activity的makeVisible,在makeVisiable中,DecorView真正的完成了添加和显示过程,Activity才可以被用户看到。
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes);
mWindowAdded = true;
}
mDecor.setVisiblity(View.VISIBLE);
}
(2)Dialog的Window创建过程
一是创建在Dialog中创建PhoneWindow
二是初始化DecorView并将Dialog的视图添加到DecorView中,通过setContentView
三是在Dialog.show方法中,将DecorView添加到Window中并显示
与Activity的Window创建过程很相似,普通Dialog有一个特殊之处是必须采用Activity的Context。