activity的啓動模式有哪些?是什麼含義?(一)

Activity的四種啓動模式如下:

standard、singleTop、singleTask、singleInstance

我們一邊講理論一邊結合案例來全面學習這四種啓動模式。
爲了打印方便,定義一個基礎BaseActivity,在其onCreate方法和onNewIntent方法中打印出當前Activity的日誌信息,主要包括所屬的task,當前類的hashcode,之後我們進行測試的Activity都直接繼承該BaseActivity

public class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.i("maweiqi", "*****onCreate()方法******");
        Log.i("maweiqi", "onCreate:" + getClass().getSimpleName() + " TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
        dumpTaskAffinity();
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.i("maweiqi", "*****onNewIntent()方法*****");
        Log.i("maweiqi", "onNewIntent:" + getClass().getSimpleName() + " TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
        dumpTaskAffinity();
    }

    protected void dumpTaskAffinity(){
        try {
            ActivityInfo info = this.getPackageManager()
                    .getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
            Log.i("maweiqi", "taskAffinity:"+info.taskAffinity);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
    }
}

standard-默認模式

這個模式是默認的啓動模式,即標準模式,在不指定啓動模式的前提下,系統默認使用該模式啓動Activity,每次啓動一個Activity都會重寫創建一個新的實例,不管這個實例存不存在,這種模式下,誰啓動了該模式的Activity,該Activity就屬於啓動它的Activity的任務棧中。

配置形式:

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

使用案例:

對於standard模式,android:launchMode可以不進行聲明,因爲默認就是standard。 SecondActivity的代碼如下,入口MainActivity中有一個按鈕進入該Activity,這個Activity中又有一個按鈕啓動SecondActivity。

public class MainActivity extends BaseActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Button btn_standard= (Button)   findViewById(R.id.btn_standard);
    btn_standard.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
       Intent intent = new Intent(MainActivity.this, SecondActivity.class);
       startActivity(intent);
    }
   });
        Log.i("maweiqi", "*****onCreate()方法******");
        Log.i("maweiqi", "onCreate:" + getClass().getSimpleName() + " TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
    }
}
public class SecondActivity extends BaseActivity {
    private Button jump;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        jump= (Button) findViewById(R.id.button3);
        jump.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(SecondActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });
    }

}

我們首先從MainActivity進入SecondActivity ,進入後再點擊進入SecondActivity,連續進入四次SecondActivity 。

輸出的日誌如下:

  MainActivity TaskId: 2 hasCode:1249333352
SecondActivity TaskId: 2 hasCode:1249526392
SecondActivity TaskId: 2 hasCode:1249424816
SecondActivity TaskId: 2 hasCode:1249439692
SecondActivity TaskId: 2 hasCode:1249459968

可以看到日誌輸出了四次SecondActivity的和一次MainActivity的,從MainActivity進入StandardActivity一次,後來我們又按了三次按鈕,總共四次SecondActivity的日誌,並且所屬的任務棧的id都是2,這也驗證了誰啓動了該模式的Activity,該Activity就屬於啓動它的Activity的任務棧中這句話.因爲啓動SecondActivity的是MainActivity,而MainActivity的taskId是2,因此啓動的SecondActivity也應該屬於id爲2的這個task,後續的3個SecondActivity是被SecondActivity這個對象啓動的,因此也應該還是2,所以taskId都是2。並且每一個Activity的hashcode都是不一樣的,說明他們是不同的實例,即“每次啓動一個Activity都會重寫創建一個新的實例”

singleTop模式

這個模式下,如果新的activity已經位於棧頂,那麼這個Activity不會被重新創建,同時它的onNewIntent方法會被調用,通過此方法的參數我們可以去除當前請求的信息。如果棧頂不存在該Activity的實例,則情況與standard模式相同。需要注意的是這個Activity它的onCreate(),onStart()方法不會被調用,因爲它並沒有發生改變。

配置形式:

