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>
View Code

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

 各个启动模式差异探究:

  1)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}

  

  2)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}

  

  3)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方法,

  

  4)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.

 

 

    

posted on 2016-07-06 14:44  梦想,就在不远方  阅读(655)  评论(0编辑  收藏  举报

导航