launchMode在多個Activity跳轉的過程中扮演著重要的角色,它可以決定是否生成新的Activity實例,是否重用已存在的Activity實例,是否和其他Activity實例公用一個task
里。這里簡單介紹一下task
的概念,task
是一個具有棧(后進先出)結構的對象,一個task
可以管理多個Activity,啟動一個應用,也就創(chuàng)建一個與之對應的task
。
Activity一共有以下四種LaunchMode:
1.standard
2.singleTop
3.singleTask
4.singleInstance
我們可以在AndroidManifest.xml
配置<activity>
的Android: LaunchMode屬性為以上四種之一即可,如果不配置,默認是standard
。
1、standard
:標準模式,這也是系統的默認模式。每次啟動一個Activity都會重新創(chuàng)建一個新的實例,不管這個實例是否已經存在。被創(chuàng)建的實例的生命周期符合典型情況下的生命周期,它的onCreate
、onStart
、onResume
都會被調用。該模式不會調用onNewIntent
方法。
下面用一個例子演示一下standard
模式:
<pre><code>
public class FirstActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(this.toString());
Button button = (Button) findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this,FirstActivity.class);
startActivity(intent);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.i("FirstActivity","onNewIntent called");}
});
}
}
</pre></code>
通過圖片可以看到,我們每次點擊按鈕都新建了不同的FirstActivity實例,并且我們需要連續(xù)按后退鍵兩次,才能回到第一個FristActivity。
standard
模式的原理如下圖所示:
如圖所示,每次跳轉系統都會在
task
中生成一個新的FirstActivity實例,并且放于棧結構的頂部,當我們按下后退鍵時,才能看到原來的FirstActivity實例。這就是
standard
啟動模式,不管棧有沒有已存在的實例,都會創(chuàng)建新的實例。2、
singleTop
:棧頂復用模式。在這種模式下,1??如果新的Activity已經位于任務棧的棧頂,注意是位于棧頂,那么此Activity不會被重新創(chuàng)建,同時它的onNewIntent
方法會被調用,通過此方法的參數我們可以取出當前請求的信息。需要注意的是,onCreate
、onStart
、onResume
不會被調用,因為它并沒有發(fā)生改變。2??但是如果新的Activity實例已存在但沒有位于棧頂,那么新的Activity仍然會被重新創(chuàng)建。1??
我們在上面代碼的基礎上為<activity>指定屬性
android:launchMode="singleTop"
,系統就會按照singleTop
啟動模式處理跳轉行為。我們重復上面幾個動作,將會出現下面的現象:同時
onNewIntent
會被調用,我們可以在onNewIntent
中的形參Intent intent
獲取一些數據做一些操作。<pre><code>
09-19 17:51:27.013 6674-6674/xiaoyong68.com.activitylaunchmode I/FirstActivity: onNewIntent called
</pre></code>
我們看到這個結果跟standard有所不同,三個序列號是相同的,也就是說使用的都是同一個FirstActivity實例;如果按一下后退鍵,程序立即退出,說明當前棧結構中只有一個Activity實例。
singleTop模式的原理如下圖所示:
正如上圖所示,跳轉時系統會先在棧結構中尋找是否有一個FirstActivity實例正位于棧頂,如果有則不再生成新的,而是直接使用。也許朋友們會有疑問,我只看到棧內只有一個Activity,如果是多個Activity怎么辦,如果不是在棧頂會如何?2??我們接下來再通過一個示例來證實一下大家的疑問。
我們再新建一個Activity命名為SecondActivity,如下:
<pre><code>
public class SecondActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(this.toString());
Button button = (Button) findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(SecondActivity.this, FirstActivity.class);
startActivity(intent);
}
});
}
}
</pre></code>
然后將FirstActivity中的跳轉代碼改為:
<pre><code>
Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
</pre></code>
點擊FirstActivity中按鈕會從FirstActivity跳轉到SecondActivity,點擊SecondActivity中按鈕會從SecondActivity又會跳轉到FirstActivity。演示結果如下:
我們看到,兩個FirstActivity的序列號是不同的,證明從SecondActivity跳轉到FirstActivity時生成了新的FirstActivity實例。原理圖如下:
我們看到,當從SecondActivity跳轉到FirstActivity時,系統發(fā)現存在有FirstActivity實例,但不是位于棧頂,于是重新生成一個實例,這種方式會重新新建,
onCreate
、onStart
、onResume
會被調用,但是onNewIntent
則不會被調用。值得注意的是,當我們不按SecondAndroid的按鈕而直接按back鍵返回到FirstActivity時,FirstActivity不會重新創(chuàng)建,只是把原來的重新展現,生命周期函數執(zhí)行如下:onRestart
->onStart
->onResume
->onWindowFocusChanged
<pre><code>
09-19 20:31:19.914 14458-14458/xiaoyong68.com.activitylaunchmode I/FirstActivity: onRestart called.
09-19 20:31:19.918 14458-14458/xiaoyong68.com.activitylaunchmode I/FirstActivity: onStart called.
09-19 20:31:19.918 14458-14458/xiaoyong68.com.activitylaunchmode I/FirstActivity: onResume called.
09-19 20:31:19.978 14458-14458/xiaoyong68.com.activitylaunchmode I/FirstActivity: onWindowFocusChanged called.
</pre></code>
這就是singleTop啟動模式,如果發(fā)現有對應的Activity實例正位于棧頂,則重復利用,不再生成新的實例。
3、singleTask
:棧內復用模式。這是一種單實例模式,在這種模式下,只要Activity在一個棧中存在,那么多次啟動此Activity都不會重新創(chuàng)建實例,系統會回調其onNewIntent
方法。具體一點,當一個具有singleTask
模式的Activity請求啟動后,例如Activity A,系統首先會尋找是否存在A想要的任務棧,如果不存在,就重新創(chuàng)建一個任務棧,然后創(chuàng)建A的實例后把A放到棧中。如果存在A所需要的任務棧,這時需要看A是否在棧中有實例存在,如果有,那么系統就把A調到(在A前面的Activity實例全部出棧)棧頂并調用其onNewIntent
方法,如果不存在實例,就創(chuàng)建A的實例并把A壓入棧中。
在上面的基礎上我們修改FirstActivity的屬性android:launchMode="singleTask"
。演示的結果如下:
我們注意到,在上面的過程中,FirstActivity的序列號是不變的,SecondActivity的序列號卻不是唯一的,說明從SecondActivity跳轉到FirstActivity時,沒有生成新的實例,但是從FirstActivity跳轉到SecondActivity時生成了新的實例。singleTask模式的原理圖如下圖所示:
在圖中的下半部分是SecondActivity跳轉到FirstActivity后的棧結構變化的結果,我們注意到,SecondActivity消失了,沒錯,在這個跳轉過程中系統發(fā)現有存在的FirstActivity實例,于是不再生成新的實例,而是將FirstActivity之上的Activity實例統統出棧,將FirstActivity變?yōu)闂m攲ο螅@示到幕前。也許朋友們有疑問,如果將SecondActivity也設置為singleTask模式,那么SecondActivity實例是不是可以唯一呢?在我們這個示例中是不可能的,因為每次從SecondActivity跳轉到FirstActivity時,SecondActivity實例都被迫出棧,下次等FirstActivity跳轉到SecondActivity時,找不到存在的SecondActivity實例,于是必須生成新的實例。但是如果我們有ThirdActivity,讓SecondActivity和ThirdActivity互相跳轉,那么SecondActivity實例就可以保證唯一。
這就是singleTask模式,如果發(fā)現有對應的Activity實例,則使此Activity實例之上的其他Activity實例統統出棧,使此Activity實例成為棧頂對象,顯示到幕前。
4、
singleInstance
:單實例模式。是一種加強的singleTask
模式,它除了具有singleTask
模式的所有特性外,還加強了一點,那就是此種模式的Activity只能單獨地位于一個任務棧中,換句話說,比如Activity A是singleInstance
模式,當A啟動后,系統會為它創(chuàng)建一個新的任務棧,然后A獨自在這個新的任務棧中,由于棧內復用的特性,后續(xù)的請求均不會創(chuàng)建新的Activity,除非這個獨特的任務棧被系統銷毀了。