Activity的启动模式

在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;
@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;
}

}

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;
@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);
    }
};

}

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方法:
@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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值