Activity啓動模式對於我們很多應用中會有不同的要求,這兒簡單說一下Activity的四種啓動模式之間的差別
1.standard默認啓動模式,如果不在AndroidMainfest文件中配置,默認爲這個模式。
這種模式下,每次啓動這個Activity都會調onCreate方法創建新的實例。
示例代碼:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i("MainActivity","onCreate :"); } public void clickButton(View view) { startActivity(new Intent(this, MainActivity.class)); } @Override protected void onResume() { super.onResume(); Log.i("MainActivity", " onResume instance :" + this.toString() + " taskID :" + this.getTaskId()); } }
這兒寫一個按鈕,點擊按鈕啓動本身,Log可以看出,打印的instance 不相同,taskID 相同,點擊返回,不會直接退出應用,而是會閃一下,但是頁面顯示沒變,這就代表是同一個activity的不同實例。
2.singleTop唯一棧頂模式,當啓動該activity時,如果該activity有實例在棧頂,就不再重新創建新的實例,而是就用當前棧頂的實例,如果該activity沒有實例在棧頂就創建新的實例於棧頂。
跟第一點中同樣的代碼,會發現每次點擊按鈕,不會走onCreate方法去創建新的實例。
3.singleTask當需要啓動的activity有實例存在於棧中,就不會再創建新的實例,而是把該實例上面的activity的實例出棧,讓該activity位於棧頂,用當前實例。
4.singleInstance該啓動模式會單獨開闢一個特殊的棧用於存放該activity的實例,當啓動別的activity的時候,跳到該進程所處的正常的那個棧,當再次啓動該activity的時候,重新跳轉到存放該activity的實例的特殊棧。
好了,上面四種啓動方式都已經很詳細的說完了,現在我們來一個簡單的案例,看看最特殊的一種啓動方式singleInstance的特質。爲什麼說他最特殊呢?因爲只有這一種會另外開闢新棧,前面三種雖然有不同,但是因爲都是在同一個棧中,所以大同小異!
現在我們有4個Activity,類名稱如下:MainActivity,Main1Activity,Main2Activity,Main3Activity.清單文件中的啓動方式,除了Main2Activity之外,其他三個都是默認的啓動方式standard啓動模式。
清單文件:
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".Main1Activity" /> <activity android:name=".Main2Activity" android:launchMode="singleInstance" /> <activity android:name=".Main3Activity"/> </application>
佈局文件都一樣,就是有一個按鈕,點擊啓動下一個Activity,button上顯示的是當前activity的名字:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.dragon.upandroiddemos.MainActivity"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="clickButton" android:text="MainActivity" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>
Activity中的代碼也一樣,就是啓動下一個activity,並且將當前activity所在棧的ID打印出來:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void clickButton(View view) { startActivity(new Intent(this, Main1Activity.class)); } @Override protected void onResume() { super.onResume(); Log.i("MainActivity","onResume taskID :"+getTaskId()); } @Override protected void onStart() { super.onStart(); Log.i("MainActivity","onStart :"); } }
現在我們做這樣的操作,在每一個activity中去啓動下一個activity,啓動順序如下:Main----->Main1---->Main2----->Main3----->Main。現在我們來看看log,然後再分析一下。
好了,現在我們再按返回鍵,觀察log結果:
很明顯除了Main2在12167棧中,其他三個都在12166棧中。並且按返回鍵的時候,沒有按啓動的順序來返回,現在我們來說說這個過程。
啓動過程是調用startActivity方法去創建新的activity並且將當前窗口交給被啓動的activity,這個是按前面所說的啓動方式正常的啓動,沒有什麼可質疑的。過程如下圖:
現在的問題是,現在按返回鍵的時候,從前面的log很明顯的看出,在Main3返回的時候,沒有返回到Main2,而是直接回到了Main1。注意這兒就對了。其實系統返回鍵是將activity棧中的activity出棧的一個過程,也就是說這個過程會連續去操作12166中所存在的activity。當12166棧中的所有activity出棧之後,12167還在當前應用進程中,這時候無法直接退出進程的。需要將12167中的activity也出棧之後將12167棧回收掉。所以纔會有上面的這個過程。
好了講到這兒就差不多完了,網友可以自己試驗一下將Main3也該成singleInstance啓動模式,看看上面的操作會是一個什麼效果。這兒我就不再試了!