從事開發到了必定階段,想要提升就必須搞明白系統的一些工做原理。爲何?由於只有明白了這些,你才能針對平臺的特性寫出優質的代碼。當遇到棘手的問題時,你才能更快速的結合系統原理去尋找最優解決方案。底層基礎決定上層建築。這個原理在開發中一樣適用。我是提倡 迴歸基礎 的。高級的功能老是由最基本的元件構成,就比如爲數很少的元素構成了咱們不可思議的豐富的物質世界同樣。只有掌握了最根本的內容,才能促使你爆發出不可思議的創造力來!html
重視基礎,迴歸基礎。回到最初,去探尋靈感。 願與君共勉✌️!java
上圖中我把涉及到的類名方法命均列出來了,你能夠看着流程,打開源碼跟着過一遍。相信在過完一遍以後,在從此的開發中你會更加自信!android
上圖乍一看可能感受有些眼花繚亂,但請不要害怕。其實根本就沒什麼東西,你只須要從藍色箭頭開始看下去,會發現一下就看完了。在結合下面簡要的分析,3分鐘內你就能搞明白Activity的啓動流程。bash
關於Activity的啓動,我在《【拒絕一問就懵】之從Thread講到Handle》https://juejin.im/post/5cdc09aa6fb9a031f80dff23 一文中有提到過。這篇文章主要講的是Thread線程究竟是個什麼東西,以及Android中的消息機制。感興趣能夠點連接看一看。
app
Android中,一個應用程序的開始能夠說就是從ActivityThread.java中的main()方法開始的。都是學過Java的人,想必也都知道Java的程序入口就是main()方法。從這點而言,咱們能夠把它想成是一個Java程序(注意,不是說Android是個Java程序哦)去理解。框架
從上圖能夠看到,main()方法中主要作的事情有:ide
public static void main(String[] args){
...
Looper.prepareMainLooper();
//初始化Looper
...
ActivityThread thread = new ActivityThread();
//實例化一個ActivityThread
thread.attach(false);
//這個方法最後就是爲了發送出建立Application的消息
...
Looper.loop();
//主線程進入無限循環狀態,等待接收消息
}
複製代碼
2.調用attach()方法,主要就是爲了發送出初始化Application的消息。這個流程說長不長,說短不短。下文會再捋一捋。函數
上面提到過,ActivityThread的attach()方法最終的目的是發送出一條建立Application的消息——H.BIND_APPLICATION,到主線程的主Handler中。那咱們來看看attach()方法幹了啥。
attach()關鍵代碼:oop
public void attach(boolean system){
...
final IActivityManager mgr = ActivityManagerNative.getDefault();
//得到IActivityManager實例,下面會看看它是個啥
try {
mgr.attachApplication(mAppThread);
//看見沒?關鍵啊。mAppThread這個參數下面也會說一下
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
...
}
複製代碼
莫慌莫慌,下面看看上面出現的兩個對象是個啥。post
從上圖也能夠看到,IActivityManager是一個接口,當咱們調用ActivityManagerNative.getDefault()
得到的實際是一個代理類的實例——ActivityManagerProxy,這個東西實現了IActivityManager接口。打開源碼你會發現,ActivityManagerProxy是ActivityManagerNative的一個內部類。能夠看出,Android團隊在設計的過程當中是實踐了最小驚異原則的,就是把相關的東西儘可能放在一塊兒。那麼既然是個代理類,它究竟代理了誰?代碼裏看看嘍。
下面這個代碼稍微有點繞啊!老哥,穩住!
public ActivityManagerProxy(IBinder remote) {
mRemote = remote;
}
複製代碼
這個構造函數很是的簡單。首先它須要一個IBinder參數,而後賦值給mRemote變量。這個mRemote顯然是ActivityManagerProxy的成員變量,對它的操做是由ActivityManagerProxy來代理間接進行的。這樣設計的好處是保護了mRemote,而且可以在操做mRemote前執行一些別的事務,而且咱們是以IActivityManager的身份來進行這些操做的!這就很是巧妙了。
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
//先檢查一下有沒有
if (in != null) {
return in;
}
...
return new ActivityManagerProxy(obj);
//這個地方調用了構造函數
}
複製代碼
上面這個方法是ActivityManagerNative中的一個靜態方法,它會調用到ActivityManagerProxy的構造方法。然而,這個靜態方法也須要一個IBinder做爲參數!老夫被繞暈了。可是不怕,我們繼續往找!
private static final Singleton<IActivityManager> gDefault =
new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
//重點啊!IBinder實例就是在這裏得到的。
...
IActivityManager am = asInterface(b);
//調用了上面的方法。
...
return am;
}
};
複製代碼
這是ActivityManagerNative的靜態常量,它是一個單例。在其中終於得到了前面一直在用的IBinder實例。
IBinder b = ServiceManager.getService("activity");
複製代碼
試着在上圖中找到對應位置。
這裏是經過ServiceManager獲取到IBinder實例的。若是你之前瞭解AIDL通信流程的話。這可能比較好理解一點,這只是經過另外一種方式獲取IBinder實例罷了。獲取IBinder的目的就是爲了經過這個IBinder和ActivityManager進行通信,進而ActivityManager會調度發送H.BIND_APPLICATION即初始化Application的Message消息。若是以前沒接觸過Binder機制的話,只需知道這個目的就好了。我後面會寫一篇專門介紹Android中Binder機制的文章。固然,你也能夠參考一下羅大的系列文章,寫的很詳細,很是的很贊!【Android系統進程間通訊Binder機制在應用程序框架層的Java接口源代碼分析
】http://m.blog.csdn.net/article/details?id=6642463。
public void attachApplication(IApplicationThread app){
...
mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
...
}
複製代碼
這個方法我在上圖中也體現出來了。
這個方法中上面這一句是關鍵。調用了IBinder實例的tansact()方法,而且把參數app(這個參數稍後就會提到)放到了data中,最終傳遞給ActivityManager。
如今,咱們已經基本知道了IActivityManager是個什麼東東了。其實最重要的就是它的一個實現類ActivityManagerProxy,它主要代理了內核中與ActivityManager通信的Binder實例。下面再看看ApplicationThread mAppThread。
final ApplicationThread mAppThread = new ApplicationThread();
複製代碼
ApplicationThread是做爲ActivityThread中的一個常量出現的。這代表系統不但願這個變量中途被修改,可見這個變量具備特定而十分重要的做用。
private class ApplicationThread extends ApplicationThreadNative{
...
}
複製代碼
ApplicationThread是ActivityThread中的一個內部類,爲何沒有單獨出來寫在別的地方呢?我以爲這也是對最小驚異原則的實踐。由於ApplicationThread是專門真對這裏使用的對象。
public abstract class ApplicationThreadNative extends Binder implements IApplicationThread{
...
//無參構造函數
public ApplicationThreadNative() {
//這是Binder的
attachInterface(this, descriptor);
}
...
}
複製代碼
那麼很明顯,ApplicationThread最終也是一個Binder!同時,因爲實現了IApplicationThread接口,因此它也是一個IApplicationThread。以上這系對應關係你均可以在上圖中找到。
咱們在ActivityThread中看到的ApplicationThread使用的構造函數是無參的,因此看上面無參構造函數都幹了啥!
Binder的attachInterface(IInterface owner, String descriptor)方法沒什麼特別的,就是賦值了。
public void attachInterface(IInterface owner, String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}
複製代碼
4.那麼IApplicationThread又是啥?老鐵,走着!咱們繼續挖。
public interface IApplicationThread extends IInterface {
...
String descriptor = "android.app.IApplicationThread";
//留意下這個參數
...
}
複製代碼
好吧,這在上圖中沒有,挖的有點什麼了。可是學習嘛,咱就看看嘍。
IApplicationThread是繼承了IInterface的一個接口,咱們須要關注一下里面的descriptor參數。後面會用它,它是一個標識,查詢的時候很重要。
好,咱們終於知道attach()方法中出現的兩個對象是啥了。ApplicationThread做爲IApplicationThread的一個實例,承擔了最後發送Activity生命週期、及其它一些消息的任務。也就是說,前面繞了一大圈,最後仍是回到這個地方來發送消息。我擦!
也許你會想,既然在ActivityThread中咱們已經建立出了ApllicationThread的了,爲何還要繞這麼彎路?,固然是爲了讓系統根據狀況來控制這個過程嘍,否則爲何要把ApplicationThread傳到ActivityManager中呢?
通過上面的展轉,ApplicationThread終於到了ActivityManagerService中了。請在上圖中找到對應位置!
從上圖中能夠看到,ActivityManagerService中有一這樣的方法:
private final boolean attachApplicationLocked(IApplicationThread thread , int pid) {
...
thread.bindApplication();
//注意啦!
...
}
複製代碼
ApplicationThread以IApplicationThread的身份到了ActivityManagerService中,通過一系列的操做,最終被調用了本身的bindApplication()方法,發出初始化Applicationd的消息。
public final void bindApplication(String processName, ApplicationInfo appInfo, List<ProviderInfo> providers, ComponentName instrumentationName, ProfilerInfo profilerInfo, Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, IUiAutomationConnection instrumentationUiConnection, int debugMode, boolean enableBinderTracking, boolean trackAllocation, boolean isRestrictedBackupMode, boolean persistent, Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings){
...
sendMessage(H.BIND_APPLICATION, data);
}
複製代碼
嚇屎老紙!這麼多參數。這明明很違反參數儘可能要少的原則嘛!因此說,有的時候,開發過程當中仍是很難避免一些參數堆積的狀況的。也不能一律而論。
可是,這個地方,咱們只要知道最後發了一條H.BIND_APPLICATION消息,接着程序開始了。
上面咱們已經找到初始化Applicaitond的消息是在哪發送的了。如今,須要看一看收到消息後都發生了些什麼。
如今上圖的H下面找到第一個消息:H.BIND_APPLICATION。一旦接收到這個消息就開始建立Application了。這個過程是在handleBindApplication()中完成的。看看這個方法。在上圖中能夠看到對應的方法。
private void handleBindApplication(AppBindData data) {
...
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName())
.newInstance();
//經過反射初始化一個Instrumentation儀表。後面會介紹。
...
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
//經過LoadedApp命令建立Application實例
mInitialApplication = app;
...
mInstrumentation.callApplicationOnCreate(app);
//讓儀器調用Application的onCreate()方法
...
}
複製代碼
handleBindApplication()是一個很長的方法,可是我爲各位看官精選出了上面這幾句代碼。對於本篇的主題來講,他們是相當重要的。上面短短的代碼中出現了幾個新對象。下面我會一一道來。
1.這個叫Instrumentation儀表的東西十分詭異,姑且翻譯爲儀器吧。字面上看不出任何它是幹什麼的線索。可是,咱們能夠打開文檔看看嘍。
Instrumentation會在應用程序的任何代碼運行以前被實例化,它可以容許你監視應用程序和系統的全部交互。
大概就這個意思啦。
2.可是,從上面的代碼咱們能夠看出,Instrumentation確實是在Application初始化以前就被建立了。那麼它是如何實現監視應用程序和系統交互的呢?
打開這個類你能夠發現,最終Apllication的建立,Activity的建立,以及生命週期都會通過這個對象去執行。簡單點說,就是把這些操做包裝了一層。經過操做Instrumentation進而實現上述的功能。
3.那麼這樣作究竟有什麼好處呢?仔細想一想。Instrumentation做爲抽象,當咱們約定好須要實現的功能以後,咱們只須要給Instrumentation儀表添加這些抽象功能,而後調用就好。剩下的,無論怎麼實現這些功能,都交給Instrumentation儀器的實現對象就好。啊!這是多態的運用。啊!這是依賴抽象,不依賴具體的實踐。啊!這是上層提出需求,底層定義接口,即依賴倒置原則的踐行。呵!抽象不過如此。
從代碼中能夠看到,這裏實例化Instrumentation的方法是反射!而反射的ClassName是來自於從ActivityManagerService中傳過來的Binder的。套路太深!就是爲了隱藏具體的實現對象。可是這樣耦合性會很低。
4.好了,不瞎扯了。既然在說Instrumentation,那就看看最後調的callApplicationOnCreate()方法。
public void callApplicationOnCreate(Application app) {
app.onCreate();
}
複製代碼
你沒看錯,它啥也沒幹。只是調用了一下Application的onCreate()方法。這就是爲何它可以起到監控的做用。
在上圖中你可以看到Instrumentation,以及它的交互過程。
關於它是怎麼來的本篇就不說了,之後可能會介紹下。本篇就看流程就好。因此直接進去看它的makeApplication()幹了啥,就把Application給建立了。
public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {
...
String appClass = mApplicationInfo.className;
//Application的類名。明顯是要用反射了。
...
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread
, this);
//留意下Context
app = mActivityThread.mInstrumentation
.newApplication( cl, appClass, appContext);
//經過儀表建立Application
...
}
複製代碼
在這個方法中,咱們須要知道的就是,在取得Application的實際類名以後,最終的建立工做仍是交由Instrumentation去完成,就像前面所說的同樣。
值得留意的是,就像上圖所標註的同樣,當須要第二次獲取Application時,一樣只須要調用這個方法就好。「真是方便!」
看看newApplication()中是如何完成Application的建立的。
static public Application newApplication(Class<?> clazz , Context context) throws InstantiationException , IllegalAccessException , ClassNotFoundException {
Application app = (Application)clazz.newInstance();
//反射建立,簡單粗暴
app.attach(context);
//關注下這裏,Application被建立後第一個調用的方法。
//目的是爲了綁定Context。
return app;
}
複製代碼
個人天,繞了這麼多,這Application可算是建立出來了。快給本身一個小紅花吧!
當Application初始化完成後,系統會更具Manifests中的配置的啓動Activity發送一個Intent去啓動相應的Activity。這個過程本篇先不提,下次再說。主要看流程!
private void handleLaunchActivity(ActivityClientRecord r , Intent customIntent , String reason) {
...
Activity a = performLaunchActivity(r, customIntent);
//媽蛋!又封裝到另外一個方法中建立了。
...
if (a != null) {
...
handleResumeActivity(r.token
, false
, r.isForward
,!r.activity.mFinished && !r.startsNotResumed
, r.lastProcessedSeq, reason);
//Activity建立成功就往onResume()走了!
...
}
}
複製代碼
從上面的代碼中能夠看出...好吧,什麼都看不出來!
private Activity performLaunchActivity(ActivityClientRecord r , Intent customIntent) {
...
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
//經過儀表來建立Activity
...
Application app = r.packageInfo.makeApplication(false
, mInstrumentation);
//前面說過,是在獲取Application
...
activity.attach(appContext
, this
, getInstrumentation()
, r.token
,.ident
, app
, r.intent
, r.activityInfo
, title
, r.parent
, r.embeddedID
, r.lastNonConfigurationInstances
, config
,r.referrer
, r.voiceInteractor
, window);
//方法怪出現!
...
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(
activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
//根據是否可持久化選擇onCreate()方法。
...
}
複製代碼
這個方法內容較多,咱們一個個看。
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
複製代碼
正如前面所說,Activity、Application的建立及生命週期都被承包給Instrumentation儀表了。因此由它來負責。看看Instrumentation幹了啥。
public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException , IllegalAccessException, ClassNotFoundException {
return (Activity)cl.loadClass(className).newInstance();
//真的沒幹啥。反射實例化Activity而已
}
複製代碼
就是反射出一個Activity而已。
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(
activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
複製代碼
根據是否可持久化選擇Activity的onCreate()方法。一樣是經過Instrumentation儀表來執行onCreate()的。它兩分別對應的onCreate()方法爲:
onCreate(icicle, persistentState);
//可得到持久化數據
複製代碼
和
onCreate(icicle);
//平時重寫的最多的。
複製代碼
中間兩個方法留意一下就好,就不在解釋的,感興趣的點源碼看看。
到此,Activity就跑起來了!怎麼樣?是否是並不複雜。
本篇就到此結束了。本篇主要流程是從Application建立開始,到第一個Activity onCreate()結束的。這了流程也不算長,關鍵是結合上面的圖來看。重點環節我都用不一樣的顏色標記出來了。
看到這裏的同窗獎勵本身一包辣條吧!
【Android系統進程間通訊Binder機制在應用程序框架層的Java接口源代碼分析
】http://m.blog.csdn.net/article/details?id=6642463
【Instrumentation API】https://developer.android.com/reference/android/app/Instrumentation.html
【ActivityManager API】https://developer.android.com/reference/android/app/ActivityManager.html
感謝你的閱讀。若是你以爲對你有用的話,記得給CoorChice點個贊,添加下關注哦,謝謝!