Activity啓動模式聯想到多進程相關的一些東西

看到這個題目估計又有人說我標題黨了,啓動模式跟多進程有什麼關係,沒啥關係,我只是在寫Activity啓動模式的demo的時候,用到了多進程進行測試,順便一塊兒交代一下。java


Task與Process

不知道有沒有人想固然的混淆上述兩個概念,我是見過有這樣想的開發者。android

Task

Task就是一堆Activity的集合,你能夠這樣想,一個棧中,有多個Activity,當用戶在多個activity之間跳轉時,執行壓棧操做,當用戶按返回鍵時,執行出棧操做。 在作測試以前,咱們須要先介紹一下Task相關的代碼。 在Activity中,直接調用getTaskId()能夠獲取當前Activity所在的Task_id。 咱們也能夠調用系統方法,獲取Task的相關信息:git

public static void getTask(Context context){
        ActivityManager  mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<AppTask> list =  mAm.getAppTasks();
        for (AppTask appTask:list){
            Log.e("Utils",context.getClass().getName()+" "+appTask.getTaskInfo().affiliatedTaskId+"的num = "+appTask.getTaskInfo().numActivities);

        }
    }
複製代碼

standard

咱們設置四個Activity,每一個Activity的啓動模式都設置成standard。來看一下Task的相關狀況。 github

上圖是用上面介紹的代碼完成的一個demo,從第一個Actvity切換到第四個Activity,每增長一個ActivityTask都會增長一個Activity,若是按返回鍵,即銷燬一個Activity,根據上圖所知,ActivityTask會減小一個。若是不斷的startActivity則ActivityTask數量不斷增長。shell

singleTask

咱們設置四個Activity,每一個Activity的啓動模式都設置成singleTask。來看一下Task的相關狀況。 bash

由上圖可知,若是一個activity的啓動模式爲singleTask,那麼Task棧中將會只有一個該Activity的實例。因此從第一個activity,跳到第四個Activity,再跳回第一個的時候,只是將第一個Activity啓動了,同時調用了第一個Activity的onNewIntent 這裏還有一個有趣的事,注意觀察上圖,再回到第一個Activity的時候,Task中Activity的數量變爲了1,也就是singleTask除了啓動了第一個Activity,並將第一個Activity順序之上的activity所有銷燬了。app

singleTop

咱們設置四個Activity,每一個Activity的啓動模式都設置成singleTop。來看一下Task的相關狀況。 ide

根據上圖可知,你可能感受這個跟standard模式沒什麼區別啊,的確是這樣的,若是被啓動的Activity不處於棧頂,那麼跟standard沒有什麼區別,當要啓動的Activity處於棧頂,不會再次建立這個Activity的實例,而是重用原來的實例,而且調用原來實例的onNewIntent()方法。

singleInstance

咱們設置四個Activity,每一個Activity的啓動模式都設置成singleInstance。來看一下Task的相關狀況。 測試

由上圖可知,此次的變化是很明顯的。每次啓動Activity都會從新建立一個Task,而且這個Task中只有這一個實例。也就是說被該實例啓動的其餘activity會自動運行於另外一個任務中。當再次啓動該activity的實例時,會重用已存在的任務和實例。而且會調用這個實例的onNewIntent()方法。

Process

如今聊一下與進程相關的東西this

taskAffinity屬性

首先先說的是taskAffinity,爲何在Process標題下聊taskAffinity,由於進程間咱們能夠看到的taskAffinity屬性,更明顯的特性。 接着須要引出的概念就是taskAffinity,taskAffinity表示當前activity具備親和力的一個Task,能夠這樣理解, taskAffinity表示一個Task的名字,這個Task就是當前activity所在的Task。一個Task的taskAffinity取決於跟Activity的taskAffinity。 若是一個Activity沒有顯式的指明該 Activity的taskAffinity,那麼它的這個屬性就等於Application指明的taskAffinity,若是 Application也沒有指明,那麼該taskAffinity的值就等於包名。 如今來示範一個例子(全部的例子,都有demo,在文章的最後),新建兩個應用,app,app2,每一個應用都有MainActivity,和SecondActivity,從MainActivity能夠跳到SecondActivity,爲了方便描述,咱們appMain,appSecond,app2Main,app2Second來代替。 咱們將appSecond和app2Second設置成一樣的taskAffinity:

<activity android:name=".MainActivity"
                  android:launchMode="standard">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity android:name=".SecondActivity"
                  android:taskAffinity="com.deep"
                >

        </activity>
