你的位置:首页 > 操作系统

[操作系统]Android Activity各启动模式的差异


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

 

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

AndoirdManifest文件

<??><manifest ="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>

View Code

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

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

    SecondActivity ---->  singleTop

    ThirdActivty     ---->  singleTask

    FourActivity     ---->  singleInstance

布局文件 activity_main.

<RelativeLayout ="http://schemas.android.com/apk/res/android"  ="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>

View Code

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

View Code

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

View Code

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

View Code

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

View Code

 各个启动模式差异探究:

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

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

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

  Task id #48   TaskRecord{2cfa2efd #48 A=com.example.activitylaunchmode U=0 sz=2}   Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x30200000 cmp=com.example.activitylaunchmode/.MainActivity }    Hist #1: ActivityRecord{37783c3a u0 com.example.activitylaunchmode/.MainActivity t48}     Intent { cmp=com.example.activitylaunchmode/.MainActivity }     ProcessRecord{358547f2 29163:com.example.activitylaunchmode/u0a134}    Hist #0: 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=[801,812][1047,1060] }     ProcessRecord{358547f2 29163:com.example.activitylaunchmode/u0a134}  Running activities (most recent first):   TaskRecord{2cfa2efd #48 A=com.example.activitylaunchmode U=0 sz=2}    Run #1: ActivityRecord{37783c3a u0 com.example.activitylaunchmode/.MainActivity t48}    Run #0: ActivityRecord{363c8000 u0 com.example.activitylaunchmode/.MainActivity t48}

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

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

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

  Task id #51   TaskRecord{fb41e01 #51 A=com.example.activitylaunchmode U=0 sz=2}   Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x30200000 cmp=com.example.activitylaunchmode/.MainActivity }    Hist #1: ActivityRecord{1ea62f6c u0 com.example.activitylaunchmode/.SecondActivity t51}     Intent { cmp=com.example.activitylaunchmode/.SecondActivity }     ProcessRecord{69b44a6 30061:com.example.activitylaunchmode/u0a134}    Hist #0: 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=[801,812][1047,1060] }     ProcessRecord{69b44a6 30061:com.example.activitylaunchmode/u0a134}  Running activities (most recent first):   TaskRecord{fb41e01 #51 A=com.example.activitylaunchmode U=0 sz=2}    Run #1: ActivityRecord{1ea62f6c u0 com.example.activitylaunchmode/.SecondActivity t51}    Run #0: ActivityRecord{27f7bb0a u0 com.example.activitylaunchmode/.MainActivity t51}

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

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

  Task id #52   TaskRecord{147eed75 #52 A=com.example.activitylaunchmode U=0 sz=3}   Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x30200000 cmp=com.example.activitylaunchmode/.MainActivity }    Hist #2: ActivityRecord{2bf26a69 u0 com.example.activitylaunchmode/.MainActivity t52}     Intent { cmp=com.example.activitylaunchmode/.MainActivity }     ProcessRecord{3e2f10a 30540:com.example.activitylaunchmode/u0a134}    Hist #1: ActivityRecord{147e2631 u0 com.example.activitylaunchmode/.ThirdActivity t52}     Intent { flg=0x10000000 cmp=com.example.activitylaunchmode/.ThirdActivity }     ProcessRecord{3e2f10a 30540:com.example.activitylaunchmode/u0a134}    Hist #0: 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=[801,812][1047,1060] }     ProcessRecord{3e2f10a 30540:com.example.activitylaunchmode/u0a134}  Running activities (most recent first):   TaskRecord{147eed75 #52 A=com.example.activitylaunchmode U=0 sz=3}    Run #2: ActivityRecord{2bf26a69 u0 com.example.activitylaunchmode/.MainActivity t52}    Run #1: ActivityRecord{147e2631 u0 com.example.activitylaunchmode/.ThirdActivity t52}    Run #0: ActivityRecord{4e87389 u0 com.example.activitylaunchmode/.MainActivity t52}

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

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

  Task id #53   TaskRecord{2553d3b2 #53 A=com.example.activitylaunchmode U=0 sz=2}   Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x30200000 cmp=com.example.activitylaunchmode/.MainActivity }    Hist #1: ActivityRecord{33f3f7cd u0 com.example.activitylaunchmode/.ThirdActivity t53}     Intent { flg=0x10000000 cmp=com.example.activitylaunchmode/.ThirdActivity }     ProcessRecord{1cdd8f03 30924:com.example.activitylaunchmode/u0a134}    Hist #0: 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=[801,812][1047,1060] }     ProcessRecord{1cdd8f03 30924:com.example.activitylaunchmode/u0a134}  Running activities (most recent first):   TaskRecord{2553d3b2 #53 A=com.example.activitylaunchmode U=0 sz=2}    Run #1: ActivityRecord{33f3f7cd u0 com.example.activitylaunchmode/.ThirdActivity t53}    Run #0: ActivityRecord{e5f9ea5 u0 com.example.activitylaunchmode/.MainActivity t53}

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

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

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

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

  Task id #55   TaskRecord{11be8b0d #55 A=com.example.activitylaunchmode U=0 sz=1}   Intent { flg=0x10000000 cmp=com.example.activitylaunchmode/.FourActivity }    Hist #0: ActivityRecord{1cd2b9e5 u0 com.example.activitylaunchmode/.FourActivity t55}     Intent { flg=0x10000000 cmp=com.example.activitylaunchmode/.FourActivity }     ProcessRecord{358d5ac2 31514:com.example.activitylaunchmode/u0a134}  Task id #54   TaskRecord{12e2f0d3 #54 A=com.example.activitylaunchmode U=0 sz=1}   Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x30200000 cmp=com.example.activitylaunchmode/.MainActivity }    Hist #0: 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=[801,812][1047,1060] }     ProcessRecord{358d5ac2 31514:com.example.activitylaunchmode/u0a134}  Running activities (most recent first):   TaskRecord{11be8b0d #55 A=com.example.activitylaunchmode U=0 sz=1}    Run #1: ActivityRecord{1cd2b9e5 u0 com.example.activitylaunchmode/.FourActivity t55}   TaskRecord{12e2f0d3 #54 A=com.example.activitylaunchmode U=0 sz=1}    Run #0: ActivityRecord{374dcd03 u0 com.example.activitylaunchmode/.MainActivity t54}

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

 

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