Window和WindowManager的分析
2016-05-20 23:27
423 查看
Window表示一个窗口的概念 在日常的开发中我们接触的并不多 但是在我们需要在桌面上显示一个类似于悬浮的东西时 就需要使用Window来实现了 Window类只是一个抽象类 它的具体实现是PhoneWindow 创建一个Window是一件很简单的是 只需要由WindowManager即可完成
WindowManager通过IPC调用WindowManagerService Android中的所有视图都是通过Window来呈现的 不论是Activity Dialog Toast 它们的视图都是附加在Window上的 因此Window实际上是View的直接管理者
我们在研究View的分发机制时也了解到 事件是由Window传递给DecorView中的 然后由DecorView传递给我们的View Activity的setContentView方法 也是通过Window实现的
上述代码就在 屏幕的200,300位置放置了一个button控件 而且是Toast类型的
下面来介绍一下Window的一些属性:
详细的介绍可以参考这篇文章 介绍的相当详细:
WindowManager.LayoutParams的各种属性
window的属性都放在WindowManager.LayoutParams中
flags :
用来表示window的显示特性 比如显示的事件的响应情况 焦点的获取情况 是否可以显示在锁屏界面上之类的
type:
用来表示Window的类型 Window有三种类型 应用Window 、子Window 、 还有系统Window
应用Window对应着一个Activity 子Window不能单独存在,必须依附于父容器 例如Dialog就是一个子Window 系统Window需要声明权限才可以 比如Toast和系统状态栏都是系统Window
Window是分层的 每个Window有对应的 z-ordered 属性 层级大的会显示在小的上面 甚至会覆盖
其中应用Window 层级在 1-99 子Window在 1000-1999
系统Window在2000-2999
需要声明权限 :
format:
表示期望的位图格式。。。
softInputMode:
Window的软键盘的使用模式
如果我们在Window上操控控件只需要调用它的addView removeView updateViewLayout三个方法即可 很简单
1.检查参数是否合法 如果是子Window还要调整一些布局参数
2.创建ViewRootImpl 并将View添加到WMG的列表中
3.通过ViewRootImp来更新界面完成Window的添加过程
删除的过程也类似 先findViewLocked(view,true)找到要移除的view的位置 找到后调用WMG的removeViewLocked方法 把view移除就可以 当然也是IPC调用 移除的。。 在移除的过程中还会调用我们以前提到的dispatchDetachedFromWindow接口
更新也类似就不详细解析了
要了解这个过程就要先了解Activity的启动过程 比较复杂 最终会由ActivityThread中的performLaunchActivity()来完成整个启动过程 这个方法内部会通过类加载器创建Activity对象 并通过attach为其关联运行过程中所依赖的上下文环境
在attach方法中 系统会创建 Activity所属的Window对象 并为其设置回调接口
再看Activity的setContentView方法
是通过window的这个方法进行的
再看phoneWindow的setContentView方法
这个方法大致分为这几步 :
1.如果没有DecorView 创建它
2.将View添加到DecorView的mContentParent中
3.回调Activity的onContentChanged方法 通知 改变了 之后就完成了 Activity的Window的创建 。。。
2.Dialog的Window创建过程
和Activity的类似 分为以下几个步骤
这样就显示了一个Dialog 所以如果要设置Dialog的布局的信息 只需要设置getWindow的一些属性就可以了。。。
上面两种WIndow的使用其实大致部分都是这个样子的 :
首先要先创建一个WIndow 也就是 new PhoneWindow()
之后给window设置一系列属性 位置 回调之类的
然后就是向window中设置布局了 也就是
mWindow.setContentView方法会执行 这个方法内部会创建并加载一个DecorView(顶级View) 之后会把xml中的布局加载到DecorView中
这时候其实window已经创建好了 它有回调 有 布局 但是还有一点 它并没有加载到屏幕上 所以这时候就需要和WindowManager联系了
使用mWindowManager.addView(mDecor,l) 函数让window显示在屏幕上即可 l参数是window的属性 就是这个参数使WM和window关联起来了 这样就完成了 一个窗口的显示
WindowManager通过IPC调用WindowManagerService Android中的所有视图都是通过Window来呈现的 不论是Activity Dialog Toast 它们的视图都是附加在Window上的 因此Window实际上是View的直接管理者
我们在研究View的分发机制时也了解到 事件是由Window传递给DecorView中的 然后由DecorView传递给我们的View Activity的setContentView方法 也是通过Window实现的
Window的简单使用介绍
下面我们就来在Window上简单添加一个控件:Button bt = new Button(this); bt.setText("哈哈哈哈"); WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.WRAP_CONTENT,0,0, PixelFormat.TRANSPARENT); params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; params.type = WindowManager.LayoutParams.TYPE_TOAST; params.gravity = Gravity.CENTER; params.x = 200; params.y = 300; wm.addView(bt,params);
上述代码就在 屏幕的200,300位置放置了一个button控件 而且是Toast类型的
下面来介绍一下Window的一些属性:
详细的介绍可以参考这篇文章 介绍的相当详细:
WindowManager.LayoutParams的各种属性
window的属性都放在WindowManager.LayoutParams中
flags :
用来表示window的显示特性 比如显示的事件的响应情况 焦点的获取情况 是否可以显示在锁屏界面上之类的
type:
用来表示Window的类型 Window有三种类型 应用Window 、子Window 、 还有系统Window
应用Window对应着一个Activity 子Window不能单独存在,必须依附于父容器 例如Dialog就是一个子Window 系统Window需要声明权限才可以 比如Toast和系统状态栏都是系统Window
Window是分层的 每个Window有对应的 z-ordered 属性 层级大的会显示在小的上面 甚至会覆盖
其中应用Window 层级在 1-99 子Window在 1000-1999
系统Window在2000-2999
需要声明权限 :
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"></uses-permission>
format:
表示期望的位图格式。。。
softInputMode:
Window的软键盘的使用模式
如果我们在Window上操控控件只需要调用它的addView removeView updateViewLayout三个方法即可 很简单
Window的内部机制
Window的操作是通过WindowManager进行的 而WindowManager的实现类WindowManagerImpl是通过 WindowManagerGlobal相应的方法执行的 这是典型的桥接模式 将所有的操作都交给WindowManagerGlobal(简称WMG)进行 WMG的addView方法主要分为以下几个步骤:1.检查参数是否合法 如果是子Window还要调整一些布局参数
2.创建ViewRootImpl 并将View添加到WMG的列表中
//WMG中的一些列表 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>(); private final ArraySet<View> mDyingViews = new ArraySet<View>(); //向列表中添加的过程 root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); mViews.add(view); mRoots.add(root); mParams.add(wparams);
3.通过ViewRootImp来更新界面完成Window的添加过程
删除的过程也类似 先findViewLocked(view,true)找到要移除的view的位置 找到后调用WMG的removeViewLocked方法 把view移除就可以 当然也是IPC调用 移除的。。 在移除的过程中还会调用我们以前提到的dispatchDetachedFromWindow接口
更新也类似就不详细解析了
Window的创建过程
1.Activity的Window创建过程要了解这个过程就要先了解Activity的启动过程 比较复杂 最终会由ActivityThread中的performLaunchActivity()来完成整个启动过程 这个方法内部会通过类加载器创建Activity对象 并通过attach为其关联运行过程中所依赖的上下文环境
在attach方法中 系统会创建 Activity所属的Window对象 并为其设置回调接口
mWindow = new PhoneWindow(this); //创建 window mWindow.setCallback(this); //设置回调 mWindow.setOnWindowDismissedCallback(this); mWindow.getLayoutInflater().setPrivateFactory(this); if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { mWindow.setSoftInputMode(info.softInputMode);//设置键盘模式 } if (info.uiOptions != 0) { mWindow.setUiOptions(info.uiOptions); }
再看Activity的setContentView方法
public void setContentView(@LayoutRes int layoutResID) { getWindow().setContentView(layoutResID); initWindowDecorActionBar(); }
是通过window的这个方法进行的
再看phoneWindow的setContentView方法
这个方法大致分为这几步 :
1.如果没有DecorView 创建它
根据android.R.id.content就可以获取contentView的id 然后加载布局即可
2.将View添加到DecorView的mContentParent中
3.回调Activity的onContentChanged方法 通知 改变了 之后就完成了 Activity的Window的创建 。。。
2.Dialog的Window创建过程
和Activity的类似 分为以下几个步骤
1.创建Window
Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) { if (createContextThemeWrapper) { if (themeResId == 0) { final TypedValue outValue = new TypedValue(); context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true); themeResId = outValue.resourceId; } 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); }
2.初始化DecorView并将Dialog视图添加到DecorView中 主要是调用window的setContentView方法 和Activity的过程差不多 可参考 3.将DecorView添加到WIndow中并显示
mWindowManager.addView(mDecor, l); mShowing = true;
这样就显示了一个Dialog 所以如果要设置Dialog的布局的信息 只需要设置getWindow的一些属性就可以了。。。
上面两种WIndow的使用其实大致部分都是这个样子的 :
首先要先创建一个WIndow 也就是 new PhoneWindow()
之后给window设置一系列属性 位置 回调之类的
然后就是向window中设置布局了 也就是
mWindow.setContentView方法会执行 这个方法内部会创建并加载一个DecorView(顶级View) 之后会把xml中的布局加载到DecorView中
这时候其实window已经创建好了 它有回调 有 布局 但是还有一点 它并没有加载到屏幕上 所以这时候就需要和WindowManager联系了
使用mWindowManager.addView(mDecor,l) 函数让window显示在屏幕上即可 l参数是window的属性 就是这个参数使WM和window关联起来了 这样就完成了 一个窗口的显示
相关文章推荐
- PAT 1025 反转链表
- android中事件分发机制
- 安装wampwerver时图标一直是橙色怎么解决
- POJ 1011 / UVA 307 Sticks
- jvisualvm监控Spark作业
- Radware LP配置步骤
- POJ 1011 / UVA 307 Sticks
- 使用Servlet上传文件
- Java 引用分类:StrongReference、SoftReference、WeakReference、PhantomReference
- 7——PHP选择结构
- css样式命名导致样式“变异”的问题
- Android官方文档之Creating a Content Provider
- Cell选中问题 以及 URL中文编码
- 基于calcite为CSV文件包装SQL接口
- 设备无法启动处理步骤
- 数组变树
- POJ 3680 Intervals
- LaTeX技巧004:给文字添加下划线、波浪线等样式
- linux下配置多个tomcat
- 更换思科交换机主控引擎操作步骤