在Android程序中,应用程序通过活动栈来管理Activity,活动栈中有多少个Activity对象,我们在退出程序的时候就要按多少下返回键(即要将活动栈中的所有Activity出栈),但是这样的话难免会有活动栈中存在相同的Activity对象,那么我们该如何解决这个问题呢。
代码语言:javascript复制首先,我们的Activity对象在我们在Android工程的AndroidManifest.xml配置文件中注册,之后才可以被我们的程序使用,而在我们注册Activity时,有一个launchMode属性是可以赋值的。如图:
代码语言:javascript复制我们可以看到android:launchMode属性有四个值供我们选择:standard、singleTop、singleTask、singleInstance。我们这里采用实验来验证它们的作用:
创建一个只有一个MainActivity的Android工程: androidmanifest.xml:
代码语言:javascript复制<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.standardactivity"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.standardactivity.MainActivity"
android:label="@string/app_name"
android:launchMode="standard" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
activity_main.xml:
代码语言:javascript复制<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="standard模式启动的Activity" />
<Button
android:id="@ id/startMainActivityButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动MainACtivity" />
</LinearLayout>
MainActivity.java:
代码语言:javascript复制package com.example.standardactivity;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
public static String TAG = "MainActivity";
Button button = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "MainActivityOnCreate");
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.startMainActivityButton);
button.setOnClickListener(listener);
}
private View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
switch(v.getId())
{
case R.id.startMainActivityButton:
intent.setClass(MainActivity.this, MainActivity.class);
break;
}
startActivity(intent);
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
我们在AndroidManifest.xml文件中注册的MainActivity启动模式launchMode属性的值为standard。运行程序,在LogCat新建一个信息查看器,by Log Tag属性设置为MainActivity(和MainActivity中的String类型的常量TAG相同),用于查看LogCat中打印的MainActivity的信息:
![这里写图片描述](http://img.blog.csdn.net/20170124165445486?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSGFja2VyX1poaURpYW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
我们可以看到,第一次启动MainActivity的onCreate方法调用,并且MainActivity处于活动栈栈顶(这绝对是当然的),然后单击按钮两次,我们在Android模拟器中可以看到MainActivity又被创建了两次,而此时的LogCat中的信息:
![这里写图片描述](http://img.blog.csdn.net/20170124185912093?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSGFja2VyX1poaURpYW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
而此时,我们要单击返回键三次才能推出这个程序,从某个方面来说,这是非常不合理的,MainActivity明明已经在活动栈栈顶,还会被创建新的对象。实际上,这正是launchMode属性中的standard值的作用,Activity默认的launchMode属性的值为standard。**当launchMode属性设置为standard时,如果有进程要启动这个Activity,那么无论这个Activiy是否在活动栈栈顶,都会被再次启动一次,**那么怎么解决呢。办法就是将我们的Androidmanifest.xml文件中MainActivity的launchMode属性改一下,变成singleTop,有什么变化呢,我们仍然来做个实验:
将这个Android工程新增一个Activity,这里就取名为SecondActivity吧。将SecondActivity在Androidmanifest.xml中的launchMode属性设置为singleTop:
`<activity
android:name=".SecondActivity"
android:label="SecondActivity"
android:launchMode="singleTop">
</activity>`
同时改一下其他文件:
activity_main.xml:
代码语言:javascript复制MainActivity.java:
package com.example.standardactivity;
import android.os.Bundle; import android.app.Activity; import android.content.Intent; import android.util.Log; import android.view.Menu; import android.view.View; import android.widget.Button;
public class MainActivity extends Activity {
代码语言:javascript复制public static String TAG = "MainActivity";
Button button = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(TAG, "MainActivityOnCreate");
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.startMainActivityButton);
button.setOnClickListener(listener);
button = (Button) findViewById(R.id.startSecondActivityButton);
button.setOnClickListener(listener);
}
private View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
switch(v.getId())
{
case R.id.startMainActivityButton:
intent.setClass(MainActivity.this, MainActivity.class);
break;
case R.id.startSecondActivityButton:
intent.setClass(MainActivity.this, SecondActivity.class);
}
startActivity(intent);
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
代码语言:javascript复制second_activity.xml:
代码语言:javascript复制SecondActivity.java:
package com.example.standardactivity;
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button;
public class SecondActivity extends Activity {
代码语言:javascript复制private Button button = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i(MainActivity.TAG, "SecondActivityOnCreate");
setContentView(R.layout.second_activity);
button = (Button)findViewById(R.id.startMainActivity);
button.setOnClickListener(listener);
button = (Button) findViewById(R.id.startSecondActivity);
button.setOnClickListener(listener);
}
private View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
switch(v.getId())
{
case R.id.startMainActivity:
intent.setClass(SecondActivity.this, MainActivity.class);
break;
case R.id.startSecondActivity:
intent.setClass(SecondActivity.this, SecondActivity.class);
break;
}
startActivity(intent);
}
};
}
代码语言:javascript复制Ok,让我们运行一下程序:
![这里写图片描述](https://img-blog.csdn.net/20170124180101970?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSGFja2VyX1poaURpYW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
首先,MainActivity被创建并打印出信息。
然后我们单击第二个按钮创建SecondActivity:
![这里写图片描述](https://img-blog.csdn.net/20170124180208455?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSGFja2VyX1poaURpYW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
SecondActivity的创建信息也被打印出来了。然后我们再点击一下“启动SecondActivity”按钮,我们会发现LogCat的信息并没有什么变化,此时也只需要点击两次BACK键就能退出程序。
接下来,我们在此基础上再点击“启动MainActivity“按钮,之后再点击“启动SecondActivity”按钮:
![这里写图片描述](https://img-blog.csdn.net/20170124180812259?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSGFja2VyX1poaURpYW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
我们会发现SecondActivity被创建了两次,Ok,我们可以猜想关于singleTop属性的作用:**再返活动栈中,如果要启动的Activity在活动栈栈顶,那么,将不会创建这个Activity的实例,但是如果不在,那么就会创建一个新的Activity实例并将其处于活动栈栈顶。** 正如我们所猜测的那样,singleTop 的作用确实如此。
接下来是singleTask的作用:**如果要启动的Activity存在于活动栈中,那么系统将会将活动栈中在这个Activity对象上面的所有Activity都出栈(被系统回收),并将这个要启动的Activity对象处于活动栈栈顶。如果要启动的Activity不存在活动栈中,那么就会新建一个这个Activity对象,并将其置于活动栈栈顶。**
我们还是用实验来看一下:
将MainActivity的launchMode改为singleTask,将SecondActivity的launchMode改为standard,重写MainActivty的onDestroy方法:
代码语言:javascript复制@Override
public void onDestroy()
{
Log.i(MainActivity.TAG, "SecondActivityOnDestroy");
super.onDestroy();
}
```
重写SecondActivity中的onDestroy方法:
“`
代码语言:javascript复制@Override
public void onDestroy()
{
Log.i(MainActivity.TAG, "SecondActivityOnDestroy");
super.onDestroy();
}
```
其余不变,运行程序,单击“启动SecondActivity”按钮进入SecondActivity之后再次单击“启动SecondActivity”按钮,之后再单击“启动MainActivity”按钮:
结果显而易见,如我们所愿,单击“启动MainActivity”按钮之后,之前在MainActivity上面的两个SecondActivity被系统回收(调用onDestroy方法),自然MainActivity对象处于活动栈栈顶。 最后是singleInstance属性,设置了singleInstance属性的Activity会单独占用一个活动栈,即系统会单独创建一个活动栈去管理launchMode为singleInstance属性的Activity
ok,关于Activity的启动模式就这么多。最后总结一下4种启动模式:
standard:不管要启动的Activity是否已经存在与活动栈,都会创建一个新的Activity对象处于活动栈栈顶。 singleTop:如果要启动的Activity对象已经存在活动栈栈顶,那么不会创建新的Activity对象,否则仍然会创建Activity对象。 singleTask:如果要启动的Activity对象存在活动栈,那么系统将不会创建新的Activity对象,而是会把活动栈中处于这个要启动的Activity对象上面的所有Activity对象出栈(被系统回收),要启动的Activity自然处于活动栈栈顶。如果活动栈中不存在要启动的Activity对象,那么会新建一个Activity对象并置于活动栈栈顶。 singleInstance:为设置了这个属性的Activity单独创建一个活动栈来管理这个Activity对象,并且不会创建重复的Activity对象