Activity启动流程简述
-
执行startActivity
-
通过IBinder远程调用AMS.startActivity。AMS通过ActivityStack来启动Activity,会处理任务栈的切换,同时通知对应Activity所在ApplicationThread进行生命周期调度。
-
调度的时候如果不是自己的Activity,并且如果之前没有运行过,则会创建ActivityThread进程,执行Application的初始化
-
然后再启动Activity
应用启动简化时序图

Activity与PhoneWindow及View之间的关系
attach()方法主要做了什么
对Activity中的成员变量进行初始化等相关操作。
必须在onCreate()方法执行之前调用,否则onCreate方法会报错。
比如onCreate()方法中调用setContentView方法设置要显示的View时,需要依赖一个Window对象,这个Window对象就是在attach()方法中来进行初始化的。
Activity的View的显示过程梳理
首先,Activity的attach()方法被调用了,在attach()方法中,完成了Window的初始化相关工作:
frameworks\base\core\java\android\app\Activity.java
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
Object lastNonConfigurationInstance,
HashMap<String,Object> lastNonConfigurationChildInstances,
Configuration config) {
……
// 初始化Window对象
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
// 其他成员变量的一些初始化操作……
}
创建Window对象的方法如下:
frameworks\base\core\java\com\android\internal\policy\PolicyManager.java
private static final IPolicy sPolicy;
public static Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}
sPolicy是一个IPolicy对象,其实现类为:Policy.java
frameworks\base\policy\src\com\android\internal\policy\impl\Policy.java
public PhoneWindow makeNewWindow(Context context) {
return new PhoneWindow(context);
}
由这里我们可以看到,我们的makeNewWindow方法实际上返回的是一个PhoneWindow的对象。
简单的看一下PhoneWindow的继承关系:
frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindow.java
public class PhoneWindow extends Window implements MenuBuilder.Callback {
……
}
PhoneWindow是Window类的一个子类,我们在Activity里用到的Window对象,实际上一个PhoneWindow对象。相应的,我们调用的Window对象的方法,实际上也就是在调用PhoneWindow对象中相应的实现方法。
在attach()方法调用完毕后,onCreate方法将被调用,在onCreate方法中,我们往往会先调用setContentView方法,来将View展示到Activity上面:
frameworks\base\core\java\android\app\Activity.java
public void setContentView(int layoutResID) {
getWindow().setContentView(layoutResID);
}
public void setContentView(View view) {
getWindow().setContentView(view);
}
public void setContentView(View view, ViewGroup.LayoutParams params) {
getWindow().setContentView(view, params);
}
由上方代码我们可以看到,我们在Activity的onCreate方法中调用setContentView,实际上是调用了Window的setContentView,也就是PhoneWindow对象的setContentView方法:
frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindow.java
private ViewGroup mContentParent;
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null) {
cb.onContentChanged();
}
}
@Override
public void setContentView(View view) {
setContentView(view,
new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (mContentParent == null) {
installDecor();
} else {
mContentParent.removeAllViews();
}
mContentParent.addView(view, params);
final Callback cb = getCallback();
if (cb != null) {
cb.onContentChanged();
}
}
上方代码可得到结论:
-
如果mContentParent是null的,则通过调用installDecor()方法初始化mContentParent;如果mContentParent不是null的,则调用removeAllViews()将里面其他的子View先清空;
-
setContentView中,无论传递的是一个layout id,还是一个View,他都将会以addView的形式被添加到mContentParent这个容器中去;
注意:mLayoutInflater.inflate(layoutResID, mContentParent); 实际上底层也是调用的addView方法
installDecor()方法在初始化mContentParent时进行了如下操作:
frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindow.java
private DecorView mDecor;
private void installDecor() {
if (mDecor == null) {
mDecor = generateDecor();
……
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
……
}
}
由上方代码可知,我们是通过一个mDecor来实现的mContentParent对象初始化操作,mDecor实际上是一个DecorView的对象。DecorView定义如下:
private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {
……
}
由DecorView类的定义,我们可以知道,DecorView实际上就是一个FrameLayout的子类。
那么,我们在构建mContentParent的时候,又进行了哪些操作,为什么会用到DecorView?
frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindow.java
protected ViewGroup generateLayout(DecorView decor) {
// 根据当前Activity的Theme,初始化一些页面显示
……
if (a.getBoolean(com.android.internal.R.styleable.Window_windowNoTitle, false)) {
requestFeature(FEATURE_NO_TITLE);
}
……
// 填充DecorView……
int layoutResource; // 将被填充进DecorView的View的layout id
……
// 一系列的if else判断,决定layoutResource应该是哪个layout id
……
layoutResource = com.android.internal.R.layout.screen_title;
……
// 填充layoutResource对应的View,并add进DecorView中
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in,
new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
// 获取其中ID_ANDROID_CONTENT对应的ViewGroup
// 这个ViewGroup其实就是我们的mContentParent
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
……
// 返回mContentParent
return contentParent;
}
系统的layout:layout.screen_title
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:fitsSystemWindows="true">
<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>
上方可知,我们在setContentView时,实际上是将我们想要展示的View用addView的方式添加到一个mContentParent中,而mContentParent实际上是DecorView里面的一个FrameLayout。
结论:
DecorView为整个Window界面的最顶层View,它包含一个头布局(其实是我们Activity的TitleBar),以及一个FrameLayout布局。我们在Activity中通过setContentView设置的想展示的Layout,实际被add到了这个FrameLayout中。
在handleResumeActivity的时候会将DecorView添加到WindowManager上并显示出来(Activity : makeVisible()方法)。

Activity、PhoneWindow、View之间的关系
Activity通过调用setContentView将View添加到PhoneWindow中,显示到界面上。
线程与进程
Linux下有真正意义的多线程么
没有,Linux并不是遵循标准的线程设计模型。

核心级线程设计模型:操作系统内核实现了线程模型,特点:线程的调度着在内核中(windows)

用户级线程设计模型:操作系统核外实现的线程模式,如在系统类库层、框架层。特点:线程的调度着在核外(Linux)
Linux系统的两个线程库:
-
LinuxThreads线程库
-
RedHat的NPTL(Native POSIX Thread Library )线程库(资料)
Android中进程的5种优先级
Google官方文档给出的介绍
<u>http://developer.android.com/intl/zh-cn/guide/components/processes-and-threads.html</u>
进程生命周期
Android 系统将尽量长时间地保持应用进程,但为了新建进程或运行更重要的进程,最终需要清除旧进程来回收内存。 为了确定保留或终止哪些进程,系统会根据进程中正在运行的组件以及这些组件的状态,将每个进程放入“重要性层次结构”中。 必要时,系统会首先消除重要性最低的进程,然后是重要性略逊的进程,依此类推,以回收系统资源。
重要性层次结构一共有 5 级。以下列表按照重要程度列出了各类进程(第一个进程最重要,将是最后一个被终止的进程):
- 前台进程
用户当前操作所必需的进程。如果一个进程满足以下任一条件,即视为前台进程:
o 托管用户正在交互的 <u>Activity</u>(已调用 <u>Activity</u> 的 <u>onResume()</u> 方法)
o 托管某个 <u>Service</u>,后者绑定到用户正在交互的 Activity
o 托管正在“前台”运行的 <u>Service</u>(服务已调用 [<u>startForeground()</u>](#startForeground(int, android.app.Notification)))
o 托管正执行一个生命周期回调的 <u>Service</u>(<u>onCreate()</u>、[<u>onStart()</u>](#onStart(android.content.Intent, int)) 或 <u>onDestroy()</u>)
o 托管正执行其 [<u>onReceive()</u>](#onReceive(android.content.Context, android.content.Intent)) 方法的 <u>BroadcastReceiver</u>
通常,在任意给定时间前台进程都为数不多。只有在内存不足以支持它们同时继续运行这一万不得已的情况下,系统才会终止它们。 此时,设备往往已达到内存分页状态,因此需要终止一些前台进程来确保用户界面正常响应。
- 可见进程
没有任何前台组件、但仍会影响用户在屏幕上所见内容的进程。 如果一个进程满足以下任一条件,即视为可见进程:
o 托管不在前台、但仍对用户可见的 <u>Activity</u>(已调用其 <u>onPause()</u> 方法)。例如,如果前台 Activity 启动了一个对话框,允许在其后显示上一 Activity,则有可能会发生这种情况
o 托管绑定到可见Activity 的 <u>Service</u>
可见进程被视为是极其重要的进程,除非为了维持所有前台进程同时运行而必须终止,否则系统不会终止这些进程。
- 服务进程
正在运行已使用 <u>startService()</u> 方法启动的服务且不属于上述两个更高类别进程的进程。尽管服务进程与用户所见内容没有直接关联,但是它们通常在执行一些用户关心的操作(例如,在后台播放音乐或从网络下载数据)。因此,除非内存不足以维持所有前台进程和可见进程同时运行,否则系统会让服务进程保持运行状态。
- 后台进程
包含目前对用户不可见的 Activity 的进程(已调用 Activity 的 <u>onStop()</u> 方法)。这些进程对用户体验没有直接影响,系统可能随时终止它们,以回收内存供前台进程、可见进程或服务进程使用。 通常会有很多后台进程在运行,因此它们会保存在 LRU (最近最少使用)列表中,以确保包含用户最近查看的 Activity 的进程最后一个被终止。如果某个 Activity 正确实现了生命周期方法,并保存了其当前状态,则终止其进程不会对用户体验产生明显影响,因为当用户导航回该 Activity 时,Activity 会恢复其所有可见状态。 有关保存和恢复状态的信息,请参阅<u>Activity</u>文档。
- 空进程
不含任何活动应用组件的进程。保留这种进程的的唯一目的是用作缓存,以缩短下次在其中运行组件所需的启动时间。 为使总体系统资源在进程缓存和底层内核缓存之间保持平衡,系统往往会终止这些进程。
根据进程中当前活动组件的重要程度,Android 会将进程评定为它可能达到的最高级别。例如,如果某进程托管着服务和可见 Activity,则会将此进程评定为可见进程,而不是服务进程。
此外,一个进程的级别可能会因其他进程对它的依赖而有所提高,即服务于另一进程的进程其级别永远不会低于其所服务的进程。 例如,如果进程 A 中的内容提供程序为进程 B 中的客户端提供服务,或者如果进程 A 中的服务绑定到进程 B 中的组件,则进程 A 始终被视为至少与进程 B 同样重要。
由于运行服务的进程其级别高于托管后台 Activity 的进程,因此启动长时间运行操作的 Activity 最好为该操作启动<u>服务</u>,而不是简单地创建工作线程,当操作有可能比 Activity 更加持久时尤要如此。例如,正在将图片上传到网站的 Activity 应该启动服务来执行上传,这样一来,即使用户退出 Activity,仍可在后台继续执行上传操作。使用服务可以保证,无论 Activity 发生什么情况,该操作至少具备“服务进程”优先级。 同理,广播接收器也应使用服务,而不是简单地将耗时冗长的操作放入线程中。
网友评论