<activity android:name=".SingleTopActivity" android:launchMode="singleTop"/>
<activity android:name=".OtherTopActivity" android:launchMode="singleTop"/>

使用案例:

public class SingleTopActivity extends BaseActivity {
    private Button jump, jump2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_singletop);

        jump = (Button) findViewById(R.id.button);
        jump2 = (Button) findViewById(R.id.button2);
        jump.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(SingleTopActivity.this, SingleTopActivity.class);
                startActivity(intent);
            }
        });
        jump2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(SingleTopActivity.this, OtherTopActivity.class);
                startActivity(intent);
            }
        });
        Log.i("maweiqi", "*****onCreate()方法******");
        Log.i("maweiqi", "onCreate:" + getClass().getSimpleName() + " TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
    }
}
public class OtherTopActivity extends AppCompatActivity {
    private Button jump;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_other);

        jump= (Button) findViewById(R.id.btn_other);
        jump.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(OtherTopActivity.this, SingleTopActivity.class);
                startActivity(intent);
            }
        });
        Log.i("maweiqi", "*****onCreate()方法******");
        Log.i("maweiqi", "onCreate:" + getClass().getSimpleName() + " TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
    }
}

操作和standard模式類似,直接貼輸出日誌

onCreateMainActivity TaskId: 3 hasCode:1249332216
onCreateSingleTopActivity TaskId: 3 hasCode:1249464444
onNewIntentSingleTopActivity TaskId: 3 hasCode:1249464444
onNewIntentSingleTopActivity TaskId: 3 hasCode:1249464444
onNewIntentSingleTopActivity TaskId: 3 hasCode:1249464444

我們看到,除了第一次進入SingleTopActivity這個Activity時,輸出的是onCreate方法中的日誌,後續的都是調用了onNewIntent方法,並沒有調用onCreate方法,並且四個日誌的hashcode都是一樣的,說明棧中只有一個實例。這是因爲第一次進入的時候,棧中沒有該實例,則創建,後續的三次發現棧頂有這個實例,則直接複用,並且調用onNewIntent方法。那麼假設棧中有該實例,但是該實例不在棧頂情況又如何呢?
我們先從MainActivity中進入到SingleTopActivity,然後再跳轉到OtherActivity中,再從OtherActivity中跳回SingleTopActivity,再從SingleTopActivity跳到SingleTopActivity中,看看整個過程的日誌。

輸出的日誌如下:

onCreateSingleTopActivity TaskId: 4 hasCode:1249520904
onCreateOtherTopActivity TaskId: 4 hasCode:1249420244
onCreateSingleTopActivity TaskId: 4 hasCode:1249448776
onCreateSingleTopActivity TaskId: 4 hasCode:1249448776
onNewIntentSingleTopActivity TaskId: 4 hasCode:1249448776

我們看到從MainActivity進入到SingleTopActivity時,新建了一個SingleTopActivity對象,然後從SingleTopActivity跳到OtherActivity時,新建了一個OtherActivity,此時task中存在三個Activity,從棧底到棧頂依次是MainActivity,SingleTopActivity,OtherActivity,此時如果再跳到SingleTopActivity,即使棧中已經有SingleTopActivity實例了,但是依然會創建一個新的SingleTopActivity實例,這一點從上面的日誌的hashCode可以看出,此時棧頂是SingleTopActivity,如果再跳到SingleTopActivity,就會複用棧頂的SingleTopActivity,即會調用SingleTopActivity的onNewIntent方法。這就是上述日誌的全過程。

對以上內容進行總結

standard啓動模式是默認的啓動模式,每次啓動一個Activity都會新建一個實例不管棧中是否已有該Activity的實例。

singleTop模式分3種情況

1)當前棧中已有該Activity的實例並且該實例位於棧頂時,不會新建實例,而是複用棧頂的實例,並且會將Intent對象傳入,回調onNewIntent方法

2)當前棧中已有該Activity的實例但是該實例不在棧頂時,其行爲和standard啓動模式一樣,依然會創建一個新的實例

