转载请注明出处:
http://blog.csdn.net/qq347198688/article/details/52637908
本文出自【何嘉龙的博客】
前言:
本篇博客是在阅读医生的《Android群英传》第三章总结出来的,在下正在学习进阶中,有不足的地方希望大家能够指出来。然后衷心向大家推荐这本书。
Android 控件架构
Android中的每个控件都会在界面中占得一块矩形的区域,而在Android中,控件大致被分为两类,即ViewGroup控件与View控件。ViewGroup控件作为父控件可以包含多个View控件,并管理其包含的View控件。通过ViewGroup,整个界面上的控件形成了一个树形结构,这也就是我们常说的控件树,上层控件负责下层子控件的测量与绘制,并传递交互事件。通常在Activity中使用的findViewById()方法,就是在控件树中以树的深度优先遍历来查找对应元素。在每颗控件树顶部,都有一个ViewParent对象,这就是整棵树的核心,所有的交互管理事件都由它来统一调度和分配,从而可以对整个视图进行整体控制。
View控件树:
通常情况下,在Activity中使用setContentView()方法来设置一个布局,在调用该方法后,布局内容才能真正显示出来。那么setContentView方法具体做了些什么呢?首先我们来看一下Android界面的架构图,如下所示:
如图所示,每个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里。
举个例子让大家理解一下:
对应的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。
欢迎大家提出意见,指责错误。