}
可以看到, Activity的 setContentView实质是将 View传递到 Window的 setContentView()方法中, Window的 setContenView会在内部调用 installDecor()方法创建 DecorView,代码如下。
public void setContentView(int layoutResID) {
if (mContentParent == null) {
//初始化DecorView以及其内部的content
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
…
} else {
//将contentView加载到DecorVoew当中
mLayoutInflater.inflate(layoutResID, mContentParent);
}
…
}
private void installDecor() {
…
if (mDecor == null) {
//实例化DecorView
mDecor = generateDecor(-1);
…
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
//获取Content
mContentParent = generateLayout(mDecor);
}
…
}
protected DecorView generateDecor(int featureId) {
…
return new DecorView(context, featureId, this, getAttributes());
}
通过 generateDecor()的new一个 DecorView,然后调用 generateLayout()获取 DecorView中 content,最终通过 inflate将 Activity视图添加到 DecorView中的 content中,但此时 DecorView还未被添加到 Window中。添加操作需要借助 ViewRootImpl。
ViewRootImpl的作用是用来衔接 WindowManager和 DecorView,在 Activity被创建后会通过 WindowManager将 DecorView添加到 PhoneWindow中并且创建 ViewRootImpl实例,随后将 DecorView与 ViewRootImpl进行关联,最终通过执行 ViewRootImpl的 performTraversals()开启整个View树的绘制。
6.5 Draw 绘制流程
Android的Draw过程可以分为六个步骤:
-
首先,绘制View的背景;
-
如果需要的话,保持canvas的图层,为fading做准备;
-
然后,绘制View的内容;
-
接着,绘制View的子View;
-
如果需要的话,绘制View的fading边缘并恢复图层;
-
最后,绘制View的装饰(例如滚动条等等)。
涉及到的代码如下:
public void draw(Canvas canvas) {
…
// 步骤一:绘制View的背景
drawBackground(canvas);
…
// 步骤二:如果需要的话,保持canvas的图层,为fading做准备
saveCount = canvas.getSaveCount();
…
canvas.saveLayer(left, top, right, top + length, null, flags);
…
// 步骤三:绘制View的内容
onDraw(canvas);
…
// 步骤四:绘制View的子View
dispatchDraw(canvas);
…
// 步骤五:如果需要的话,绘制View的fading边缘并恢复图层
canvas.drawRect(left, top, right, top + length, p);
…
canvas.restoreToCount(saveCount);
…
// 步骤六:绘制View的装饰(例如滚动条等等)
onDrawForeground(canvas)
}
6.6 Requestlayout,onlayout,onDraw,DrawChild区别与联系
-
requestLayout():会导致调用 measure()过程 和 layout()过程,将会根据标志位判断是否需要ondraw。
-
onLayout():如果该View是ViewGroup对象,需要实现该方法,对每个子视图进行布局。
-
onDraw():绘制视图本身 (每个View都需要重载该方法,ViewGroup不需要实现该方法)。
-
drawChild():去重新回调每个子视图的draw()方法。
6.7 invalidate() 和 postInvalidate()的区别
invalidate()与postInvalidate()都用于刷新View,主要区别是invalidate()在主线程中调用,若在子线程中使用需要配合handler;而postInvalidate()可在子线程中直接调用。
7,Android进程
7.1 概念
进程(Process) 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
当一个程序第一次启动的时候,Android会启动一个LINUX进程和一个主线程。默认的情况下,所有该程序的组件都将在该进程和线程中运行。 同时,Android会为每个应用程序分配一个单独的LINUX用户。Android会尽量保留一个正在运行进程,只在内存资源出现不足时,Android会尝试停止一些进程从而释放足够的资源给其他新的进程使用, 也能保证用户正在访问的当前进程有足够的资源去及时地响应用户的事件。
我们可以将一些组件运行在其他进程中,并且可以为任意的进程添加线程。组件运行在哪个进程中是在manifest文件里设置的,其中,,和都有一个process属性来指定该组件运行在哪个进程之中。我们可以设置这个属性,使得每个组件运行在它们自己的进程中,或是几个组件共同享用一个进程,或是不共同享用。元素也有一个process属性,用来指定所有的组件的默认属性。
Android中的所有组件都在指定的进程中的主线程中实例化的,对组件的系统调用也是由主线程发出的。每个实例不会建立新的线程。对系统调用进行响应的方法——例如负责执行用户动作的View.onKeyDown()和组件的生命周期函数——都是运行在这个主线程中的。这意味着当系统调用这个组件时,这个组件不能长时间的阻塞主线程。例如进行网络操作时或是更新UI时,如果运行时间较长,就不能直接在主线程中运行,因为这样会阻塞这个进程中其他的组件,我们可以将这样的组件分配到新建的线程中或是其他的线程中运行。