Android GUI之Activity、Window、View
相信大家在接触Android之初就已经知道了Activity中的setContentView方法的作用了,很明显此方法是用于为Activity填充相应的布局的。那么,Activity是如何将填充的布局绘制出来的呢?实际上Activity将View的绘制与显示交给了Window对象来处理,下面我们通过源码来进行跟踪分析。
Activity的源码如下,只给出我们关注的部分:
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback {
……
……
private Window mWindow;
private WindowManager mWindowManager;
…… /**
* Retrieve the current {@link android.view.Window} for the activity.
* This can be used to directly access parts of the Window API that
* are not available through Activity/Screen.
*
* @return Window The current window, or null if the activity is not
* visual.
*/
public Window getWindow() {
return mWindow;
}
……
/**
* Set the activity content from a layout resource. The resource will be
* inflated, adding all top-level views to the activity.
*
* @param layoutResID Resource ID to be inflated.
*
* @see #setContentView(android.view.View)
* @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
*/
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
} /**
* Set the activity content to an explicit view. This view is placed
* directly into the activity's view hierarchy. It can itself be a complex
* view hierarchy. When calling this method, the layout parameters of the
* specified view are ignored. Both the width and the height of the view are
* set by default to {@link ViewGroup.LayoutParams#MATCH_PARENT}. To use
* your own layout parameters, invoke
* {@link #setContentView(android.view.View,android.view.ViewGroup.LayoutParams)}
* instead.
*
* @param view The desired content to display.
*
* @see #setContentView(int)
* @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
*/
public void setContentView(View view) {
getWindow().setContentView(view);
initWindowDecorActionBar();
}
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, IVoiceInteractor voiceInteractor) {
attachBaseContext(context);
mFragments.attachActivity(this, mContainer, null);
mWindow = PolicyManager.makeNewWindow(this); ……
}
……
}
PolicyManager的部分源码:
public final class PolicyManager {
……
private static final IPolicy sPolicy;
static {
// Pull in the actual implementation of the policy at run-time
……
sPolicy = (IPolicy)policyClass.newInstance();
……
}
// Cannot instantiate this class
private PolicyManager() {}
// The static methods to spawn new policy-specific objects
public static Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}
……
}
Policy的部分源码:
public class Policy implements IPolicy {
……
public Window makeNewWindow(Context context) {
return new PhoneWindow(context);
}
……
}
从给出的源码我们可以看到,Activity内部含有一个Window类型的对象mWindow,当我们调用setContentView方法时,实际上是委托给了Window对象进行处理。Window本身是一个抽象类,它描述了android窗口的基本属性和行为特征。在activity的attach方法中通过mWindow = PolicyManager.makeNewWindow(this)创建了Window对象。通过追踪代码可知, PolicyManager.makeNewWindow(this)实际上是调用Policy中的makeNewWindow方法,在此方法中创建了一个PhoneWindow对象。而PhoneWindow正是Window的子类。他们的关系图如下:

继续追踪源码,PhoneWindow对Window的抽象方法setContentView(int layoutResId)进行了实现,具体源码如下:
@Override
public void setContentView(int layoutResID) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
} if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
getContext());
transitionTo(newScene);
} else {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
在这个方法中我们可以看到首先对mContentParent进行了判断,如果为空的话则调用installDecor方法,通过hasFeature判断window是否具备某些特征,如果窗口不含有FEATURE_CONTENT_TRANSITIONS特征,则清空mContentParent中的所有子元素,为后面加载布局文件到mContentParent中做好准备。通过后面的判断,我们也可以看出无论走那个分支,其实都是对mContentParent布局内容做了更新。由此我们可以推断出mContentParent其实就是我们自己的布局的存放容器,它在PhoneWindow中定义如下:
// 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.
private ViewGroup mContentParent;
那么mContentParent是在哪里被创建的呢,很显然是在方法installDecor中,方法installDecor的关键代码如下:
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
……
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
……
}
}
在这个方法中,我们可以看到,首先对mDecor进行判断,如果为空在调用generateDecor方法生成mDecor对象,那么mDecor对象是什么呢?通过查看代码,可以知道mDecor的类型为DecorView,此类型是定义在PhoneWindow中的一个内部类,它继承了FrameLayout。紧接着判断mContentParent是否为空,为空则调用generateLayout并通过传入参数mDecor生成了mContentParent对象。在这个方法中通过应用的主题、窗口特征等来确定使用的布局资源并将使用的布局添加mDecor中,而这些布局中都会含有一个id为content的ViewGroup(FrameLayout),此ViewGroup正是mContentParent,方法关键代码如下:
protected ViewGroup generateLayout(DecorView decor) {
……
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
mContentRoot = (ViewGroup) in;
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
……
return contentParent;
}
由此我们可以确定,view的显示处理顺序为Activity->PhoneWindow->DecorView->ViewGroup(mContentView)->自定义的View(布局)。
Activity中显示视图的层次结构,具体如下:

