通常情况下,一个应用有一个Task,这个Task就是为了完成某个工作的一系列Activity的集合。而这些Activity又被组织成了堆栈的形式。
当一个Activity启动时,就会把它压入该Task的堆栈,而当用户在该Activity中按返回键,或者代码中finish掉时,就会将它从该Task的堆栈中弹出。如果我们没有特别的需求,我们的应用就会呈现出如下图所示的情形(好吧,我承认这个图是document里的):然而,事实上我们的需求远没有我们想的那么简单。有时候,你可能希望在开启一个Activity时,重新开启一个Task;有时你可能希望将已经存在的一个Activity放到栈顶,而不是重新创建一个...
Android为了使我们能够打破默认的堆栈的先后出的模式,提供了两个种方式:一种是在AndroidManifest.xml定义Activity时指定它的加载模式,另一种是在用Intent开启一个Activity时,在Intent中加入标志。如果两种方式都用了,则后者的优先级更高。
两种方式的差别在于,前者在于描述自己,向别的Acttivity等声明你们如何来加载我;而后者则是动态的,指出我要求你(要启动的Activity)如何来加载。本文的重点在于研究在AndroidManifest.xml中声明加载模式。
Android为我们定义了四种加载模式,分别是:standard、singleTop、singleTask和singleInstance。
“拿来主义”——standard模式
我们写一段代码来测试一下standard加载模式,如下
AndroidManifest.xml里Activity的设置如下:
- <activity android:name=".Activity1"
- android:launchMode="standard"
- android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
Activity1的代码如下
- public class Activity1 extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- }
- /**当点击Activity时,启动另一个Activity1*/
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- Intent intent = new Intent(this, Activity1.class);
- startActivity(intent);
- return super.onTouchEvent(event);
- }
- }
然后我们启动程序,开启Activity1,然后点击Acitivity1,启动另一个Activity1,然后再点击,再点击,再点击... 之后我们点返回键。
发生了什么事情?没错,我们按返回键返回一个又一个相同的Activity1。
standard是Activity默认的加载模式,这种方式用一个词来形容的话就是“拿来主义”。使用这种模式的Activity向所有使用它的Task声明:“我这里的这种Activity多着呢,谁需要的话我就给谁”。所以当一个Task请求加载这个Activity时,该Task直接实例化该Activity,并把它放到栈顶。
因此我们的例子就出现了这样的堆栈结构(假设我们点击了4次):
Activity1 |
Activity1 |
Activity1 |
Activity1 |
Activity1 |
我们设想一个情形:我们要做一个图片浏览器,第一个界面是图片列表界面(假设为PictureListActivity),第二个界面是浏览该张图片(假设为PictureViewActivity)。在PictureViewActivity中可以startActivity启动浏览界面浏览上一张和下一张。
如果每一张图片的浏览启动一个PictureViewActivity(当然你可能不是采用这种方式来浏览上一张和下一张,这里只是举个例子),如果采用standard模式的话,就会出现多个PictureViewActivity在堆栈中堆叠的情形。下面介绍的singleTop便可以解决这个问题。
“拒绝堆叠”——singleTop模式
我们将上面的例子稍加改动,AndroidManifest.xml中Acitivity1的launchMode改为singleTop,Activity1的代码修改如下:
- public class Activity1 extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- //Activity1创建时显示Toast
- Toast.makeText(this, "onCreate called!", Toast.LENGTH_SHORT).show();
- }
- @Override
- protected void onNewIntent(Intent intent) {
- setTitle("I am Activity1 too, but I called onNewIntent!");
- super.onNewIntent(intent);
- }
- //点击进入加载Activity1
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- Intent intent = new Intent(this, Activity1.class);
- startActivity(intent);
- return super.onTouchEvent(event);
- }
- }
同样,我们启动程序,开启Activity1,然后点击Acitivity1,启动另一个Activity1,然后再点击,再点击,再点击... 之后我们点返回键。
结果,Activity1第一次创建时,显示一个Toast提示,onCreate被调用,当再次点击时,onCreate没有被调用相反是进入了onNewIntent函数。当按返回键时,直接退出了该应用,可见,堆栈中只存在一个Acitivity1。
可见,当activity被设置为singleTop的加载模式时,如果堆栈的顶部已经存在了该Activity,那么,它便不会重新创建,而是调用onNewIntent。如果,该Activity存在,但不是在顶部,那么该Activity依然要重新创建,请读者自行验证。
因此singleTop模式的思想便是“拒绝堆叠”!
以上说的两种加载模式,Activity均可以实例化多次,而下面讲的两个加载模式就只可以实例化一次。
“独立门户”——singleTask模式
我们首先测试一下,在本应用内调用singleTask模式的Activity会出现什么情况。
我们写两个Activity(Activity1和Activity2),相互调用,其中Activity1为singleTask模式。AndroidManifest.xml如下:
两个Activity的代码如下:
- /**Activity1的代码*/
- public class Activity1 extends Activity {
- private static final String TAG = "Activity1";
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- Log.e(TAG, "Activity1 onCreate! HashCode=" + this.hashCode() + " TaskId=" + getTaskId());
- }
- @Override
- protected void onNewIntent(Intent intent) {
- Log.e(TAG, "Activity1 onNewIntent! HashCode="+ this.hashCode() + " TaskId=" + getTaskId());
- super.onNewIntent(intent);
- }
- @Override
- protected void onDestroy() {
- Log.e("Activity1", "Activity1 onDestroy! HashCode="+this.hashCode()+ "TaskId="+getTaskId());
- super.onDestroy();
- }
- /**点击进入Activity2*/
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- Intent intent = new Intent(this, Activity2.class);
- startActivity(intent);
- return super.onTouchEvent(event);
- }
- }
- /**Activity2的代码*/
- public class Activity2 extends Activity {