一、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 之前,處於停止狀態的應用是可以收到開機廣播的。