3)當前棧中不存在該Activity的實例時,其行爲同standard啓動模式standard和singleTop啓動模式都是在原任務棧中新建Activity實例,不會啓動新的Task

singleTask模式

在這個模式下,如果棧中存在這個Activity的實例就會複用這個Activity,不管它是否位於棧頂,複用時,會將它上面的Activity全部出棧,並且會回調該實例的onNewIntent方法。

配置形式:

<activity android:name=".SingleTaskActivity" android:launchMode="singleTask"/>
<activity android:name=".OtherTaskActivity" android:launchMode="singleTask"/>

使用案例:

public class SingleTaskActivity extends BaseActivity {
    private Button jump,jump2;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_task);

        jump = (Button) findViewById(R.id.btn_task);
        jump2 = (Button) findViewById(R.id.btn_other);
        jump.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(SingleTaskActivity.this, SingleTaskActivity.class);
                startActivity(intent);
            }
        });
        jump2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(SingleTaskActivity.this, OtherTaskActivity.class);
                startActivity(intent);
            }
        });
    }
}
public class OtherTaskActivity extends BaseActivity {
    private Button jump;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_other_task);

        jump= (Button) findViewById(R.id.btn_other);
        jump.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(OtherTaskActivity.this, SingleTaskActivity.class);
                startActivity(intent);
            }
        });
    }
}

日誌輸出

onCreateMainActivity TaskId: 5 hasCode:1249321980
onCreateSingleTaskActivity TaskId: 5 hasCode:1249515136
onCreateOtherTaskActivity TaskId: 6 hasCode:1249386172
onNewIntentSingleTaskActivity TaskId: 6 hasCode:1249513244

當我們從MainActiviyty進入到SingleTaskActivity,再進入到OtherActivity後,此時棧中有3個Activity實例,並且SingleTaskActivity不在棧頂,而在OtherActivity跳到SingleTaskActivity時,並沒有創建一個新的SingleTaskActivity,而是複用了該實例,並且回調了onNewIntent方法。並且原來的OtherActivity出棧了,具體見下面的信息,使用命令adb shell dumpsys activity activities可進行查看

Running activities (most recent first):
      TaskRecord{3c727e #11 A=com.maweiqi.task U=0 sz=2}
        Run #1: ActivityRecord{5a00d1e u0 com.maweiqi.task/.SingleTaskActivity t11}
        Run #0: ActivityRecord{2dce0b u0 com.maweiqi.task/.MainActivity t11}

可以看到當前棧中只有兩個Activity,即原來棧中位於SingleTaskActivity 之上的Activity都出棧了。

singleInstance-全局唯一模式

該模式具備singleTask模式的所有特性外,與它的區別就是,這種模式下的Activity會單獨佔用一個Task棧,具有全局唯一性,即整個系統中就這麼一個實例,由於棧內複用的特性,後續的請求均不會創建新的Activity實例,除非這個特殊的任務棧被銷燬了。以singleInstance模式啓動的Activity在整個系統中是單例的,如果在啓動這樣的Activiyt時,已經存在了一個實例,那麼會把它所在的任務調度到前臺,重用這個實例。

singleInstance示例一配置形式:

<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=".SingleInstanceActivity" android:launchMode="singleInstance"/>
public class MainActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button btn_standard= (Button) findViewById(R.id.btn_standard);
        btn_standard.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, SingleInstanceActivity.class);
                startActivity(intent);
            }
        });

    }
}
public class SingleInstanceActivity extends BaseActivity  {
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_instance);
        Button button4 = (Button) findViewById(R.id.button4);
        button4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(SingleInstanceActivity.this, MainActivity.class);
                startActivity(intent);
            }
        });
    }
}

MainActivity進入SingleInstanceActivity,在從SingleInstanceActivity 進入MainActivity,在從MainActivity進入SingleInstanceActivity

日誌輸出

