在實際的項目中,我們應該根據特定的需求為每個活動指定恰當的啟動模式。活動的啟動模式一共有四種,可以在AndroidManifest.xml中通過給<activity>標簽指定android:launchMode屬性來選擇啟動模式。下面我們來逐一介紹:
(1)standard:活動的默認啟動模式,在standard模式下,每當啟動一個新的活動,它就會在返回棧中入棧,並置於棧頂的位置。對於使用standard模式的活動,系統不會在乎這個活動是否已經在返回棧中存在,每次啟動都會創建該活動的一個新的實例。
代碼實例:
1 @Override 2 protected void onCreate(Bundle savedInstanceState) { 3 super.onCreate(savedInstanceState); 4 setContentView(R.layout.activity_main); 5 6 Log.d(TAG, this.toString()); 7 btn_jump = findViewById(R.id.btn_jump); 8 btn_jump.setOnClickListener(new View.OnClickListener() { 9 @Override 10 public void onClick(View v) { 11 Intent intent = new Intent(MainActivity.this,MainActivity.class); 12 startActivity(intent); 13 } 14 }); 15 }
運行程序,然后在連續點擊兩次跳轉按鈕,可以看到logcat中打印的信息如下:
從打印的信息我們可以看出,每點擊一次按鈕就會創建一個新的MainActivity實例。此時返回棧中也會存在三個MainActivity的實例,因此你需要連按3次Back鍵才能退出程序。
(2)singleTop:在啟動活動的時候如果發現返回棧的棧頂已經是該活動,則認為可以直接使用它,不會再創建新的活動實例。
修改AndroidManifest.xml中MainActivity的啟動模式,如下所示:
1 <activity 2 android:name=".MainActivity" 3 android:launchMode="singleTop"> 4 <intent-filter> 5 <action android:name="android.intent.action.MAIN" /> 6 7 <category android:name="android.intent.category.LAUNCHER" /> 8 </intent-filter> 9 </activity>
運行程序,查看logcat會看到已經創建了一個MainActivity的實例,如圖所示:
但是之后不管你點擊多少次按鈕都不會再有新的打印信息出現,因為目前MainActivity已經處於返回棧的棧頂,每當你想再啟動一個MainActivity時都會直接使用棧頂的活動,所以MainActivity也只會有一個實例,僅按一次Back鍵就可以退出程序。
不過當MainActivity並未處於棧頂位置時,這時再啟動MainActivity,還是會創建新的實例的。
(3)singleTask:當活動的啟動模式指定為singleTask,每次啟動該活動時,系統首先會在返回棧中檢查是否存在該活動的實例,如果發現已經存在則直接使用該實例,並把在這個活動之上的所有活動統統出棧,如果沒有發現就會創建一個新的活動實例。
修改AndroidManifest.xml中MainActivity的啟動模式,如下所示:
1 <activity 2 android:name=".MainActivity" 3 android:launchMode="singleTask"> 4 <intent-filter> 5 <action android:name="android.intent.action.MAIN" /> 6 7 <category android:name="android.intent.category.LAUNCHER" /> 8 </intent-filter> 9 </activity>
然后在MainActivity中添加onRestart()方法,並打印日志:
1 @Override 2 protected void onRestart() { 3 super.onRestart(); 4 Log.d("MainActivity","onRestart"); 5 }
新建一個activity:JumpActivity,並添加onDestroy()方法,並打印日志:
1 @Override 2 protected void onDestroy() { 3 super.onDestroy(); 4 Log.d("JumpActivity","onDestroy"); 5 }
在JumpActivity界面布局中添加一個Button控件,添加點擊事件使其跳回MainActivity:
1 <?xml version="1.0" encoding="utf-8"?> 2 <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent" 7 tools:context=".JumpActivity"> 8 9 <Button 10 android:text="跳回去玩一下" 11 android:id="@+id/btn_jump_back" 12 android:layout_width="wrap_content" 13 android:layout_height="wrap_content" /> 14 15 </android.support.constraint.ConstraintLayout>
1 Button btn_jump_back = findViewById(R.id.btn_jump_back); 2 btn_jump_back.setOnClickListener(new View.OnClickListener() { 3 @Override 4 public void onClick(View v) { 5 Intent intent = new Intent(JumpActivity.this,MainActivity.class); 6 startActivity(intent); 7 } 8 });
最后修改Button的點擊事件,使其跳轉到JumpActivity界面:
1 btn_jump.setOnClickListener(new View.OnClickListener() { 2 @Override 3 public void onClick(View v) { 4 Intent intent = new Intent(MainActivity.this,JumpActivity.class); 5 startActivity(intent); 6 } 7 });
運行程序,在MainActivity界面點擊按鈕進入到JumpActivity,然后在按JumpActivity中的返回按鈕,又會進入到MainActivity,查看logcat中的打印信息:
其實從打印信息中就可以看出了,在JumpActivity中啟動MainActivity時,會發現返回棧中已經存在了一個MainActivity實例,並且在JumpActivity的下面,於是JumpActivity會從返回棧中出棧,而MainActivity重新成為了棧頂活動,因此MainActivity中的onRestart()方法和JumpActivity的onDestroy()方法會執行。現在返回棧中只剩下一個MainActivity的實例了,按一下Back鍵就可以退出程序。
(4)singleInstance:指定為singleInstance模式的活動會啟動一個新的返回棧來管理這個活動。
適用場景:共享活動實例的問題
代碼測試:
修改AndroidManifest.xml中JumpActivity的啟動模式:
1 <activity 2 android:name=".JumpActivity" 3 android:launchMode="singleInstance"> 4 5 </activity>
然后修改MainActivity中onCreate()方法的代碼:
1 Log.d("MainActivity", "Task id is "+getTaskId()); 2 btn_jump = findViewById(R.id.btn_jump); 3 btn_jump.setOnClickListener(new View.OnClickListener() { 4 @Override 5 public void onClick(View v) { 6 Intent intent = new Intent(MainActivity.this,JumpActivity.class); 7 startActivity(intent); 8 } 9 });
在JumpActivity的onCreate()方法中打印當前返回棧的ID:
1 Log.d("JumpActivity", "Task id is "+getTaskId());
並修改它的點擊事件:
1 btn_jump_back.setOnClickListener(new View.OnClickListener() { 2 @Override 3 public void onClick(View v) { 4 Intent intent = new Intent(JumpActivity.this,ThirdActivity.class); 5 startActivity(intent); 6 } 7 });
創建一個TiridActivity,同上修改onCreate()方法:
1 Log.d("ThirdActivity","Task id is "+getTaskId());
運行程序:在MainActivity界面點擊按鈕進入JumpActivity,然后再點擊按鈕進入TiridActivity。
查看logcat中的打印信息,如圖所示:
可以看到,JumpActivity的Task id不同於MainActivity和TiridActivity,這說明JumpActivity確實存放在一個單獨的返回棧中,而且這個棧中只有JumpActivity這一個活動。然后我們按下Back鍵進行返回,你會發現TiridActivity直接返回到了MainActivity,再按下Back鍵又會返回到JumpActivity,再按下Back鍵才會退出程序。原因:由於MainActivity和TiridActivity是存放在同一個棧里面的,當在TiridActivity界面按下Back鍵,TiridActivity會從返回棧中出棧,那么MainActivity就會成為棧頂活動顯示在界面上,因此也就出現了從TiridActivity直接返回到了MainActivity的情況。然后在MainActivity界面再次按Back鍵,這時當前的返回棧已經空了,於是顯示了另一個返回棧的棧頂活動,即JumpActivity。最后再按Back鍵,這時所有返回棧都已經空了,也就自然退出了程序。