Android Activity各启动模式的差异

Activity共有四种启动模式:standard,singleTop,singleTask,singleInstance

为了方便描述和理解,布局文件、Manifest文件和各个java文件如下:

AndoirdManifest文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.activitylaunchmode"
android:versionCode="1"
android:versionName="1.0" > <uses-sdk
android:minSdkVersion="19"
android:targetSdkVersion="21" /> <application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:launchMode="standard"
android:screenOrientation="portrait"
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:name=".SecondActivity">
</activity>
<activity
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:name=".ThirdActivity">
</activity>
<activity
android:launchMode="singleInstance"
android:screenOrientation="portrait"
android:name=".FourActivity">
</activity>
</application> </manifest>

  4个Activity分别对应一种启动模式:

    MainActivity     ---->  standard (默认模式,写不写都可以)

    SecondActivity ---->  singleTop

    ThirdActivty     ---->  singleTask

    FourActivity     ---->  singleInstance

布局文件 activity_main.xml

<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.activitylaunchmode.MainActivity" > <TextView
android:id="@+id/mTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<Button
android:layout_below="@id/mTextView"
android:id="@+id/buttonOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1"
/>
<Button
android:id="@+id/buttonTwo"
android:text="Button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/buttonOne"
android:layout_below="@id/mTextView"
/>
<Button
android:id="@+id/buttonThree"
android:text="Button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/buttonOne"
/>
<Button
android:id="@+id/buttonFour"
android:text="Button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/buttonTwo"
android:layout_toRightOf="@id/buttonThree"
/>
</RelativeLayout>

MainActivity.java

package com.example.activitylaunchmode;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView; public class MainActivity extends Activity implements OnClickListener{ private static final String TAG = "MainActivity";
TextView tv;
Button ButtonOne;
Button ButtonTwo;
Button ButtonThree;
Button ButtonFour; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.mTextView);
tv.setText("MainActivity");
ButtonOne = (Button) findViewById(R.id.buttonOne);
ButtonOne.setOnClickListener(this);
ButtonTwo = (Button) findViewById(R.id.buttonTwo);
ButtonTwo.setOnClickListener(this);
ButtonThree = (Button) findViewById(R.id.buttonThree);
ButtonThree.setOnClickListener(this);
ButtonFour = (Button) findViewById(R.id.buttonFour);
ButtonFour.setOnClickListener(this);
} @Override
protected void onNewIntent(Intent intent) {
// TODO Auto-generated method stub
super.onNewIntent(intent);
Log.d(TAG, "onNewIntent");
} @Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.buttonOne:
Intent mainIntent = new Intent(this,MainActivity.class);
startActivity(mainIntent);
break;
case R.id.buttonTwo:
Intent secondIntent = new Intent(this,SecondActivity.class);
startActivity(secondIntent);
break;
case R.id.buttonThree:
Intent ThirdIntent = new Intent(this,ThirdActivity.class);
startActivity(ThirdIntent);
break;
case R.id.buttonFour:
Intent FourIntent = new Intent(this,FourActivity.class);
startActivity(FourIntent);
break;
}
}
}

SecondActivity.java

package com.example.activitylaunchmode;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView; public class SecondActivity extends Activity implements OnClickListener { private static final String TAG = "SecondActivity";
TextView tv;
Button ButtonOne;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.mTextView);
tv.setText("SecondActivity");
ButtonOne = (Button) findViewById(R.id.buttonOne);
ButtonOne.setOnClickListener(this);
} @Override
protected void onNewIntent(Intent intent) {
// TODO Auto-generated method stub
super.onNewIntent(intent);
Log.d(TAG, "onNewIntent");
} @Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.buttonOne:
Intent secondIntent = new Intent(this,SecondActivity.class);
startActivity(secondIntent);
break;
}
}
}

ThirdActivity.java

package com.example.activitylaunchmode;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView; public class ThirdActivity extends Activity implements OnClickListener { private static final String TAG = "ThirdActivity";
TextView tv;
Button ButtonOne;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.mTextView);
tv.setText("ThirdActivity");
ButtonOne = (Button) findViewById(R.id.buttonOne);
ButtonOne.setOnClickListener(this);
} @Override
protected void onNewIntent(Intent intent) {
// TODO Auto-generated method stub
super.onNewIntent(intent);
Log.d(TAG, "onNewIntent");
} @Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.buttonOne:
Intent mainIntent = new Intent(this,MainActivity.class);
startActivity(mainIntent);
break; default:
break;
}
} }

FourActivity.java

