Activity啟動流程詳解

分類:技術 時間:2016-10-24

流程簡介

啟動一個Activity可能是我們在Android編程中最長用的功能之一了,方式也很簡單,就是調用Context類的startActivity方法。可能有些開發者誤認為startActivity就是通過直接調用另一個Activity子類的初始化方法來喚起另一個Activity的,其實不然。

當你在使用startActivity時,這個調用會被發送給屬于系統一部分的ActivityManager一個信息。由ActivityManager來創建該Activity實例并且調用它的onCreate方法。流程如下圖:

這里寫圖片描述

有人可能會問,那系統如何知道啟動哪一個Activity的呢?答案是通過Intent這個組件,以下是摘自Android源碼的兩個最基本的Intent構造函數:

public Intent(Context packageContext, Classlt;?gt; cls) {
    mComponent = new ComponentName(packageContext, cls);
}

public Intent(String action) {
    setAction(action);
}

第一個構造函數中,ActivityManager可以獲得包名,和具體的類名,進而啟動這個Activity。第二個構造函數中,ActivityManager還可以通過一個叫action的字符串來找到對應的Activity來啟動。我們可以感受出來,通過此種架構,可以讓Activity的啟動具有更大的靈活性,也更加松耦合。既然ActivityManager是系統一部分,那在每個應用安裝時,也就需要告訴系統自己哪些部分是可以被這種方式啟動的,此時我們就有了AndroidManifest文件,所以才有了我們需要在AndroidManifest文件中聲明Activity這個組件的做法,否則就會報ActivityNotFoundException這個異常。

顯示和隱式啟動

理解了上面的流程,我們再來看下啟動的兩種方式就很簡單了,一個叫顯示啟動,一個叫隱式啟動。我們來舉兩個顯示啟動的例子

Intent intent = new Intent(this, SecondActivity.class);  
startActivity(intent);

或者

ComponentName componentName = new ComponentName(this, SecondActivity.class);  
// 或者 new ComponentName(this, quot;com.example.SecondActivityquot;);  
// 或者 new ComponentName(this.getPackageName(), quot;com.example.SecondActivityquot;);  

Intent intent = new Intent();  
intent.setComponent(componentName);  
startActivity(intent);

第一種我想大家再熟悉不過了,第二種在了解啟動流程后耶比較容易理解,如果把第一個參數的包名換成其他App的,還可以直接啟動其它App。

我們再來介紹下隱式啟動,在介紹之前,我們需要了解一個標簽 lt;intent-filtergt; ,從字面上來看,很好理解,就是用來過濾掉一些intent。讓只有具備處理特定intent的Activity才會被啟動。比如在AndroidManifest中有如下聲明:

lt;activity  
    android:name=quot;com.example.SecondActivityquot;gt;  
    lt;intent-filtergt;  
        lt;action android:name=quot;12345quot;/gt;  
        lt;category android:name=quot;android.intent.category.DEFAULTquot;/gt;  
    lt;/intent-filtergt;  
lt;/activitygt;

那么啟動該Activity除了以上介紹的顯示方法外,我們還可以用以下方法

Intent intent = new Intent(quot;12345quot;);  
intent.addCategory(quot;android.intent.category.DEFAULTquot;);  //可以不加,默認被加上
startActivity(intent);

隱式啟動是由action、category和data共同決定的,只有三者都滿足,該Activity才會被列入可處理列表,一般intent-filter包含一個action,可以包含多個category和data,所有category和某一個data滿足才行。如果你手機上多個應用同時擁有相同的intent-filter,那么就會出現一個應用列表供用戶選擇。

注:Android對待所有隱式Intent,默認它們已經具有了quot;android.intent.category.DEFAULTquot;,所以如果你想你的Activity被隱式調用,那一定需要在其intent-filter中加上該條category。不過入口Activity被quot;android.intent.action.MAINquot; 和quot;android.intent.category.LAUNCHERquot;標記的除外,雖然你也可以加上DEFAULT的category,但不是必須的

應用

學習了以上幾點后,我們來應用一下,做一個在不接入微信SDK的情況下的微信分享。你可以用apktool反編譯微信,然后通過看smali代碼和AndroidManifest文件,了解它規則后就能知道如何調用它的分享界面了。這里反編譯方法先不介紹了。經過分析,我們找到 ShareImgUI 類極為微信分享的朋友列表頁面,我們來看下它的AndroidManifest.xml中內容

lt;activity android:configChanges=quot;keyboardHidden|orientation|screenSizequot; android:icon=quot;@drawable/iconquot; android:name=quot;com.tencent.mm.ui.tools.ShareImgUIquot;gt;
            lt;intent-filter android:label=quot;@string/cquot;gt;
                lt;action android:name=quot;android.intent.action.SENDquot;/gt;
                lt;category android:name=quot;android.intent.category.DEFAULTquot;/gt;
                lt;data android:mimeType=quot;image/*quot;/gt;
                lt;data android:mimeType=quot;video/*quot;/gt;
                lt;data android:mimeType=quot;text/*quot;/gt;
                lt;data android:mimeType=quot;application/*quot;/gt;
            lt;/intent-filtergt;
            lt;intent-filter android:label=quot;@string/cquot;gt;
                lt;action android:name=quot;android.intent.action.SEND_MULTIPLEquot;/gt;
                lt;category android:name=quot;android.intent.category.DEFAULTquot;/gt;
                lt;data android:mimeType=quot;image/*quot;/gt;
            lt;/intent-filtergt;
 lt;/activitygt;

根據以上分析,對應分享代碼如下

Intent it = new Intent(Intent.ACTION_SEND);
it.setComponent(new ComponentName(quot;com.tencent.mmquot;,quot;com.tencent.mm.ui.tools.ShareImgUIquot;));
it.putExtra(Intent.EXTRA_TEXT, quot;分享成功quot;);
it.setType(quot;text/plainquot;);  //可以不要
mActivity.startActivity(Intent.createChooser(it, quot;本機未安裝微信quot;));

相信上面的代碼大家很容易就能看明白,不過有人可能會迷惑,我們已經用顯示啟動了,為什么還要用action呢,這是因為微信在代碼里判斷了action,如果你不傳入這個action就無法分享。代碼的最后一行我們為了避免微信未安裝產生ActivityNotFoundException異常,用了Intent.createChooser來處理。分享圖片視頻理論上也都是可以的,但你需要具體分析下ShareImgUI的smali代碼,讓自己傳入的數據可以被微信接受就行。分享到朋友圈也一樣道理。

寫在后面

雖然上面分析了Activity啟動流程,但該流程只是簡化版,實際的啟動流程要復雜很多,涉及到很多類。雖是簡化版,但對我們理解有關Activity間跳轉的代碼足矣。后續也為大家能繼續深入源碼級別了解這些流程提供了一點引zi


Tags: Activity

文章來源:http://www.jianshu.com/p/4d261a086e71


ads
ads

相關文章
ads

相關文章

ad