Android Activity的4种启动模式详解(示例)
轉載請注明出處:http://www.cnblogs.com/Joanna-Yan/p/5233269.html
先介紹下Android對Activity的管理,Android采用Task來管理多個Activity,當我們啟動一個應用時,Android就會為之創建一個Task,然后啟動這個應用的入口Activity(即<intent-filter.../>中配置為 MAIN和LAUNCHER的Activity)。
因為Android并沒有為Task提供API,因此我們無法真正去訪問Task,只能調用Activity的getTaskId()方法來獲取它所在的Task的ID。事實上我們可以把Task理解成Activity棧,Task以棧的形式來管理Activity:先啟動的Activity被放在Task棧底,后啟動的Activity被放在Task棧頂。
那么Activity的加載模式,就負責管理實例化、加載Activity的方式、并可以控制Activity與Task之間的關系。
Activity有4中啟動模式,分別為:standard,singleTop,singleTask,singleInstance。如果要使用這四種啟動模式,必須在manifest文件中<activity>標簽中的launchMode屬性配置,如:
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="standard"
>
</activity>
standard
標準啟動模式,也是Android的默認啟動模式。在這種模式下啟動的activity可以被多次實例化,即在一個任務中可以存在多個activity實例,每個實例都會處理一個Intent對象。如果Activity A的啟動模式為standard,并且A已經啟動,在A中再次啟動Activity A,即調用startActivity(new Intent(this,A.class)),會在A的上面再次啟動一個A的實例,即當前的棧中的狀態為A-->A。
singleTop
如果一個以singleTop模式啟動的activity的實例已經存在于任務棧的棧頂,那么再次啟動這個activity時,不會創建新的實例,而是重用位于棧頂的那個實例,并且會調用該實例的onNewIntent()方法將Intent對象傳遞到這個實例中。舉例來說,如果A的啟動模式為singleTop,并且A的一個實例已經存在于棧頂中,那么再調用startActivity(new Intent(this,A.class))啟動A時,不會再創建A的實例,而是重用原來的實例,并且調用原來實例的onNewIntent()方法。這時任務棧中還是有一個A的實例。
如果以singleTop模式啟動的activity的一個實例已經存在于任務棧中,但是不在棧頂,那么它的行為和standard模式相同,也會創建多個實例。
singleTask
官方文檔上稱,如果一個activity的啟動模式為singleTask,那么系統總會在一個新的任務的最底部(root)啟動這個activity,并且被這個activity啟動的其它activity會和該activity同時存在于這個新任務中。如果系統中已經存在一個這樣的activity則會重用這個實例,并且調用它的onNewIntent()方法。即,這樣的一個activity在系統中只會存在一個實例。
但是這種說法并不準確,采用singleTask啟動目標Activity時,可分三種情況:
1、如果將要開啟的目標Activity不存在,系統將會創建目標Activity實例,并將它放入Task棧頂。
2、如果將要啟動的目標Activity已經位于Task棧頂,此時與singleTop模式的行為相同。
3、如果將要啟動的目標Activity已經存在、但沒有位于Task棧頂,系統將會把位于該Activity上面的所有Activity移出Task棧,從而使得目標Activity轉入棧頂。
下面通過實例說明:
兩個Activity,FirstActivity顯示文本框和按鈕,該按鈕用于啟動SecondActivity;SecondActivity顯示文本框和按鈕,該按鈕用于啟動FirstActivity。
public class FirstActivity extends Activity {TextView tv;Button btn;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv=(TextView) findViewById(R.id.tv);tv.setText("Activity為:"+this.toString()+",Task ID為:"+this.getTaskId());btn=(Button) findViewById(R.id.btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent=new Intent(FirstActivity.this, SecondActivity.class);startActivity(intent);}});} } public class SecondActivity extends Activity {TextView tv;Button btn;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);tv=(TextView) findViewById(R.id.tv);tv.setText("Activity為:"+this.toString()+",Task ID為:"+this.getTaskId());btn=(Button) findViewById(R.id.btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent=new Intent(SecondActivity.this, FirstActivity.class);startActivity(intent);}});} }運行該實例,系統默認啟動FirstActivity,點擊該界面按鈕,系統以singgleTask模式打開SecondActivity ,此時Task棧中有兩個Activity(從底向上):FirstActivity-->SecondActivity.
點擊SecondActivity界面按鈕,系統以標準模式再次啟動FirstActivity,此時Task棧中有三個Activity(從底向上):FirstActivity-->SecondActivity-->FirstActivity.
在FirstActivity中再次點擊按鈕,系統以singleTask模式再次打開SecondActivity,系統會將位于SecondActivity上面的所有Activity移出,使得SecondActivity進入棧頂,此時Task棧中只有兩個Activity(從底向上):FirstActivity-->SecondActivity.
效果圖(依次):
?
??
singleInstance
總是在新的任務中開啟,并且這個新的任務中有且只有這一個實例,也就是說被該實例啟動的其他activity會自動運行于另一個任務中。當再次啟動該activity的實例時,會重用已存在的任務和實例。并且會調用這個實例的onNewIntent()方法,將Intent實例傳遞到該實例中。和singleTask相同,同一時刻在系統中只會存在一個這樣的Activity實例。
說明:
這種加載模式下,系統保證無論從哪個Task中啟動目標Activity,只會創建一個目標Activity實例,并會使用一個全新的Task棧來裝載該Activity實例。
當用singleInstance啟動目標Activity時,分兩種情況:
1、當將要啟動的目標Activity不存在,系統會先創建一個全新的Task、再創建目標Activity的實例,并將它加入新的Task的棧頂。
2、如果將要啟動的目標Activity已經存在,無論它位于哪個應用程序中,無論它位于哪個Task中,系統將會把該Activity所在的Task轉到前臺,從而使用該Activity顯示出來。
采用該模式加載的Activity總是位于Task棧頂,所在Task只包含該Activity.
舉例說明:
點擊FirstActivity中按鈕,啟動SecondActivity。SecondActivity配置成singleInstance加載模式,export屬性配置成true---表明該Activity可被其它應用啟動。
public class FirstActivity extends Activity {TextView tv;Button btn;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv=(TextView) findViewById(R.id.tv);tv.setText("Activity為:"+this.toString()+",Task ID為:"+this.getTaskId());btn=(Button) findViewById(R.id.btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent=new Intent(FirstActivity.this, SecondActivity.class);startActivity(intent);}});} } <activityandroid:name=".SecondActivity"android:launchMode="singleInstance"android:exported="true" ><intent-filter><!--知道該Activity能響應Action為指定字符串的Intent --><action android:name="joanna.yan.action.TEST_ACTION" /><category android:name="android.intent.category.DEFAULT" /></intent-filter></activity>系統啟動新的Task并用新的Task加載新創建的SecondActivity實例,SecondActivity總是位于棧頂。
效果圖:
?
另一個示例采用隱式Intent再次啟動該SecondActivity。
代碼:
public class OtherActivity extends Activity {TextView tv;Button btn;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);tv=(TextView) findViewById(R.id.tv);tv.setText("Activity為:"+this.toString()+",Task ID為:"+this.getTaskId());btn=(Button) findViewById(R.id.btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) { Intent intent=new Intent();intent.setAction("joanna.yan.action.TEST_ACTION");startActivity(intent);}});} }單擊OtherActivity中的按鈕隱式啟動singleInstance模式的SecondActivity,如果前面一個示例還未退出,無論SecondActivity所在Task是否位于前臺,系統將再次把SecondActivity所在Task轉入前臺,從而將SecondActivity顯示出來。
效果圖:
?
如果此文對您有幫助,微信打賞我一下吧~
總結
以上是生活随笔為你收集整理的Android Activity的4种启动模式详解(示例)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java原理—反射机制
- 下一篇: Junit源码阅读(四)之自定义扩展