onCreateMainActivity TaskId: 12 hasCode:201331476
onCreateSingleInstanceActivity TaskId: 13 hasCode:57987178
onCreateMainActivity TaskId: 12 hasCode:254253633
onNewIntentSingleInstanceActivity TaskId: 13 hasCode:57987178

測試結果

1)兩個SingleInstanceActivity是同一個實例。

2) 第一次進入的MainActivity和第一次進入的SingleInstanceActivity位於不同的task中。

3) 兩個MainActivity是位於同一個task中的不同實例。

4)這個結論與預期是相同的,即,singleInstance類型的Activity的實例只能有一個,而且它只允許存在於單獨的一個task中。

5)至於爲什麼兩個MainActivity是位於同一個task中的不同實例,那是因爲它是standard類型的,我們可以將ActivityTest修改爲singleTop等其他類型進行測試。

singleInstance示例二配置形式:

MainActivity的模式改爲”singleTop”,修改後的manifest如下:

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

      <category android:name="android.intent.category.LAUNCHER"/>
     </intent-filter>
</activity>
 <activity android:name=".SingleInstanceActivity" android:launchMode="singleInstance"/>

MainActivity進入SingleInstanceActivity,在從SingleInstanceActivity 進入MainActivity,在從MainActivity進入SingleInstanceActivity

日誌輸出

onCreateMainActivity TaskId: 15 hasCode:201331476
onCreateSingleInstanceActivity TaskId: 16 hasCode:57987178
onNewIntentMainActivity TaskId: 15 hasCode:201331476
onNewIntentSingleInstanceActivity TaskId: 16 hasCode:57987178

測試結果

1)兩個SingleInstanceActivity是同一個實例。

2)第一次進入的MainActivity和第一次進入的SingleInstanceActivity位於不同的task中。

3)兩個MainActivity是同一個實例。

launchMode模式總結

1. standard

在該模式下,Activity可以擁有多個實例,並且這些實例既可以位於同一個task,也可以位於不同的task。

2.singleTop

該模式下,在同一個task中,如果存在該Activity的實例,並且該Activity實例位於棧頂(即,該Activity位於前端),則調用startActivity()時,不再創建該Activity的示例;而僅僅只是調用Activity的onNewIntent()。否則的話,則新建該Activity的實例,並將其置於棧頂。

3. singleTask

只容許有一個包含該Activity實例的task存在!
總的來說:singleTask的結論與android:taskAffinity相關(下章在講),以A啓動B來說

1) 當A和B的taskAffinity相同時:第一次創建B的實例時,並不會啓動新的task,而是直接將B添加到A所在的task;否則,將B所在task中位於B之上的全部Activity都刪除,然後跳轉到B中。
2) 當A和B的taskAffinity不同時:第一次創建B的實例時,會啓動新的task,然後將B添加到新建的task中;否則,將B所在task中位於B之上的全部Activity都刪除,然後跳轉到B中。

4. singleInstance

顧名思義,是單一實例的意思,即任意時刻只允許存在唯一的Activity實例,而且該Activity所在的task不能容納除該Activity之外的其他Activity實例!
它與singleTask有相同之處,也有不同之處。
相同之處:任意時刻,最多隻允許存在一個實例。
不同之處:
1) singleTask受android:taskAffinity屬性的影響,而singleInstance不受android:taskAffinity的影響。
2) singleTask所在的task中能有其它的Activity,而singleInstance的task中不能有其他Activity。
3) 當跳轉到singleTask類型的Activity,並且該Activity實例已經存在時,會刪除該Activity所在task中位於該Activity之上的全部Activity實例;而跳轉到singleInstance類型的Activity,並且該Activity已經存在時,不需要刪除其他Activity,因爲它所在的task只有該Activity唯一一個Activity實例。

參考鏈接:http://blog.csdn.net/sbsujjbcy/article/details/49360615

  • 歡迎關注微信公衆號,長期推薦技術文章和技術視頻

  • 微信公衆號名稱:Android乾貨程序員

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章