Android学习笔记——Activity的四种启动模式

1.Activity的管理机制

  Android的管理主要是通过Activity栈来进行的。当一个Activity启动时,系统根据其配置或调用的方式,将Activity压入一个特定的栈中,系统处 于运行(Running or Resumed)状态。当按Back键或触发finish()方法时,Activity会从栈中被压出,进而被销毁,当有新的Activity压入栈时, 如果原Activity仍然可见,则原Activity的状态将转变为暂停(Paused)状态,如果原Activity完全被遮挡,那么其状态将转变为 停止(Stopped)。

2.Task

  Task按我的理解,Activity对应的task,就相当于数据所对应的一种数据结构栈(Stack),一个Task对应一个Activity栈。

3.启动模式的作用

  Activity启动模式就是属于Activity配置属性之一,叫它具有四种启动模式,分别是:1.standard ,2.singleTop,3.singleTask,4.singleInstance,一般如果不显示声明,默认为standard模式。launchMode 在多个Activity跳转的过程中扮演着重要的角色,它可以决定是否生成新的Activity实例,是否重用已存在的Activity实例,是否和其他 Activity实例公用一个task里。

4.模式说明
下面通过一个实例具体说明四种启动模式的区别。

  • standard模式:这是系统默认的启动模式,这种模式就是创建一个Activity压入Task容器栈中,当当前Activity激活,并处在和用户交互时,此Activity弹出栈顶,当finish()的时候,在任务栈中销毁该实例。
在布局文件activity_first.xml中添加一个Button和一个TextView控件,并给Button添加一个onClick事件。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_first"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="cn.edu.bzu.activitydemo.FirstActivity">
   <Button
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="toFirst"
       android:drawableLeft="@mipmap/ic_launcher"
       android:id="@+id/btnClick"/>

   <TextView
       android:text="第一个Activity"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:id="@+id/textView"
       android:layout_below="@+id/btnClick"
       android:layout_alignParentLeft="true"
       android:layout_alignParentStart="true"
       android:textSize="40sp" />
RelativeLayout>
在FirstActivity中编写onClick事件,并打印当前对象的地址值。
public class FirstActivity extends AppCompatActivity {
    private Button btnClick;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
        Log.d("FirstActivity", this.toString());//调用toString()方法打印当前对象的地址值。
        btnClick = (Button) findViewById(R.id.btnClick);
        btnClick.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intent=new Intent(FirstActivity.this,FirstActivity.class);
                startActivity(intent);
            }
        });
    }
}

由于standard模式是系统默认的启动模式,所以无需修改清单文件。
Android学习笔记——Activity的四种启动模式_第1张图片
在Android Monitor窗口中创建一个新的过滤器first,Android学习笔记——Activity的四种启动模式_第2张图片Log Tag中输入FirstActivity,过滤出FirstActivity的地址值。如下图所示:Android学习笔记——Activity的四种启动模式_第3张图片由此可以发现每次点击按钮时都会出现一个新的地址值,即每次点击按钮跳转到本身是都会有一个新的Activity入栈,同样的每次点击返回按钮时,后入的Activity先出栈,所以需要一个一个出栈。


  • singleTop模式:这种模式首先会判断要激活的Activity是否在栈顶,如果在则不重新创建新的实例,复用当前的实例,如果不在栈顶,则在任务栈中创建实例。条件是是否在栈顶,而不是是否在栈中。
在布局文件activity_first.xml中添加一个Button和一个TextView控件,并给Button添加一个onClick事件。与上一个完全相同

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_first"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="cn.edu.bzu.activitydemo.FirstActivity">
   <Button
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="toFirst"
       android:drawableLeft="@mipmap/ic_launcher"
       android:id="@+id/btnClick"/>

   <TextView
       android:text="第一个Activity"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:id="@+id/textView"
       android:layout_below="@+id/btnClick"
       android:layout_alignParentLeft="true"
       android:layout_alignParentStart="true"
       android:textSize="40sp" />
RelativeLayout>
在FirstActivity中编写onClick事件,并打印当前对象的地址值。
public class FirstActivity extends AppCompatActivity {
    private Button btnClick;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
        Log.d("FirstActivity", this.toString());//调用toString()方法打印当前对象的地址值。
        btnClick = (Button) findViewById(R.id.btnClick);
        btnClick.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intent=new Intent(FirstActivity.this,FirstActivity.class);
                startActivity(intent);
            }
        });
    }
}

