上一篇博客Android中Handler原理在讲到Handler的时候谈到了android的Activity启动是怎样运行到onCreate方法的,这篇主要从onCreate方法里面我们必需要写的方法setContentView開始,研究布局视图是怎样载入到手机窗体上的。

当在运行到setContentView时,实际上运行的是

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

能够看到实际上是Window类的setContentView方法

private Window mWindow;
public Window getWindow() {
return mWindow;
}

Window类是一个抽象类,以下主要是找到他的实现类。mWindow初始化在

final void attach(……) {
……
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
……
}

Attach方法在main方法中。详细查看上一篇博客。调用了PolicyManager类的静态方法makeNewWindow生成Window对象

private static final String POLICY_IMPL_CLASS_NAME =
"com.android.internal.policy.impl.Policy";
private static final IPolicy sPolicy;
static {
try {
Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
sPolicy = (IPolicy)policyClass.newInstance();
}
……
}
public static Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}

能够看到是通过Policy类的makeNewWindow方法得到的Window对象。这里是通过反射机制获取的Policy的实例。

public Window makeNewWindow(Context context) {
return new PhoneWindow(context);
}

能够看到实际上是一个PhoneWindow。那么依据多态。事实上在上面调用的就是PhoneWindow#setContentWindow

public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();//1
} else {
mContentParent.removeAllViews();
}
mLayoutInflater.inflate(layoutResID, mContentParent);//2 将layoutResID填充。他的父View是mContentParent是在installDecor方法里面mContentParent = generateLayout(mDecor);得到的
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}

运行到installDecor()

private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();//生成装饰窗体。装饰窗体继承自FrameLayout
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);// 产生布局。返回父布局,临时这样理解,详细进去看代码
mDecor.makeOptionalFitsSystemWindows();
mTitleView = (TextView)findViewById(com.android.internal.R.id.title);
......
}
}
}

generateLayout的代码例如以下

protected ViewGroup generateLayout(DecorView decor) {
// Apply data from current theme. TypedArray a = getWindowStyle();// 获取当前设置的主题
......
if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) {
requestFeature(FEATURE_NO_TITLE);//能够看到平时在AndroidManifest配置的窗体等各事实上在代码里都是在这里改动的
} else if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBar, false)) {
// Don't allow an action bar if there is no title.
requestFeature(FEATURE_ACTION_BAR);
} if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBarOverlay, false)) {
requestFeature(FEATURE_ACTION_BAR_OVERLAY);
}
......
//19-63行依据我们指定的有无标题等各种窗体风格得到相应的默认布局。
//这些布局在D:\SoftWare\Java\android4.2-source\frameworks\base\core\res\res\layout
int layoutResource;
int features = getLocalFeatures();
if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
com.android.internal.R.attr.dialogTitleIconsDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = com.android.internal.R.layout.screen_title_icons;
}
removeFeature(FEATURE_ACTION_BAR);
} else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
&& (features & (1 << FEATURE_ACTION_BAR)) == 0) {
layoutResource = com.android.internal.R.layout.screen_progress;
} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
com.android.internal.R.attr.dialogCustomTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = com.android.internal.R.layout.screen_custom_title;
}
removeFeature(FEATURE_ACTION_BAR);
} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
com.android.internal.R.attr.dialogTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
if ((features & (1 << FEATURE_ACTION_BAR_OVERLAY)) != 0) {
layoutResource = com.android.internal.R.layout.screen_action_bar_overlay;
} else {
layoutResource = com.android.internal.R.layout.screen_action_bar;
}
} else {
layoutResource = com.android.internal.R.layout.screen_title;
}
} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
layoutResource = com.android.internal.R.layout.screen_simple_overlay_action_mode;
} else {
layoutResource = com.android.internal.R.layout.screen_simple;
} mDecor.startChanging(); View in = mLayoutInflater.inflate(layoutResource, null);//依据上面的推断选择的layoutResource填充成View
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));//调用装饰窗体的addView方法将上一步生成的View加入到最外层的装饰窗体 ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);//ID_ANDROID_CONTENT相应的都是@android:id/content事实上是一个FrameLayout
......
mDecor.finishChanging();
return contentParent;
}

以下是最经常使用的layoutResource布局文件他们在D:\SoftWare\Java\android4.2-source\frameworks\base\core\res\res\layout目录下

Screen-title.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:fitsSystemWindows="true">
<!-- Popout bar for action modes -->
<ViewStub android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="?android:attr/windowTitleSize"
style="?android:attr/windowTitleBackgroundStyle">
<TextView android:id="@android:id/title"
style="? android:attr/windowTitleStyle"
android:background="@null"
android:fadingEdge="horizontal"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<FrameLayout android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>

最外层是线性布局。包括帧布局(包括一个TextView事实上就是标题)和帧布局。事实上这个就是最常见的样子。

默认生成的程序就是这个样子。

Screen-simple.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<ViewStub android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundInsidePadding="false"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>

显而易见这个就是全屏设置时默认载入的布局。

我们能够看到id为content的FrameLayout都存在的,由于他要装载我们填充的xml

依Screen-title.xml为例。大致是这样子的

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2F1Y2h5d2VpZXJzdHJhc3M=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

