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启动模式,看看上面的操作会是一个什么效果。这儿我就不再试了!