由于singleTop模式不是默认启动模式,所以需要修改清单文件AndroidManifest.xml。

 <activity
            android:name=".FirstActivity" android:launchMode="singleTop">//添加Activity的launchMode属性,修改启动模式。
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            intent-filter>
        activity>

Android学习笔记——Activity的四种启动模式_第4张图片
点击按钮,在Android Monitor窗口中查看过滤器first中的信息。发现只产生一个地址值,同样只需点击一次返还建即可退出。
Android学习笔记——Activity的四种启动模式_第5张图片
在singleTop模式下,跳转到本身是如果检测已存在一个栈,就不会再创建一个新栈。

  • singleTask模式: 这种模式启 动的目标Activity实例如果已经存在task容器栈中,不管当前实例处于栈的任何位置,是栈顶也好,栈底也好,还是处于栈中间,只要目标 Activity实例处于task容器栈中,都可以重用该Activity实例对象,然后,把处于该Activity实例对象上面全部Activity实 例清除掉,并且,task容器栈中永远只有唯一实例对象,不会存在两个相同的实例对象。所以,如果你想你的应用不管怎么启动目标Activity,都只有 唯一一个实例对象,就使用这种启动模式。

在布局文件activity_first.xml中添加一个Button和一个TextView控件,并给Button添加一个onClick事件。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_first"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="cn.edu.bzu.activitydemo.FirstActivity">
   <Button
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="toSecond"//跳转到第二个Activity
       android:drawableLeft="@mipmap/ic_launcher"
       android:id="@+id/btnClick"/>

   <TextView
       android:text="第一个Activity"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:id="@+id/textView"
       android:layout_below="@+id/btnClick"
       android:layout_alignParentLeft="true"
       android:layout_alignParentStart="true"
       android:textSize="40sp" />
RelativeLayout>
在布局文件activity_second.xml中添加一个Button和一个TextView控件,并给Button添加一个onClick事件。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_second"
    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="cn.edu.bzu.activitydemo.SecondActivity">
    <TextView
        android:text="第二个Activity"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView"
        android:layout_below="@+id/btnClick"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:textSize="40sp" />

RelativeLayout>
在FirstActivity中编写onClick事件,并打印当前对象的地址值,并重写onRestart()方法。
package cn.edu.bzu.activitydemo;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class FirstActivity extends AppCompatActivity {
    private Button btnClick;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
        Log.d("FirstActivity","Task id is"+getTaskId());
        btnClick=(Button)findViewById(R.id.btnClick);
        btnClick.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intent=new Intent(FirstActivity.this,SecondActivity.class);//点击到第二个Activity。
                startActivity(intent);
            }
        });
    }

    @Override
    protected void onRestart() {//重写onRestart()方法
        super.onRestart();
        Log.d("FirstActivity","onRestart()");
    }
}
在SecondActivity中编写onClick事件,并打印当前对象的地址值,并添加onDestroy()方法。
package cn.edu.bzu.activitydemo;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class SecondActivity extends AppCompatActivity {
    private Button btnClick;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        Log.d("FirstActivity","Task id is"+getTaskId());
        btnClick=(Button)findViewById(R.id.btnClick);
        btnClick.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intent=new Intent(SecondActivity.this,FirstActivity.class);//点击回到第一个Activity。
                startActivity(intent);
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("SecondActivity","onDestroy()");
    }
}
修改清单文件AndroidManifest.xml中第一个Activity的启动模式为singleTask,第二个Activity为默认启动模式。
<activity
            android:name=".FirstActivity" android:launchMode="singleTask">//修改第一个Activity的启动模式为singleTask。
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            intent-filter>
        activity>
        <activity android:name=".SecondActivity"/>

Android学习笔记——Activity的四种启动模式_第6张图片
由此可以发现,当启动模式为singleTask模式是,点击toSecond后到达第二个Activity页面,然后点击toFirst回到FirstActivity时,检测到第一个Activity已经入栈,所以会将第一个Activity之前的所有Activity全部出栈,所以只需点击一次返回键即可退出。

  • singleInstance模式:当该模式Activity实例在任务栈中创建后,只要该实例还在任务栈中,即只要激活的是该类型的Activity,都会通过调用实例的newInstance()方法重用该Activity,此时使用的都是同一个Activity实例,它都会处于任务栈的栈顶。此模式一般用于加载较慢的,比较耗性能且不需要每次都重新创建的Activity。

