相信大家在接触Android之初就已经知道了Activity中的setContentView方法的作用了,很明显此方法是用于为Activity填充相应的布局的。那么,Activity是如何将填充的布局绘制出来的呢?实际上Activity将View的绘制与显示交给了Window对象来处理,下面我们通过源码来进行跟踪分析。

  Activity的源码如下,只给出我们关注的部分:

  1. public class Activity extends ContextThemeWrapper
  2. implements LayoutInflater.Factory2,
  3. Window.Callback, KeyEvent.Callback,
  4. OnCreateContextMenuListener, ComponentCallbacks2,
  5. Window.OnWindowDismissedCallback {
  6. ……
  7. ……
  8. private Window mWindow;
  9. private WindowManager mWindowManager;
  10. ……
  11.  
  12. /**
  13. * Retrieve the current {@link android.view.Window} for the activity.
  14. * This can be used to directly access parts of the Window API that
  15. * are not available through Activity/Screen.
  16. *
  17. * @return Window The current window, or null if the activity is not
  18. * visual.
  19. */
  20. public Window getWindow() {
  21. return mWindow;
  22. }
  23. ……
  24. /**
  25. * Set the activity content from a layout resource. The resource will be
  26. * inflated, adding all top-level views to the activity.
  27. *
  28. * @param layoutResID Resource ID to be inflated.
  29. *
  30. * @see #setContentView(android.view.View)
  31. * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
  32. */
  33. public void setContentView(int layoutResID) {
  34. getWindow().setContentView(layoutResID);
  35. initWindowDecorActionBar();
  36. }
  37.  
  38. /**
  39. * Set the activity content to an explicit view. This view is placed
  40. * directly into the activity's view hierarchy. It can itself be a complex
  41. * view hierarchy. When calling this method, the layout parameters of the
  42. * specified view are ignored. Both the width and the height of the view are
  43. * set by default to {@link ViewGroup.LayoutParams#MATCH_PARENT}. To use
  44. * your own layout parameters, invoke
  45. * {@link #setContentView(android.view.View,android.view.ViewGroup.LayoutParams)}
  46. * instead.
  47. *
  48. * @param view The desired content to display.
  49. *
  50. * @see #setContentView(int)
  51. * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
  52. */
  53. public void setContentView(View view) {
  54. getWindow().setContentView(view);
  55. initWindowDecorActionBar();
  56. }
  57. final void attach(Context context, ActivityThread aThread,
  58. Instrumentation instr, IBinder token, int ident,
  59. Application application, Intent intent, ActivityInfo info,
  60. CharSequence title, Activity parent, String id,
  61. NonConfigurationInstances lastNonConfigurationInstances,
  62. Configuration config, IVoiceInteractor voiceInteractor) {
  63. attachBaseContext(context);
  64. mFragments.attachActivity(this, mContainer, null);
  65. mWindow = PolicyManager.makeNewWindow(this);
  66.  
  67. ……
  68. }
  69. ……
  70. }

PolicyManager的部分源码:

  1. public final class PolicyManager {
  2. ……
  3. private static final IPolicy sPolicy;
  4. static {
  5. // Pull in the actual implementation of the policy at run-time
  6. ……
  7. sPolicy = (IPolicy)policyClass.newInstance();
  8. ……
  9. }
  10. // Cannot instantiate this class
  11. private PolicyManager() {}
  12. // The static methods to spawn new policy-specific objects
  13. public static Window makeNewWindow(Context context) {
  14. return sPolicy.makeNewWindow(context);
  15. }
  16. ……
  17. }

