读书笔记-Android开发艺术探索-第8章-理解Window和WindowManager

来源:互联网 发布:mysql中timestampdiff 编辑:程序博客网 时间:2024/06/05 17:01

1.Window和WindowManager

Window是一个抽象类,它的具体实现是PhoneWindow,通过WindowManager即可创建一个Window。WindowManager是外界访问Window的入口,Window的具体实现位于WindowManagerService中,WindowManager和WindowManagerService的交互是一个IPC过程。Android中所有视图都是通过Window来呈现的,不管是Activity,Dialog还是Toast,它们的视图实际上都是附加在Window上的,因此Window实际是View的直接管理者。

public interface ViewManager {    public abstract void addView (View view, ViewGroup.LayoutParams params);    public abstract void removeView (View view);    public abstract void updateViewLayout (View view, ViewGroup.LayoutParams params);}public interface WindowManager implements ViewManager {    public static class BadTokenException extends RuntimeException {}    public static class InvalidDisplayException extends RuntimeException {}    public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {        LayoutParams(){}        LayoutParams(int _type){}        LayoutParams(int _type, int _flags){}        LayoutParams(int _type, int _flags, int _format){}        LayoutParams(int w, int h, int _type, int _flags, int _format){}        LayoutParams(int w, int h, int xpos, int ypos, int _type, int _flags, int _format){}        LayoutParams(Parcel in){}    }    public abstract Display getDefaultDisplay ();    public abstract void removeViewImmediate (View view);}

Flags参数:表示Window的属性,它有很多选项,通过这些选项可以控制Window的显示特性。
Type参数:表示Window的类型,Window有三种类型,分别是Application windows(应用Window),Sub-windows(子Window),System windows(系统Window)。应用类Window对应着一个Activity;子Window不能单独存在,它需要附属在特定的父Window之中,比如常见的一些Dialog就是一个子Window;系统Window是需要声明权限才能创建的Window,比如Toast和系统状态栏这些都是系统Window。

Window是分层的,每个Window都有对应的z-ordered,层级大的会覆盖在层级小的Window的上面,这和HTML中的z-index的概念是完全一致的。在三类Window中,应用Window的层级范围是1-99,子Window的层级范围是1000-1999,系统Window的层级范围是2000-2999,这些层级范围对应着WindowManager.LayoutParams的type参数。如果想要Window位于所有Window的最顶层,那么采用较大的层级即可。

获取WindowManager:

Context.getSystemService(Context.WINDOW_SERVICE);

WindowManager所提供的方法很简单,常用的只有三个方法,即addView(),updateViewLayout()和removeView(),这三个方法定义在ViewManager中,而WindowManager继承了ViewManager。

2.Window的内部机制

Window是一个抽象的概念,每一个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系,因此Window并不是实际存在的,它是以View的形式存在。

Window的添加/删除/更新过程需要通过WindowManager来实现,WindowManager是一个接口,它的真正实现是WindowManagerImpl类。
WindowManagerImpl源码
WindowManagerImpl并没有直接实现Window的三大操作,而是全部交给了WindowManagerGlobal来处理。
WindowManagerGlobal源码
WindowManagerImpl这种工作模式是典型的桥接模式,将所有的操作全部委托给WindowManagerGlobal来实现。

3.Window的创建过程

1.Activity的Window创建过程

1.如果没有DecorView,那么就创建它。
DecorView是一个FrameLayout,是Activity中的顶级View,一般来说它的内部包含标题栏和内部栏,但这个会随着主题的变换而发生改变。DecorView的创建过程由installDecor方法来完成,在方法内部会通过generateDecor方法来直接创建DecorView,这个时候DecorView还只是一个空白的FrameLayout:

protected DecorView generateDecor() {    return new DecorView(getContext(), -1);}

为了初始化DecorView的结构,PhoneWindow还需要通过generateLayout方法来加载具体的布局文件到DecorView中,具体的布局文件和系统版本以及主题有关,这个过程如下所示:

View in = mLayoutInflater.inflate(layoutResource, null);decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));mContentRoot = (ViewGroup) in;ViewGroup mContentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);

2.将View添加到DecorView的mContentParent中。
Activity的setContentView方法添加的布局文件被添加到DecorView的mContentParent中。

public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;

3.回调Activity的onContentChanged方法通知Activity视图已经发生改变。
由于Activity实现了Window的Callback接口,这里表示Activity的布局文件已经被添加到了DecorView的mContentParent中了,于是需要通知Activity,使其可以做相应的处理。Activity的onContentChanged方法是个空实现,可以在子Activity中处理这个回调:

final Callback cb = getCallback();if (cb != null && !isDestroyed) {    cb.onContentChanged();}

2.Dialog的Window创建过程

1.创建Window。
2.初始化DecorView并将Dialog的视图添加到DecorView中。
3.将DecorView添加到Window中并显示。

普通的Dialog有一个特殊之处,那就是必须采用Activity的Context,如果采用Application的Context,那么就会报错,这是因为没有应用token所导致的。

3.Toast的Window创建过程

Toast和Dialog不同,它的工作过程稍显复杂。首先Toast也是基于Window来实现的,但是由于Toast具有定时取消这一功能,所以系统采用了Handler。在Toast的内部有两类IPC过程,第一类是Toast访问NotificationManagerService,第二类是NotificationManagerService回调Toast里的TN接口。

Toast属于系统Window,它内部的视图由两种方式指定,一种是系统默认的样式,另一种是通过setView方法来指定一个自定义View。

0 0