複製代碼

啓動這兩個Activity,發現沒有什麼特殊效果,appSecond都在各自應用的應用根Activity的Task中。 這時咱們改一下代碼將appSecond設置成singleTask,這樣appSecond所在的Task就是帶有taskAffinity屬性的了。 而後這時咱們再啓動app2Second:

由圖可知,app2Second仍然在app2Main的Task中,這是因爲app2Second的啓動模式是標準,沒有自主選擇task的能力,咱們再將app2Second改爲singleTask:
而後使用 adb shell dumpsys activity activities查看一下activity的堆棧信息:
#733 與#734標識的爲Task,與上面app截圖不一樣是因爲,我又運行了一次,因此Task id增長了,可是Activity與Task的歸屬關係是同樣的。 因此咱們發現app2Second所在的task跟appSecond所在的task同樣了,這說明app2Second能夠根據taskAffinity選擇Task了,並且這個Task還能夠不是當前Process。

多進程

關於多進程,能夠共用Task的例子,也能夠這樣證實:

<activity android:name=".MainActivity"
                  android:launchMode="standard">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity android:name=".SecondActivity"
                  android:process="com.deep1"
                  android:launchMode="standard"

                     >

        </activity>
        <activity android:name=".ThirdActivity"
                  android:process="com.deep2"
                  android:launchMode="standard">

        </activity>
        <activity android:name=".FourthActivity"
                  android:launchMode="standard">

        </activity>
複製代碼

在一個app中啓用多進程,但全部的Activity都是標準模式,能夠發現,全部的Activity都在同一個Task中。

全局變量的訪問

Activity均可以設置進程的歸屬關係,可是若是不是Activity,而是一個全局變量呢?能夠試一下,咱們創建一個全局變量:

public class StaticParam {
    public static String a = "default";
    public static Object o = new Object();
}
複製代碼

首先在Application中初始化:

@Override
    public void onCreate() {
        super.onCreate();
        StaticParam.a ="init";
        Log.e("xxxxxx","application:"+Utils.getCurProcessName(this)+ " "+StaticParam.a.getClass().toString());
    }
複製代碼

而後在上面例子中的四個Activity中的onCreate添加以下代碼:

StaticParam.a = StaticParam.a+ " "+getClass().getSimpleName();
Log.e("xxxxxx","a="+StaticParam.a+" "+StaticParam.o+" "+Utils.getCurProcessName(this));
複製代碼

執行一遍全部的activity,看一下效果:

12-27 10:56:32.993 31195-31195/umeng.com.testlauncher E/xxxxxx: application:umeng.com.testlauncher    class java.lang.String
12-27 10:56:33.053 31195-31195/umeng.com.testlauncher E/xxxxxx: a=init MainActivity      java.lang.Object@76794cc    umeng.com.testlauncher
12-27 10:56:40.000 31325-31325/? E/xxxxxx: application:com.deep1    class java.lang.String
12-27 10:56:40.057 31325-31325/? E/xxxxxx: a=init SecondActivity      java.lang.Object@76794cc    com.deep1
12-27 10:56:49.618 31486-31486/com.deep2 E/xxxxxx: application:com.deep2    class java.lang.String
12-27 10:56:49.674 31486-31486/com.deep2 E/xxxxxx: a=init ThirdActivity      java.lang.Object@76794cc    com.deep2
12-27 10:56:51.202 31195-31195/umeng.com.testlauncher E/xxxxxx: a=init MainActivity FourthActivity      java.lang.Object@76794cc    umeng.com.testlauncher
複製代碼

根據log,咱們發現幾個問題:

  • 當從MainActivity跳到SecondActivity的時候,因爲SecondActivity屬於進程com.deep1,因此會在com.deep1 進程中再次執行Application的初始化。
  • MainActivity已經將StaticParam.a置成了a=init MainActivity可是SecondActivity添加了本身的名字倒是a=init SecondActivity,等到與MainActivity同進程的FourthActivity的時候,又變回a=init MainActivity FourthActivity,這說明全局靜態變量在各個進程間是不通用的,每一個進程各自維護各自的,互不干擾。

總結

demo地址:https://github.com/mymdeep/activityTest 暫時就想到了這些,寫的有點亂,想到哪寫到哪,若有問題,歡迎進一步討論 也歡迎關注個人公衆號,以後會推薦更多好用的組件庫。

相關文章
相關標籤/搜索