activity,view,window,windowmanager代码阅读总结及相互关系
ActivityThread类:performLaunchActivity函数:
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstance,
r.lastNonConfigurationChildInstances, config);
Activity类中的attach方法:
//创建新的window,与Activity相关联,在android2.2以下以及2.2版本返回的是MidWindow,但是sdk类库中包含PhoneWindow,2.2版本以上删除了MidWindow类,使用的是PhoneWindow。这两个类都是继承自Window,因此可以认为两个类是相同的。
mWindow = PolicyManager.makeNewWindow(this);
***省略操作
//创建一个与window相关的WindowManager,由于Activity类中使用的setManager方法传递的WindowManager参数为null,因此在Window类中使用WindowManager变量是同一个对象。
mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
//从Window类的setWindowManager方法可以知道Activity的WindowManager是一个//LocalWindowManager
mWindowManager = mWindow.getWindowManager();
Window类的setWindowManager方法:
public void setWindowManager(WindowManager wm, IBinder appToken,
String appName) {
mAppToken = appToken;
mAppName = appName;
if (wm == null) {
wm = WindowManagerImpl.getDefault();
}
//使用WindowManager的变量来创建LocalWindowManager
mWindowManager = new LocalWindowManager(wm);
}
private class LocalWindowManager implements WindowManager {
LocalWindowManager(WindowManager wm) {
mWindowManager = wm;
mDefaultDisplay = mContext.getResources().getDefaultDisplay(
mWindowManager.getDefaultDisplay());
}
public final void addView(View view, ViewGroup.LayoutParams params) {
****
View decor = peekDecorView();
****
mWindowManager.addView(***);
}
*********
}
Window类的peekDecorView()方法,获取当前的Decor View
public abstract View peekDecorView();
获取顶层窗口decor view(包含了标准窗口)可以作为window添加到window manager。
public abstract View getDecorView();
这两个函数在PhoneWindow中被实现。
在WindowImpl类中:
public static WindowManagerImpl getDefault() {
return mWindowManager;
}
private static WindowManagerImpl mWindowManager = new WindowManagerImpl();
因此通过getDefault()方法返回的WindowManagerImpl是同一个对象。
addView方法,将View保存到数组中,并设置View的root信息:
private void addView(View view, ViewGroup.LayoutParams params, boolean nest) {
****
ViewRoot root;
View panelParentView = null;
****
root = new ViewRoot(view.getContext());
****
mViews[index] = view;
mRoots[index] = root;
mParams[index] = wparams;
****
root.setView(view, wparams, panelParentView);
}
PhoneWindow继承了Window,实现了Window中的所有虚函数。
// This is the top-level view of the window, containing the window decor.
// 窗口的顶层View
private DecorView mDecor;
// This is the view in which the window contents are placed. It is either
// mDecor itself, or a child of mDecor where the contents go.
// 放置窗口内容的View,或者是mDecor或者mDecor的子View用来放置内容,对应于ID为com.android.internal.R.id.content的FramLayout。
private ViewGroup mContentParent;
//设置view
@Override
public void setContentView(int layoutResID) {
//判断contentParent是否为null,如果为null则需要installDecor,否则需要清空原来已经填充的view
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
//inflate xml并设置父view为mContentParent,初次设置view
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null) {
cb.onContentChanged();
}
}
@Override
public void setContentView(View view) {
setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
//判断contentParent是否为null,如果为null则需要installDecor,否则需要清空原来已经填充的view
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
//给mContentParent增加view
mContentParent.addView(view, params);
final Callback cb = getCallback();
if (cb != null) {
cb.onContentChanged();
}
}
private void installDecor() {
//生成mDecor
if (mDecor == null) {
mDecor = generateDecor();
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
}
if (mContentParent == null) {
//生成mContentParent
mContentParent = generateLayout(mDecor);
mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
****设置标题栏信息
}
}
//使用DecorView作为参数创建mContentParent,并设置mDecor将mContentParent添加为子view
//mContentParent对应于id为content的framlayout可以参考代码中提供的window布局文件,以及使用的findViewById函数的参数。
protected ViewGroup generateLayout(DecorView decor) {
设置flags
WindowManager.LayoutParams params = getAttributes();
设置params
// Inflate the window decor.
int layoutResource;
int features = getLocalFeatures();
获取整个屏幕对应的layout资源id
mDecor.startChanging();
//根据使用的资源不同,显示出来的布局也不同,可以参考sdk下的platforms/android-*/data/res/layout/screen*.xml或dialog*.xml
View in = mLayoutInflater.inflate(layoutResource, null);
//将整个屏幕对应的view作为decor子view,并设置布局参数为铺满整个屏幕(match_parent)
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
//找到id为content的framlayout,由于使用的资源不同,所以content不一定为mDecor的直接子View。使用的findViewById是mDecor的方法,
//由于已经将屏幕View加为mDecor的子View,因此mContentParent也是mDecor的子View
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
设置mDecor的背景和标题
mDecor.finishChanging();
return contentParent;
}
//从本质上来讲Decor为一个FramLayout
private final class DecorView extends FrameLayout {
***省略各种操作
}
Activity在onCreate之前调用attach方法,在attach方法中会创建window对象。window对象创建时并没有创建 Decor对象对象。用户在Activity中调用setContentView,然后调用window的setContentView,这时会检查 DecorView是否存在,如果不存在则创建DecorView对象,然后把用户自己的View 添加到DecorView中。
在ActivityThread函数中:
ActivityThread.java中调用wm.addView(decor, l);把它加入到window manager proxy的mViews中,同时为这个decor view创建一个ViewRoot,ViewRoot负责协调decor view与window manager直接绘图、事件处理。
ViewRoot中有IWindowSession和IWindow用来和window manger打交道和接收window manager传过来的消息,消息传过来后ViewRoot分发给decor view,再由decor view进行分发
windowManager创建和使用流程:
创建:
1、Activity的attach方法中:
mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
2、Window的setWindowManager方法,会返回一个LocalWindowManager对象:
if (wm == null) {
//调用WindowManagerImpl的getDefault方法
wm = WindowManagerImpl.getDefault();
}
//使用WindowManager的变量来创建LocalWindowManager
mWindowManager = new LocalWindowManager(wm);
3、WindowManagerImpl的getDefault方法:
public static WindowManagerImpl getDefault() {
return mWindowManager;
}
mWindowManager生成方法,在WIndowManageImpl类中:
private static WindowManagerImpl mWindowManager = new WindowManagerImpl();
使用:
1、 在Activity中生成
2、 ActivityThread类的handleResumeActivity方法中:
ActivityRecord r = performResumeActivity(token, clearHide);
if (r != null) {
final Activity a = r.activity;
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
//只有在此时才创建一个新的WindowManager
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
//将decor添加到WindowManager中,具体的wm为WindowManagerImpl //在wm的addView方法中将ViewRoot和WindowManager关联起来
wm.addView(decor, l);
}
}
}
3、 WindowManagerImpl类的addView方法,windowManager通过数组来建立View,ViewRoot之间的关联:
ViewRoot root;
//使用view来创建ViewRoot
root = new ViewRoot(view.getContext());
root.mAddNesting = 1;
//使用索引将view和ViewRoot关联起来
mViews[index] = view;
mRoots[index] = root;
mParams[index] = wparams;
//设置root的view,并设置view的parent为root
root.setView(view, wparams, panelParentView);
总结Activity,View,window,DecorView的关系如下:
android中真正展示给用户的是window和view,activity在android中所的作用主要是处理一些逻辑问题,比如生命周期的管理、建立窗口等。在android中,窗口的管理还是比较重要的一块,因为他直接负责把内容展示给用户,并和用户进行交互。响应用户的输入等。
View是真正显示的矩形区域,DecorView是顶层View,也就是主View。
相互之间的关系可以理解为一个Activity包含了一个Window,这个Window其实是一个PhoneWindow,在PhoneWindow中包含了DecorView,变量名称为mDecor,mDecor有一个子View,这个子View的布局方式根据设定的主题来确定,在这个子View的xml布局中包含了一个FrameLayout元素,这个FrameLayout元素的id为content,这个content对应于PhoneWindow中的mContentParent变量,用户自定义的布局作为mContentParent的子View存在,一般情况下mContentParnet只有一个子View,如果在Activity调用addView方式实际上是给PhoneWindow中的mContentParent添加子View,由于mContentParent是一个FrameLayout,因此新的子view会覆盖通过setContentView添加的子view。
仅通过setContentView添加子View类View层次与下图类似:
通过addView方式给Activity添加子view层次图如下所示,右下角两个LinearLayout为用户自定义的布局。
ViewRoot作用:是View和WindowManager之间的桥梁,用于两者之间的协议通讯。
Android 的窗口管理是基于 C/S 模式的,客户端就是应用程序,服务端 就是 Window Manager服务。如下图:
public static IWindowSession getWindowSession(Looper mainLooper) {
InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
//获取回话Session,ViewRoot和Window manager通信,
sWindowSession = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"))
.openSession(imm.getClient(), imm.getInputContext());
return sWindowSession;
}
}
Activity和Window manager之间的通讯:
Activity 建立一个主窗口之后,在将主窗口添加到 Window Manager 时,首先要建立 Window Manager的代理对象,并打开一个Session(session:会话;该session由上面函数中的第二行代码实现,实现 IWindowSession AIDL 接口),并维持该会话(Activity 将通过该会话与 Window Manager 建立联系,这个Session 是C/S 体系的基础)。Client 通过这个Session 将 window 加入到 Window Manager 中。
一个完整的窗口概念包含了 View,ViewRoot,Window Manager Service,Window,Decor View,IWindow,ISession,WindowState。他们之间的关系如下:
Client 端的 Activity 通过 IWindowSession 会话与Window Manager Service 建立对话,而 Window Manager Service 通过 IWindow 接口访问 Client,将消息传递到Client 端,在通过消息分发渠道,将消息传递到具体的消息处理函数。(用户输入等操作最先是到 窗口管理服务,由窗口管理服务发给活动窗口,再一步步传递到焦点)。
public ViewRoot(Context context) {
super();
//获取IWindowSession,
getWindowSession(context.getMainLooper());
mWindow = new W(this, context);
}
W类,用于window manager向Activity传递各种消息。
static class W extends IWindow.Stub {
private final WeakReference<ViewRoot> mViewRoot;
private final Looper mMainLooper;
public W(ViewRoot viewRoot, Context context) {
mViewRoot = new WeakReference<ViewRoot>(viewRoot);
mMainLooper = context.getMainLooper();
}
******从Window mananger来的消息通过W出递给ViewRoot,由ViewRoot分发
public void dispatchKey(KeyEvent event) {
final ViewRoot viewRoot = mViewRoot.get();
if (viewRoot != null) {
viewRoot.dispatchKey(event);
} else {
new EventCompletion(mMainLooper, this, event, false, null);
}
}
}
通过IWindowSession机制就可以保证Activity和Window manager保持联系,通过IWindow可以将window manager收集到的消息分发出去。
部分内容及第三张和第四张图片参考网址:
http://blog.csdn.net/xieqibao/article/details/6567814
http://blog.csdn.net/windskier/article/details/6957901
http://vssupermadman.iteye.com/blog/1196323
http://blog.csdn.net/maxleng/article/list/2
http://hi.baidu.com/xiaofanqing/item/8ad71c3fd40e810eceb9feb5[/size][size=xx-large]
http://wsy1983wsy.iteye.com/blog/1671999
activity,view,window,windowmanager代码阅读总结及相互关系的更多相关文章
- Activity和Window的View的移动的一些思考与体会,腾讯悬浮小火箭的实现策略
Activity和Window的View的移动的一些思考与体会,腾讯悬浮小火箭的实现策略 事实上写这个也是因为自己实际在项目中用到了才会去研究已经写文章,对于View的移动,其实说实话,已经有很多文章 ...
- Android GUI之Activity、Window、View
相信大家在接触Android之初就已经知道了Activity中的setContentView方法的作用了,很明显此方法是用于为Activity填充相应的布局的.那么,Activity是如何将填充的布局 ...
- Android进阶笔记08:Android 中Activity、Window和View之间的关系
1. Android 中Activity.Window和View之间的关系(比喻): Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图) LayoutI ...
- android应用开发之Window,View和WindowManager .
ViewManager vm = a.getWindowManager(); vm.add(view,l); window :一个抽象的窗口基类,控制顶层窗口的外观和行为.作为顶层窗口,可控制窗口背 ...
- 动态加载Layout 与 论Activity、 Window、View的关系
1)动态加载Layout的代码是 getWindow().setContentView(LayoutInflater.from(this).inflate(R.layout.main, null)); ...
- android中Activity中的WindowManager与Window
在做项目的过程中,需要实现Activity非全屏显示.窗口背景透明显示的效果. 在实现这些功能的过程中,涉及到Window与WindowManager两个类,经过查一些相关资料,了解二者之间的不同点如 ...
- 动态载入Layout 与 论Activity、 Window、View的关系
1)动态载入Layout的代码是 getWindow().setContentView(LayoutInflater.from(this).inflate(R.layout.main, null)); ...
- Android 的窗口管理系统 (View, Canvas, WindowManager)
http://blog.csdn.net/ritterliu/article/details/39295271 From漫天尘沙 在图解Android - Zygote 和 System Server ...
- Unity3D研究院之打开Activity与调用JAVA代码传递参数
原地址:http://www.xuanyusong.com/archives/667 Unity for Android 比较特殊,Unity for IOS 打包是将XCODE工程直接交给开发 ...
随机推荐
- 转: Python 运算符与用法
+加两个对象相加 3 + 5得到8.'a' + 'b'得到'ab'. (注意:6+'a'这样是错误的,但在PHP里这样是可以运行的) -减得到负数或是一个数减去另一个数 -5.2得到一个负数.50 - ...
- 【转】如何判断CPU是大端还是小端模式
原文网址:http://blog.csdn.net/ysdaniel/article/details/6617458 如何判断CPU是大端还是小端模式 http://blog.sina.com.cn/ ...
- Android studio 开发中 用git实现批量忽略特定文件的方法
git实现批量忽略特定文件的方法 在用AndroidStudio开发项目的时候,3个人协同开发,那么用Git同步代码,会将模块中的大量iml文件同步,每次都会提交和更新,一个一个的去忽略他们,显然是最 ...
- HDU5126---stars (CDQ套CDQ套 树状数组)
题意:Q次操作,三维空间内 每个星星对应一个坐标,查询以(x1,y1,z1) (x2,y2,z2)为左下顶点 .右上顶点的立方体内的星星的个数. 注意Q的范围为50000,显然离散化之后用三维BIT会 ...
- CCF 送货 + 欧拉路模板
#include <bits/stdc++.h> using namespace std; stack<int> st; vector<]; ][]; ],cp[]; i ...
- C++ 命名规范小结
1. #defines and const test.h #ifndef TEST_H #define TEST_H #endif #define FALSE 0 #define TRUE (!FAL ...
- 关于UIView 的autoresizingMask属性,即UIViewAutoresizing
enum { UIViewAutoresizingNone = 0, UIViewAutoresizingFlexibleLeftMargin = 1 &l ...
- Ubuntu 14.04 下手动安装Firefox的Flash插件
有时候我们不得不採用手动安装一些软件. Ubuntu 14.04 下手动安装Firefox的Flash插件有下面几步 1. 下载Flash插件 下载地址为http://get.adobe.com/cn ...
- shell脚本加密
如何保护自己编写的shell程序要保护自己编写的shell脚本程序,方法有很多,最简单的方法有两种:1.加密 2.设定过期时间,下面以shc工具为例说明: 一.下载安装shc工具shc是一个加密s ...
- (转)Android 判断用户2G/3G/4G移动数据网络
在做 Android App 的时候,为了给用户省流量,为了不激起用户的愤怒,为了更好的用户体验,是需(要根据用户当前网络情况来做一些调整的,也可以在 App 的设置模块里,让用户自己选择,在 2G ...