一、Activity 的工作过程
1、根 Activity 组件的启动过程
private void attach(boolean system) {
...
if (!system) {
...
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
// Ignore
}
...
}
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
...
Looper.loop();
}
2、子 Activity 组件在进程内启动
# ActivityThread.java
private void handlePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) {
ActivityClientRecord r = mActivities.get(token);
if (r != null) {
//Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);
// 如果离开,像点击 home 键,就会调用这里
if (userLeaving) {
performUserLeavingActivity(r);
}
r.activity.mConfigChangeFlags |= configChanges;
// 这里最终会调用 Client Activity 的 onPause() 方法
performPauseActivity(token, finished, r.isPreHoneycomb());
// Make sure any pending writes are now committed.
// 等待前面的工作完成
if (r.isPreHoneycomb()) {
QueuedWork.waitToFinish();
}
// Tell the activity manager we have paused.
if (!dontReport) {
try {
// 发送一个已经进入中止状态的进程间通信
ActivityManagerNative.getDefault().activityPaused(token);
} catch (RemoteException ex) {
}
}
mSomeActivitiesChanged = true;
}
}
从上面的 handlePauseActivity 方法中可以看到会先把当前 Activity 进行 pause 完成,让后再发送一个进入中止状态的进程间通信,让子 Activity 启动。所以,不要在 onPause 中做一些耗时的操作,否则会使子 Activity 等待启动的时间过久.
二、Service 的启动过程
1、Client 组件在新进程中启动 Service
(1). Client 向 AMS 发送一个启动 Service 的进程间通信请求;
(2). AMS 发现用来运行 Service 的应用程序进程不存在,因此,它会首先将 Service 的组件信息保存下来, 接着再创建一个新的应用程序进程;
(3).新的应用程序进程启动完成之后,就会向 AMS 发送一个启动完成的进程间通行请求,以便 AMS 可以继续执行启动 Service 的操作;
(4). AMS 将第 2 步保存下来的 Service 组件信息发送到第 2 步 创建的应用程序进程,以便它可以将 Service 启动。
I. 启动时,如果版本大于 LOLLIPOP 及其以上版本, Intent 必须是显示,否则会抛出异常
// ContextImpl.java 中
private void validateServiceIntent(Intent service) {
if (service.getComponent() == null && service.getPackage() == null) {
if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
IllegalArgumentException ex = new IllegalArgumentException(
"Service Intent must be explicit: " + service);
throw ex;
} else {
Log.w(TAG, "Implicit intents with startService are not safe: " + service
+ " " + Debug.getCallers(2, 3));
}
}
}
2. Service 组件在进程内的绑定过程
(1). Activity 想 AMS 发送一个绑定 Service 组件的进程间通信请求;
(2). AMS 发现用来运行 Service 组件的应用程序进程,即 Activity 组件所运行在的应用程序进程已经存在。因此,它直接通知应用程序将 Service 启动;
(3).Service 启动后,AMS 就会请求它返回一个 Binder 本地对象,以便 Activity 可以通过这个 Binder 本地对象和 Service 建立连接;
(4). AMS 将前面从 Service 组件中获得一个 Binder 本地对象发个 Activity 组件;
(5). Activity 组件获得 AMS 给它发送的 Binder 本地对象之后,就可以通过它来获得 Service 组件的一个访问接口. Activity 组件以后可以通过这个访问接口来使用 Service 所提供的服务,这相当于将这个 Service 组件绑定在 Activity 内部。
ActivityThread.java
I.如果没有绑定过,则绑定,如果已经绑定过了,从新绑定
private void handleBindService(BindServiceData data) {
Service s = mServices.get(data.token);
...
if (s != null) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
ensureJitEnabled();
} catch (RemoteException ex) {
}
} catch (Exception e) {
...
}
}
}
三.BroadCastReceiver 的工作过程
广播机制是在 Binder 进程间通信机制的基础上实现的; 广播机制是一种基于消息发布和订阅的事件驱动模型,即广播发送者负责发布消息,而广播接收者需要先订阅消息,然后才能接收消息。
(1) 广播的注册
Activity 组件注册一个广播接受者是,并不是真的将这个广播接收者注册到 ActivityManagerService 中, 而是将与它关联的 InnerReceiver 对象注册到 AMS 中。
(2) 广播的发送过程
.在 AMS 的 broadcastIntentLocked 方法的开始添加了
// By default broadcasts do not go to stopped apps.
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
这表示在 Android 5.0 中,默认情况下,广播不会发送给已经停止的应用
Intent 的标记位
FLAG_INCLUDE_STOPPED_PACKAGES
表示包含已经停止的应用,这个时候广播会发送给已经停止的应用;
FLAG_EXCLUDE_STOPPED_PACKAGES
表示不包含已经停止的应用,这个时候广播不会发送给已经停止的应用;
从 Android 3.1 开始,系统为所有广播默认条件了 FLAG_EXCLUDE_STOPPED_PACKAGES 标志。如果确实需要调去未启动的应用,添加
FLAG_INCLUDE_STOPPED_PACKAGES 标记位即可。 两者共存时,以 FLAG_INCLUDE_STOPPED_PACKAGES 为准。
这里应用处于停止状态分两种情况: 第一种是应用安装后未运行,第二种是应用被手动或者其他应用强停了。
从 Android 3.1 开始,处于停止状态的应用无法接收到开机广播,而 3.1 之前,处于停止状态的应用是可以收到开机广播的。