Policy的部分源码:

  1. public class Policy implements IPolicy {
  2. ……
  3. public Window makeNewWindow(Context context) {
  4. return new PhoneWindow(context);
  5. }
  6. ……
  7. }

  从给出的源码我们可以看到,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)进行了实现,具体源码如下:

  1. @Override
  2. public void setContentView(int layoutResID) {
  3. // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
  4. // decor, when theme attributes and the like are crystalized. Do not check the feature
  5. // before this happens.
  6. if (mContentParent == null) {
  7. installDecor();
  8. } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
  9. mContentParent.removeAllViews();
  10. }
  11.  
  12. if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
  13. final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
  14. getContext());
  15. transitionTo(newScene);
  16. } else {
  17. mLayoutInflater.inflate(layoutResID, mContentParent);
  18. }
  19. final Callback cb = getCallback();
  20. if (cb != null && !isDestroyed()) {
  21. cb.onContentChanged();
  22. }
  23. }

  在这个方法中我们可以看到首先对mContentParent进行了判断,如果为空的话则调用installDecor方法,通过hasFeature判断window是否具备某些特征,如果窗口不含有FEATURE_CONTENT_TRANSITIONS特征,则清空mContentParent中的所有子元素,为后面加载布局文件到mContentParent中做好准备。通过后面的判断,我们也可以看出无论走那个分支,其实都是对mContentParent布局内容做了更新。由此我们可以推断出mContentParent其实就是我们自己的布局的存放容器,它在PhoneWindow中定义如下:

  1. // This is the view in which the window contents are placed. It is either
  2. // mDecor itself, or a child of mDecor where the contents go.
  3. private ViewGroup mContentParent;

  那么mContentParent是在哪里被创建的呢,很显然是在方法installDecor中,方法installDecor的关键代码如下:

  1. private void installDecor() {
  2. if (mDecor == null) {
  3. mDecor = generateDecor();
  4. ……
  5. }
  6. if (mContentParent == null) {
  7. mContentParent = generateLayout(mDecor);
  8. ……
  9. }
  10. }

  在这个方法中,我们可以看到,首先对mDecor进行判断,如果为空在调用generateDecor方法生成mDecor对象,那么mDecor对象是什么呢?通过查看代码,可以知道mDecor的类型为DecorView,此类型是定义在PhoneWindow中的一个内部类,它继承了FrameLayout。紧接着判断mContentParent是否为空,为空则调用generateLayout并通过传入参数mDecor生成了mContentParent对象。在这个方法中通过应用的主题、窗口特征等来确定使用的布局资源并将使用的布局添加mDecor中,而这些布局中都会含有一个id为content的ViewGroup(FrameLayout),此ViewGroup正是mContentParent,方法关键代码如下:

  1. protected ViewGroup generateLayout(DecorView decor) {
  2. ……
  3. View in = mLayoutInflater.inflate(layoutResource, null);
  4. decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
  5. mContentRoot = (ViewGroup) in;
  6. ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
  7. ……
  8. return contentParent;
  9. }

  由此我们可以确定,view的显示处理顺序为Activity->PhoneWindow->DecorView->ViewGroup(mContentView)->自定义的View(布局)。

  Activity中显示视图的层次结构,具体如下:

  疑问咨询或技术交流,请加入官方QQ群: (452379712)

作者:杰瑞教育
出处:http://www.cnblogs.com/jerehedu/ 
本文版权归烟台杰瑞教育科技有限公司和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
 