package com.example.activitylaunchmode;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView; public class FourActivity extends Activity implements OnClickListener { private static final String TAG = "FourActivity";
TextView tv;
Button ButtonOne;
Button ButtonTwo;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.mTextView);
tv.setText("FourActivity");
ButtonOne = (Button) findViewById(R.id.buttonOne);
ButtonOne.setOnClickListener(this);
} @Override
protected void onNewIntent(Intent intent) {
// TODO Auto-generated method stub
super.onNewIntent(intent);
Log.d(TAG, "onNewIntent");
} @Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.buttonOne:
Intent MainIntent = new Intent(this,MainActivity.class);
startActivity(MainIntent);
break; case R.id.buttonFour:
Intent FourIntent = new Intent(this,FourActivity.class);
startActivity(FourIntent);
default:
break;
}
} }

各个启动模式差异探究:

  1)standard:  默认模式,每启动一个activity都会在Task中创建一个,back键会依次从栈中退出

    MainActivity的启动模式是standard, 点击Button1,会再启动一个MainActivity.

    通过adb shell dumpsys activity命令, 我们能看到在Task中存在两个MainActivity.

    Task id #
TaskRecord{2cfa2efd # A=com.example.activitylaunchmode U= sz=}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x30200000 cmp=com.example.activitylaunchmode/.MainActivity }
Hist #: ActivityRecord{37783c3a u0 com.example.activitylaunchmode/.MainActivity t48}
Intent { cmp=com.example.activitylaunchmode/.MainActivity }
ProcessRecord{358547f2 :com.example.activitylaunchmode/u0a134}
Hist #: ActivityRecord{363c8000 u0 com.example.activitylaunchmode/.MainActivity t48}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x30200000 cmp=com.example.activitylaunchmode/.MainActivity bnds=[,][,] }
ProcessRecord{358547f2 :com.example.activitylaunchmode/u0a134} Running activities (most recent first):
TaskRecord{2cfa2efd # A=com.example.activitylaunchmode U= sz=}
Run #: ActivityRecord{37783c3a u0 com.example.activitylaunchmode/.MainActivity t48}
Run #: ActivityRecord{363c8000 u0 com.example.activitylaunchmode/.MainActivity t48}

  

  2)singleTop:如果要启动的Activity在栈顶,则不会重新创建

     SecondActivity的启动模式是singleTop, 点击MainActivity中的Button2,会创建一个SecondActivity,再点击SecondActivity中的Button1,会重新启动 SecondActivity.

    通过adb命令,我们可以看到,Task中只有MainActivity和SecondActivity两个Activity,第二次点击并没有重新创建。从log中,我们可以看到,第二次点击启动SecondActivity,只是调用了前一个SecondActivity的onNewIntent方法。

    Task id #
TaskRecord{fb41e01 # A=com.example.activitylaunchmode U= sz=}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x30200000 cmp=com.example.activitylaunchmode/.MainActivity }
Hist #: ActivityRecord{1ea62f6c u0 com.example.activitylaunchmode/.SecondActivity t51}
Intent { cmp=com.example.activitylaunchmode/.SecondActivity }
ProcessRecord{69b44a6 :com.example.activitylaunchmode/u0a134}
Hist #: ActivityRecord{27f7bb0a u0 com.example.activitylaunchmode/.MainActivity t51}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x30200000 cmp=com.example.activitylaunchmode/.MainActivity bnds=[,][,] }
ProcessRecord{69b44a6 :com.example.activitylaunchmode/u0a134} Running activities (most recent first):
TaskRecord{fb41e01 # A=com.example.activitylaunchmode U= sz=}
Run #: ActivityRecord{1ea62f6c u0 com.example.activitylaunchmode/.SecondActivity t51}
Run #: ActivityRecord{27f7bb0a u0 com.example.activitylaunchmode/.MainActivity t51}

  

  3)singleTask: 任务栈中没有这个Activity,则会在任务栈中创建一个实例,如果任务栈中已经存在,则会将任务栈中的此activity之上的activity全部出栈

    ThirdActivity的启动模式是singleTask, 点击MainActivity中的Button3,启动ThirdActivity,再点击ThirdActivity中的Button1,启动MainActivity,此时的Activity的堆栈信息如下:

    Task id #
TaskRecord{147eed75 # A=com.example.activitylaunchmode U= sz=}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x30200000 cmp=com.example.activitylaunchmode/.MainActivity }
Hist #: ActivityRecord{2bf26a69 u0 com.example.activitylaunchmode/.MainActivity t52}
Intent { cmp=com.example.activitylaunchmode/.MainActivity }
ProcessRecord{3e2f10a :com.example.activitylaunchmode/u0a134}
Hist #: ActivityRecord{147e2631 u0 com.example.activitylaunchmode/.ThirdActivity t52}
Intent { flg=0x10000000 cmp=com.example.activitylaunchmode/.ThirdActivity }
ProcessRecord{3e2f10a :com.example.activitylaunchmode/u0a134}
Hist #: ActivityRecord{4e87389 u0 com.example.activitylaunchmode/.MainActivity t52}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x30200000 cmp=com.example.activitylaunchmode/.MainActivity bnds=[,][,] }
ProcessRecord{3e2f10a :com.example.activitylaunchmode/u0a134} Running activities (most recent first):
TaskRecord{147eed75 # A=com.example.activitylaunchmode U= sz=}
Run #: ActivityRecord{2bf26a69 u0 com.example.activitylaunchmode/.MainActivity t52}
Run #: ActivityRecord{147e2631 u0 com.example.activitylaunchmode/.ThirdActivity t52}
Run #: ActivityRecord{4e87389 u0 com.example.activitylaunchmode/.MainActivity t52}

    这个也说明了standard启动模式会重新创建一个Activity.

    然后再点击MainActivity中的Button3,启动ThirdActivity,通过adb命令看到的如下: 

    Task id #
TaskRecord{2553d3b2 # A=com.example.activitylaunchmode U= sz=}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x30200000 cmp=com.example.activitylaunchmode/.MainActivity }
Hist #: ActivityRecord{33f3f7cd u0 com.example.activitylaunchmode/.ThirdActivity t53}
Intent { flg=0x10000000 cmp=com.example.activitylaunchmode/.ThirdActivity }
ProcessRecord{1cdd8f03 :com.example.activitylaunchmode/u0a134}
Hist #: ActivityRecord{e5f9ea5 u0 com.example.activitylaunchmode/.MainActivity t53}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x30200000 cmp=com.example.activitylaunchmode/.MainActivity bnds=[,][,] }
ProcessRecord{1cdd8f03 :com.example.activitylaunchmode/u0a134} Running activities (most recent first):
TaskRecord{2553d3b2 # A=com.example.activitylaunchmode U= sz=}
Run #: ActivityRecord{33f3f7cd u0 com.example.activitylaunchmode/.ThirdActivity t53}
Run #: ActivityRecord{e5f9ea5 u0 com.example.activitylaunchmode/.MainActivity t53}

      能看到Task中现在只有两个Activity,ThirdActivity并没有重新创建,靠后的一个MainActivity也被弹出栈,从log也能看出调用了onNewIntent方法,

  

  4)singleInstance: 只有一个实例,运行于独立的task,启动此Activity的时候如果已经创建,则不会重新创建

    FourActivity的启动模式是singleInstance,点击MainActivity中的Button4,会启动FourActivity

    通过adb shell dumpsys activity命令,我们能看到两个Activity在不同的Task中,    

    Task id #
TaskRecord{11be8b0d # A=com.example.activitylaunchmode U= sz=}
Intent { flg=0x10000000 cmp=com.example.activitylaunchmode/.FourActivity }
Hist #: ActivityRecord{1cd2b9e5 u0 com.example.activitylaunchmode/.FourActivity t55}
Intent { flg=0x10000000 cmp=com.example.activitylaunchmode/.FourActivity }
ProcessRecord{358d5ac2 :com.example.activitylaunchmode/u0a134}
Task id #
TaskRecord{12e2f0d3 # A=com.example.activitylaunchmode U= sz=}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x30200000 cmp=com.example.activitylaunchmode/.MainActivity }
Hist #: ActivityRecord{374dcd03 u0 com.example.activitylaunchmode/.MainActivity t54}
Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x30200000 cmp=com.example.activitylaunchmode/.MainActivity bnds=[,][,] }
ProcessRecord{358d5ac2 :com.example.activitylaunchmode/u0a134} Running activities (most recent first):
TaskRecord{11be8b0d # A=com.example.activitylaunchmode U= sz=}
Run #: ActivityRecord{1cd2b9e5 u0 com.example.activitylaunchmode/.FourActivity t55}
TaskRecord{12e2f0d3 # A=com.example.activitylaunchmode U= sz=}
Run #: ActivityRecord{374dcd03 u0 com.example.activitylaunchmode/.MainActivity t54}

    如果再点击FourActivity中的Button4,也不会重新创建,从log可以看出,会调用onNewIntent方法,这里就不在贴activity的信息。

     adb shell dumpsys activity activities  也可以看到Task中各个activity的 launchMode.

    

上一篇:PI-webservice05-SAP调用外部webservice


下一篇:zk客户端的ClientCnxn类