Android控件架构以及setContentView()方法剖析

来源:互联网 发布:广电网络是国企吗 编辑:程序博客网 时间:2024/06/01 23:46

转载请注明出处:
http://blog.csdn.net/qq347198688/article/details/52637908
本文出自【何嘉龙的博客】

前言:

本篇博客是在阅读医生的《Android群英传》第三章总结出来的,在下正在学习进阶中,有不足的地方希望大家能够指出来。然后衷心向大家推荐这本书。

Android 控件架构

Android中的每个控件都会在界面中占得一块矩形的区域,而在Android中,控件大致被分为两类,即ViewGroup控件与View控件。ViewGroup控件作为父控件可以包含多个View控件,并管理其包含的View控件。通过ViewGroup,整个界面上的控件形成了一个树形结构,这也就是我们常说的控件树,上层控件负责下层子控件的测量与绘制,并传递交互事件。通常在Activity中使用的findViewById()方法,就是在控件树中以树的深度优先遍历来查找对应元素。在每颗控件树顶部,都有一个ViewParent对象,这就是整棵树的核心,所有的交互管理事件都由它来统一调度和分配,从而可以对整个视图进行整体控制。

View控件树:

View控件树

通常情况下,在Activity中使用setContentView()方法来设置一个布局,在调用该方法后,布局内容才能真正显示出来。那么setContentView方法具体做了些什么呢?首先我们来看一下Android界面的架构图,如下所示:

UI界面架构图

如图所示,每个Activity都包含一个Window,在Android中Window对象通常由PhoneWindow来实现。PhoneWindow将一个DecorView设置为整个应用窗口的根View。DecorView作为窗口界面的顶层视图,封装了一些窗口操作的通用方法。可以说DecorView将要显示的具体内容呈现在了PhoneWindow上,这里面的所有View的监听事件,都通过WindowManagerService来进行接收,并通过Activity对象来回调相应的OnClickListener。

activity、window和view之间的关系:
而当我们运行程序的时候,有一个setContentView()方法,Activity其实不是显示视图(直观上感觉是它),实际上Activity调用了PhoneWindow的setContentView()方法,然后加载视图,将视图放到这个Window上,而Activity其实构造的时候初始化的是Window(PhoneWindow),Activity其实是个控制单元,即可视的人机交互界面。

打个比喻:
Activity是一个工人,它来控制Window;Window是一面显示屏,用来显示信息;View就是要显示在显示屏上的信息,这些View都是层层重叠在一起(通过infalte()和addView())放到Window显示屏上的。而LayoutInfalter就是用来生成View的一个工具,XML布局文件就是用来生成View的原料。

activity调用setContentView其实是调用window的方法。让我们来查看源码:

Activity中:

 public void setContentView(int layoutResID) {        getWindow().setContentView(layoutResID);        initActionBar();    }

在PhoneWindow类中:

 @Override    public void setContentView(int layoutResID) {        if (mContentParent == null) {            installDecor();        } else {            mContentParent.removeAllViews();        }        mLayoutInflater.inflate(layoutResID, mContentParent);        final Callback cb = getCallback();        if (cb != null && !isDestroyed()) {            cb.onContentChanged();        }    }

在理解实际上Activity调用了PhoneWindow的setContentView()方法后,再让我们看到那幅界面架构图,DecorView,它将屏幕分为两个部分,一个是TitleView,另一个是ContentView。看到这里,大家一定看到了一个非常熟悉的布局——ContentView。它是一个ID为content的FrameLayout,activity_main.xml就是设置在这样的一个FrameLayout里。

举个例子让大家理解一下:

3

对应的xml文件如下:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout                      xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="edu.whut.xucheng.job1.MainActivity">    <TextView        android:id="@+id/textview"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="Hello World!" />    <Button        android:id="@+id/button"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerHorizontal="true"        android:layout_centerVertical="true"        android:text="显示手机信息" /></RelativeLayout>

可以看到,我们并没有在xml文件中写入Actionbar或者是Toolbar,而我们的运行效果里面就有。这是为什么呢?大家回顾一下上面说的,DecorView被分为两个部分,第一个是TitleView,由Actionbar或Toolbar组成。另一个就是ContentView,对应的是布局文件里面的内容。所以TitleView不是在布局文件中定义的。

当然,我们也可以在布局文件中定义自己的Toolbar,但必须要在代码中加入requestWindowFeature(Window.FEARURE_NO_TITLE)隐藏系统自带的TitleView。


欢迎大家提出意见,指责错误。

1 0