Android GUI之Activity、Window、View的更多相关文章

  1. Activity Window View的关系

    http://blog.csdn.net/chiuan/article/details/7062215 http://blog.163.com/fenglang_2006/blog/static/13 ...

  2. activity window view 关系

    1.Activity , Window和View的关系是什么? 跟踪Activity的源码就会发现:Activity.attch() -> PolicyManager -> Policy ...

  3. Activity Window View WindowManager关系&Touch事件分发机制

    http://www.cnblogs.com/linjzong/p/4191891.html https://www.cnblogs.com/kest/p/5141817.html https://b ...

  4. android中activity,window,view之间的关系

    activity:控制单元 window:承载模型 view:显示视图 几个小tip: 1.一个 Activity 构造的时候一定会构造一个 Window(PhoneWindow),并且只有一个 2. ...

  5. android 中的 window,view,activity具体关系

    通过讨论这个问题,我们能够见识到google是对面向对象模式的理解,能够理解android底层的一些调用.这也是一道很常见的面试题. 我们这篇文章就来解决这四个问题: Android  中view的显 ...

  6. 图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)

    Android 的窗口管理系统 (View, Canvas, WindowManager) 在图解Android - Zygote 和 System Server 启动分析一 文里,我们已经知道And ...

  7. android应用开发之Window,View和WindowManager .

    ViewManager  vm = a.getWindowManager(); vm.add(view,l); window :一个抽象的窗口基类,控制顶层窗口的外观和行为.作为顶层窗口,可控制窗口背 ...

  8. View, Activity, Window

    View, Activity, Window 2010-03-02 10:42:56|  分类: android|举报|字号 订阅     对于屏幕显示而言,整个是window,这个window里显示 ...

  9. Android GUI之View绘制流程

    在上篇文章中,我们通过跟踪源码,我们了解了Activity.Window.DecorView以及View之间的关系(查看文章:http://www.cnblogs.com/jerehedu/p/460 ...

随机推荐

  1. python 全栈开发,Day137(爬虫系列之第4章-scrapy框架)

    一.scrapy框架简介 1. 介绍 Scrapy一个开源和协作的框架,其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的,使用它可以以快速.简单.可扩展的方式从网站中提取所需的数据.但目前S ...

  2. python 全栈开发,Day102(支付宝支付)

    昨日内容回顾 1. django请求生命周期? - 当用户在浏览器中输入url时,浏览器会生成请求头和请求体发给服务端 请求头和请求体中会包含浏览器的动作(action),这个动作通常为get或者po ...

  3. python 全栈开发,Day54(jQuery的属性操作,使用jQuery操作input的value值,jQuery的文档操作)

    昨日内容回顾 jQuery 宗旨:write less do more 就是js的库,它是javascript的基础上封装的一个框架 在前端中,一个js文件就是一个模块 一.用法: 1.引入包 2.入 ...

  4. node.js认识及学习资料

    2011年阿里就已经开始在生产环境中使用nodejs. 阿里的技术栈中,Java是最核心的,Nodejs扮演怎样的一个角色? 1. 基础设施大部分采用Java实现,变化较少,有事务要求的Busines ...

  5. 结构型模式之Adapter模式

    适配器模式把一个类的接口变换成客户端所期待的另一种接口. 在JDK中的体现 把一个接口或类变成另外一种. java.util.Arrays#asList()javax.swing.JTable(Tab ...

  6. #8 //HDU 5730 Shell Necklace(CDQ分治+FFT)

    Description 给出长度分别为1~n的珠子,长度为i的珠子有a[i]种,每种珠子有无限个,问用这些珠子串成长度为n的链有多少种方案 题解: dp[i]表示组合成包含i个贝壳的项链的总方案数 转 ...

  7. 安装oracle11g时遇到INS-13001环境不满足最低要求

    在安装oracle11g,点击setup.exe之后,弹出了如下提示框: 解决方法: 首先,打开你解压后的database文件夹,找到stage,然后cvu,找到cvu_prereq.xml文件,用记 ...

  8. 085 HBase的二级索引,以及phoenix的安装(需再做一次)

    一:问题由来 1.举例 有A列与B列,分别是年龄与姓名. 如果想通过年龄查询姓名. 正常的检索是通过rowkey进行检索. 根据年龄查询rowkey,然后根据rowkey进行查找姓名. 这样的效率不高 ...

  9. Flutter常用组件(Widget)解析-Text

    单一格式的文本. 文本组件是以字符串形式显示的单一格式,这个文本字符串可以是多行显示也可以是单独一行显示,主要取决于你的布局限制. 这样式内容是可选择的,如果你省略了,则会使用文本的默认样式来显示.如 ...

  10. [洛谷P2066]机器分配

    题目描述 总公司拥有高效设备M台,准备分给下属的N个分公司.各分公司若获得这些设备,可以为国家提供一定的盈利.问:如何分配这M台设备才能使国家得到的盈利最大?求出最大盈利值.其中M≤15,N≤10.分 ...