在布局文件activity_first.xml中添加一个Button和一个TextView控件,并给Button添加一个onClick事件。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_first"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="cn.edu.bzu.activitydemo.FirstActivity">
   <Button
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:text="toSecond"//跳转到第二个Activity
       android:drawableLeft="@mipmap/ic_launcher"
       android:id="@+id/btnClick"/>

   <TextView
       android:text="第一个Activity"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:id="@+id/textView"
       android:layout_below="@+id/btnClick"
       android:layout_alignParentLeft="true"
       android:layout_alignParentStart="true"
       android:textSize="40sp" />
RelativeLayout>
在布局文件activity_second.xml中添加一个Button和一个TextView控件,并给Button添加一个onClick事件。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_second"
    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="cn.edu.bzu.activitydemo.SecondActivity">
    <TextView
        android:text="第二个Activity"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView"
        android:layout_below="@+id/btnClick"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:textSize="40sp" />

RelativeLayout>
在布局文件activity_third.xml中添加一个TextView控件。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_third"
    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="cn.edu.bzu.activitydemo.ThirdActivity">
    <TextView
        android:text="第三个Activity"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textView"
        android:layout_below="@+id/btnClick"
        android:textSize="40sp" />

RelativeLayout>
在FirstActivity中编写onClick事件,并打印当前对象的地址值。
public class FirstActivity extends AppCompatActivity {
    private Button btnClick;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);
        Log.d("FirstActivity", "Task id is"+getTaskId());//进行日志输出,打印TaskId
        btnClick = (Button) findViewById(R.id.btnClick);
        btnClick.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intent=new Intent(FirstActivity.this,FirstActivity.class);
                startActivity(intent);
            }
        });
    }
}
在SecondActivity中编写onClick事件,并打印当前对象的地址值,并添加onDestroy()方法。
package cn.edu.bzu.activitydemo;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class SecondActivity extends AppCompatActivity {
    private Button btnClick;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        Log.d("FirstActivity","Task id is"+getTaskId());//进行日志输出,打印TaskId
        btnClick=(Button)findViewById(R.id.btnClick);
        btnClick.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intent=new Intent(SecondActivity.this,ThirdActivity.class);//点击回到第三个Activity。
                startActivity(intent);
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("SecondActivity","onDestroy()");
    }
}
在第三个Activity中进行日志输出,打印TaskId。
package cn.edu.bzu.activitydemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

public class ThirdActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("ThirdActivity","Task id is"+getTaskId());
        setContentView(R.layout.activity_third);
    }
}
修改清单文件AndroidManifest.xml中第二个Activity的启动模式为singleInstance,第一个Activity为默认启动模式。
 <activity
        android:name=".FirstActivity" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        intent-filter>
    activity>
        <activity android:name=".SecondActivity" android:launchMode="singleInstance"/>//修改第二个Activity的启动模式为singleInstance
        <activity android:name=".ThirdActivity">activity>

Android学习笔记——Activity的四种启动模式_第7张图片
当点击运行,第一个Activity入栈,得到Task id。
Android学习笔记——Activity的四种启动模式_第8张图片
当点击ToSecond按钮时,进入第二个Activity,即第二个Activity重新开辟一个新栈,并得到相应的Task id。由此可见Task id与FirstActivity的Task id不同,即重新开辟一个新栈。
Android学习笔记——Activity的四种启动模式_第9张图片
Android学习笔记——Activity的四种启动模式_第10张图片
当点击ToThird按钮时,进入第三个Activity,即第三个Activity入栈,得到Task id。由此可见Task id与FirstActivity的Task id相同同,即与FirstActivity在同一个任务栈中。
Android学习笔记——Activity的四种启动模式_第11张图片
Android学习笔记——Activity的四种启动模式_第12张图片
点击返回键时直接回到FirstActivity中。

5.总结
总之,Android四大启动模式相当简单。默认standard模式,他是task容器栈可能存在相同的Activity实例;singletop模式 下,重用栈顶Activity实例,栈顶不存在,则创建新的Activity实例,该模式下有可能存在相同Activity实例;singletask模 式,task容器栈存在目标Activity实例,则重用该实例,task容器栈永远只有唯一activity实例,并且,其一是Activity实例被 清除掉。singleinstance模式,不同应用可以共享Activity实例,并且是处于不同容器栈中。

你可能感兴趣的:(Android,android,栈)