Activity的启动模式

来源:互联网 发布:java培训机构比较好 编辑:程序博客网 时间:2024/06/11 12:55

在Android程序中,应用程序通过活动栈来管理Activity,活动栈中有多少个Activity对象,我们在退出程序的时候就要按多少下返回键(即要将活动栈中的所有Activity出栈),但是这样的话难免会有活动栈中存在相同的Activity对象,那么我们该如何解决这个问题呢。

首先,我们的Activity对象在我们在Android工程的AndroidManifest.xml配置文件中注册,之后才可以被我们的程序使用,而在我们注册Activity时,有一个launchMode属性是可以赋值的。如图:

这里写图片描述

我们可以看到android:launchMode属性有四个值供我们选择:standard、singleTop、singleTask、singleInstance。我们这里采用实验来验证它们的作用:

创建一个只有一个MainActivity的Android工程:
androidmanifest.xml:

<?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:

<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:

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:

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 {

public static String TAG = "MainActivity";Button button = null;@Overrideprotected 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);    }};@Overridepublic 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;}

}

second_activity.xml:

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 {

private Button button = null;@Overridepublic 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);    }};

}

Ok,让我们运行一下程序:![这里写图片描述](http://img.blog.csdn.net/20170124180101970?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSGFja2VyX1poaURpYW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)首先,MainActivity被创建并打印出信息。然后我们单击第二个按钮创建SecondActivity:![这里写图片描述](http://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”按钮:![这里写图片描述](http://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方法:
@Override public void onDestroy(){    Log.i(MainActivity.TAG, "SecondActivityOnDestroy");    super.onDestroy();}```重写SecondActivity中的onDestroy方法:

“`

@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对象

0 0