通过以上分析明确了下面几点:

1. Activity呈现出来的界面事实上是一个PhoneWindow类在管理的。这个类中有一个DecorView成员就是最外层的一个容器。

2. 上面这张图是很重要的,显示了窗体的结构。

3. Activity究竟是个什么东西?还真不好说清楚…^_^总之和刚開始的认识是不同的。

4. 遇到不懂得问题就去查看源代码。代码是最好的老师!

Android视图载入到窗体的过程分析的更多相关文章

  1. Android视图框架

    Android视图框架 Android的UI系统是android应用系统框架最核心,最基础的内容! 1. Android视图系统.层次关系 Android应用设计和Web应用设计类似,也分前端和后端设 ...

  2. Android动态载入Dex机制解析

    1.什么是类载入器? 类载入器(class loader)是 Java™中的一个非常重要的概念.类载入器负责载入 Java 类的字节代码到 Java 虚拟机中. Java 虚拟机使用 Java 类的方 ...

  3. 1.Android 视图及View绘制分析笔记之setContentView

    自从1983年第一台图形用户界面的个人电脑问世以来,几乎所有的PC操作系统都支持可视化操作,Android也不例外.对于所有Android Developer来说,我们接触最多的控件就是View.通常 ...

  4. 从零开始学android开发- 应用程序窗体显示状态操作requestWindowFeature

    我们在开发程序是经常会需要软件全屏显示.自定义标题(使用按钮等控件)和其他的需求,今天这一讲就是如何控制Android应用程序的窗体显示. 首先介绍一个重要方法那就是requestWindowFeat ...

  5. 深入浅出Android动态载入jar包技术

    在实际项目中.因为某些业务频繁变更而导致频繁升级client的弊病会造成较差的用户体验,而这也恰是Web App的优势,于是便衍生了一种思路.将核心的易于变更的业务封装在jar包里然后通过网络下载下来 ...

  6. 实现Android 动态载入APK(Fragment or Activity实现)

    尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38565345 近期由于项目太大了.导致编译通只是(Android对一个应用中的方法个数貌似有 ...

  7. Android异步载入全解析之使用多线程

    异步载入之使用多线程 初次尝试 异步.异步,事实上说白了就是多任务处理.也就是多线程执行.多线程那就会有各种问题,我们一步步来看.首先.我们创建一个class--ImageLoaderWithoutC ...

  8. Android Bitmap 载入与像素操作

    Android Bitmap 载入与像素操作 一:载入与像素读写 在Android SDK中,图像的像素读写能够通过getPixel与setPixel两个Bitmap的API实现. Bitmap AP ...

  9. Android异步载入全解析之IntentService

    Android异步载入全解析之IntentService 搞什么IntentService 前面我们说了那么多,异步处理都使用钦定的AsyncTask.再不济也使用的Thread,那么这个Intent ...

随机推荐

  1. 壹、js的概述

    一.js的起源 1992年的时候,一家名为Nomnas的公司开发出了c减减的嵌入式脚本语言:然后利用分享的方式,扩大其市场. 之后,Netscape为了扩展浏览器的功能,开发了一个名为LiveScri ...

  2. 向ueditor中插入内容

    html在ueditor中插入内容不能直接插入,必须判断编辑器是否创建成功,jsp可以用java代码嵌套的方式. html页面中:<textarea id="zym" nam ...

  3. [转载]不唐突的JavaScript的七条准则

    经过多年的开发.教学和编写不唐突的JavaScript, 我发现了下面的一些准则.我希望它们可以帮助你对“为什么这样设计和执行JavaScript比较好”有一点理解.这些规则曾经帮助我更快地交付产品, ...

  4. Linux 磁盘坏道检测和修复

    今天在实验室碰到一台机器,根分区和/upgrade分区变成了read-only system.当碰到这个问题的时候,我的第一反应很可能硬件出现了故障,我使用了如下的方法来检测和排除故障: 使用dmes ...

  5. 《Effective Modern C++》翻译--条款4:了解怎样查看推导出的类型

    条款4:了解怎样查看推导出的类型 那些想要了解编译器怎样推导出的类型的人通常分为两个阵营. 第一种阵营是实用主义者.他们的动力通常来自于编敲代码过程中(比如他们还在调试解决中),他们利用编译器进行寻找 ...

  6. JavaScript加密解密7种方法

    注:本文纯转贴,供学习使用 本文一共介绍了七种javascript加密方法: 在做网页时(其实是网页木马呵呵),最让人烦恼的是自己辛辛苦苦写出来的客户端IE运行的javascript代码常常被别人轻易 ...

  7. h5 离线存储

  8. numeric and int in sql server

    类型映射 https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql-server-data-type-mappings C#关 ...

  9. 使用OpenCV把二进制mnist数据集转换为图片

    mnist数据集是以二进制形式保存的,这里借助OpenCV把mnist数据集转换成图片格式.转换程序如下: #include <iostream> #include <fstream ...

  10. [POJ2728] Desert King 解题报告(最优比率生成树)

    题目描述: David the Great has just become the king of a desert country. To win the respect of his people ...