疑问咨询或技术交流,请加入官方QQ群:
(452379712)
出处:http://www.cnblogs.com/jerehedu/
本文版权归烟台杰瑞教育科技有限公司和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
Android GUI之Activity、Window、View的更多相关文章
- Activity Window View的关系
http://blog.csdn.net/chiuan/article/details/7062215 http://blog.163.com/fenglang_2006/blog/static/13 ...
- activity window view 关系
1.Activity , Window和View的关系是什么? 跟踪Activity的源码就会发现:Activity.attch() -> PolicyManager -> Policy ...
- Activity Window View WindowManager关系&Touch事件分发机制
http://www.cnblogs.com/linjzong/p/4191891.html https://www.cnblogs.com/kest/p/5141817.html https://b ...
- android中activity,window,view之间的关系
activity:控制单元 window:承载模型 view:显示视图 几个小tip: 1.一个 Activity 构造的时候一定会构造一个 Window(PhoneWindow),并且只有一个 2. ...
- android 中的 window,view,activity具体关系
通过讨论这个问题,我们能够见识到google是对面向对象模式的理解,能够理解android底层的一些调用.这也是一道很常见的面试题. 我们这篇文章就来解决这四个问题: Android 中view的显 ...
- 图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)
Android 的窗口管理系统 (View, Canvas, WindowManager) 在图解Android - Zygote 和 System Server 启动分析一 文里,我们已经知道And ...
- android应用开发之Window,View和WindowManager .
ViewManager vm = a.getWindowManager(); vm.add(view,l); window :一个抽象的窗口基类,控制顶层窗口的外观和行为.作为顶层窗口,可控制窗口背 ...
- View, Activity, Window
View, Activity, Window 2010-03-02 10:42:56| 分类: android|举报|字号 订阅 对于屏幕显示而言,整个是window,这个window里显示 ...
- Android GUI之View绘制流程
在上篇文章中,我们通过跟踪源码,我们了解了Activity.Window.DecorView以及View之间的关系(查看文章:http://www.cnblogs.com/jerehedu/p/460 ...
随机推荐
- 使用exundelete在Linux下恢复删除的文件
原文:https://my.oschina.net/looly/blog/261912 Linux下执行 rm 并不会真正删除,而是将inode节点中的扇区删除,同时释放数据块.在数据块被系统重新分配 ...
- pytest十一:函数传参和 firture 传参数 request
为了提高代码的复用性,我们在写用例的时候,会用到函数,然后不同的用例去调用这个函数.比如登录操作,大部分的用例都会先登录,那就需要把登录单独抽出来写个函数,其它用例全部的调用这个登录函数就行.但是登录 ...
- python 全栈开发,Day137(爬虫系列之第4章-scrapy框架)
一.scrapy框架简介 1. 介绍 Scrapy一个开源和协作的框架,其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的,使用它可以以快速.简单.可扩展的方式从网站中提取所需的数据.但目前S ...
- python 全栈开发,Day104(DRF用户认证,结算中心,django-redis)
考试第二部分:MySQL数据库 6. MySQL中char和varchar的区别(1分) char是定长,varchar是变长. char的查询速度比varchar要快. 7. MySQL中va ...
- Java 和 C++ 的部分区别
1. Java是解释型语言,所谓的解释型语言,就是源码会先经过一次编译,成为中间码,中间码再被解释器解释成机器码.对于Java而言,中间码就是字节码(.class),而解释器在JVM中内置了. 2. ...
- 检测cpu、主板、内存
https://jingyan.baidu.com/article/636f38bb595cebd6b84610eb.html
- 高德地图web端笔记;发送http请求的工具类
1.查询所有电子围栏 package com.skjd.util; import java.io.BufferedReader; import java.io.InputStream; import ...
- 《Gradle权威指南》--Android Gradle多渠道构建
No1: Build Variant = Build Type + Product Flavor Build Variant:构建的产物 Build Type:构建的类型 Product Flavor ...
- FZU 2150 Fire Game(双起点)【BFS】
<题目链接> 题目大意: 两个熊孩子在n*m的平地上放火玩,#表示草,两个熊孩子分别选一个#格子点火,火可以向上向下向左向右在有草的格子蔓延,点火的地方时间为0,蔓延至下一格的时间依次加一 ...
- 数据库学习之数据库增删改查(另外解决Mysql在linux下不能插入中文的问题)(二)
数据库增删改查 增加 首先我们创建一个数据库user,然后创建一张表employee create table employee( id int primary key auto_increment, ...