配置Activity时可指定android:launchMode属性,该属性用于配置该Activity的加载模式,该属性支持如下4个属性值。

  • standard:标准模式,这是默认的加载模式。
  • singleTop:Task顶单例模式。
  • singleTask:Task内单例模式。
  • singleInstance:全局单例模式。

Android采用Task来管理多个Activity,当我们启动一个应用时,Android就会为之创建一个Task,然后启动这个应用的入口Activity(即<intent-filter.../>中配置为MAIN和LAUNCHER的Activity)。

Adroid的Task是一个有点麻烦的概念——因为Android并没有为Task提供API,因此开发者无法真正去访问Task,只能调用Activity的getTaskId()方法来获取它所在的Task的ID。事实上,我们可以把Task理解成Activity栈,Task以栈的形式来管理Activiy:先启动的Activity被放在Task栈底,后启动的Activity被放在Task栈顶。

那么Activity的加载模式,就负责管理实例化、加载Activity的方式、并可以控制Activity与Task之间的加载关系。

下面详细介绍这4种加载模式。

  1、standard加载模式

每次通过这种模式来启动目标Activity时,Android总会为目标Activity创建一个新的实例,并将该Activity添加到当前Task栈中——这种模式不会启动新的Task,新Activity将被添加到原有的Task中。

下面的示例使用了standard模式来不断启动自身。

package com.example.studyactivity;

import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView; public class StandardTest extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout layout=new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
this.setContentView(layout);
//创建一个TextView来显示该Activity和它所在的Task ID
TextView tv=new TextView(this);
tv.setText("Activity为"+this.toString()+"\n"+",Task ID为:"+this.getTaskId());
Button button=new Button(this);
button.setText("启动StardardTest");
//添加TextView和Button
layout.addView(tv);
layout.addView(button);
//为button添加事件监听器,当单击该按钮时启动StandardTest
button.setOnClickListener(new OnClickListener(){ @Override
public void onClick(View v) {
// TODO Auto-generated method stub
//创建启动StardardTest的Intent
Intent intent=new Intent(StandardTest.this,StandardTest.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.standard_test, menu);
return true;
} }

正如上面的粗体字代码所示,每次单击按钮,程序将会再次启动StandardTest   Activity,程序配置该Activity时无须指定launchMode属性,该Activty默认采用standard加载模式。

运行该程序,多次单击程序界面上的“启动StandardTest”按钮,程序将会不断启动新的StandardTest实例(不同Activity实例的hashCode值有差异),但它们所在的Task ID总是相同的——这表明这种加载模式不会使用全新的Task。

standard加载模式的示意图如图4.22所示。

正如图4.22所示,当用户低年级手机的“返回”键时,系统将会“逐一”从Activity栈顶删除Activity实例。

2、singleTop模式

     这种模式与standard模式基本相似,但有一点不同:当将要被启动的目标Activity已经位于Task栈顶时,系统不会重新创建目标Activity的实例,而是直接复用已有的Activity实例。

如果将上面实例中StandardTest Activity的加载模式改为standard加载模式,无论用户点击多少次按钮,界面上的程序将不会有任何变化。

如果将要比启动的目标Activity没有位于Task栈顶,此时系统会重新创建目标Activity的实例,并将它加载到Task的栈顶——此时与standard模式完全相同。

    3、singleTask模式

     采用这种加载模式的Activity在同一个Task内只有一个实例,当系统采用singleTask模式启动Activity时,可分为如下三种情况:

  • 如果将要启动的目标Activity不存在,系统将会创建目标Activity的实例,并将它加入Task栈顶。
  • 如果将要启动的目标Activity已经位于栈顶,此时与singleTop模式的行为相同。
  • 如果将要启动的目标Activity已经存在、但没有位于Task栈顶,系统将会把位于该Activity上面的所有Activity移出Task栈,从而使目标Activity转入栈顶。

   4、singleInstance模式

    这种加载模式下,系统保证无论从哪个Task中启动目标Activity,只会创建一个目标Activity实例,并会启动一个全新的Task栈来装载该Activity实例。

当系统采用singelInstance模式启动目标Activity时,可分为如下两种情况。

  • 如果将要启动的目标Activity不存在,系统会先创建一个全新的Task、再创建目标Activity的实例,并将它加入新的Task的栈顶。
  • 如果将要启动的目标Activity已经存在,无论它位于哪个应用程序中,无论它位于哪个Task中,系统将会把该Activity所在的Task转到前台,从而使该Activity显示出来。

需要指出的是,采用singleInstance模式加载Activity总是位于Task栈顶,采用singleInstance模式加载Activity所在Task只包含该Activity。

下面示例中的SingleInstanceTest中包含一个按钮,当用户单击该按钮时,系统启动SingleInstanceSecondTest,程序清单如下。

package com.example.studyactivity;

import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView; public class SingleInstanceTest extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout layout=new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
this.setContentView(layout);
//创建一个TextView来显示该Activity和它所在Task ID
TextView tv=new TextView(this);
tv.setText("Activity为:"+this.toString()+"\n"+",Task ID为:"+this.getTaskId());
Button button=new Button(this);
button.setText("启动SingleInstanceSecondTest");
layout.addView(tv);
layout.addView(button);
//为button添加事件监听器,当单击该按钮时启动SingleInstanceSecondTest
button.setOnClickListener(new OnClickListener(){ @Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent=new Intent(SingleInstanceTest.this,SingleInstanceSecondTest.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.single_instance_test, menu);
return true;
} }

上面的粗体字代码指定单击按钮时将会启动SingleInstanceSecondTest,将该SingleInstanceSecondTest配置成singleInstance加载模式,并且将该Activity的exported属性配置成true——表明该Activity可被其他应用启动。

配置该Activity的配置片段如下:

 <activity
android:name="com.example.studyactivity.SingleInstanceSecondTest"
android:label="@string/title_activity_single_instance_second_test"
android:exported="true"

android:launchMode="singleInstance"
>
<intent-filter> <!-- 指定该Activity能响应Action为指定字符串的Intent -->
<action android:name="com.example.intent.action.CRAZY_T_ACTION" /> <category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

配置该Activity时,将它的exported属性设为true,表明允许通过其他程序来启动该Activity,配置该Activity时还配置了<intent-filter.../>子元素,这表明该Activity可通过隐式Intent启动。

运行该示例,系统默认显示SingleInstanceTest,当用户单击该Activity界面上的按钮时,系统将会采用singleInstance模式加载SingleInstanceSecondTest:系统启动新的TaskTask、并用新的Task加载新创建的SingleInstanceSecondTest实例,SingleInstanceSecondTest总是位于该新Task的栈顶。

另一个示例将采用隐式Intent再次启动该SingleInstanceSecondTest,下面是采用隐式Intent启动SingleInstanceSecondTest的示例的代码。

package com.example.studyactivity;

import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView; public class SingleInstanceOtherTest extends Activity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LinearLayout layout=new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
setContentView(layout);
//创建一个TextView来显示该Activity和它所在的Task ID
TextView tv=new TextView(this);
tv.setText("Activity为:"+this.toString()+"\n"+",Task ID为:"+this.getTaskId());
Button button=new Button(this);
button.setText("启动SingleInstanceSecondTest");
//添加TextView和Button
layout.addView(tv);
layout.addView(button);
//为button添加事件监听器,使用隐式Intent启动目标Activity
button.setOnClickListener(new OnClickListener(){ @Override
public void onClick(View v) {
// TODO Auto-generated method stub
//使用隐式Intent启动SingleInstanceSecondTest
Intent intent=new Intent();
intent.setAction("com.example.intent.action.CRAZY_T_ACTION"
);
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.single_instance_other_test, menu);
return true;
} }

运行该示例,系统默认显示SingleInstanceOtherTest,当用户单击该Activity界面上的按钮时,系统将采用隐式Intent来启动SingleInstanceSecondTest,注意SingleInstanceSecondTest的加载模式是singleInstance,如果前一个示例还未退出,无论SingleInstanceSecondTest所在的Task是否位于前台,系统将再次把SingleInstanceSecondTest所在的Task转入前台,从而将SingleInstanceSecondTest显示出来。

Activity的生命周期与加载模式——Activity的4种加载模式的更多相关文章

  1. Activity 的生命周期与加载模式

    当Activity 处于Android 应用中运行时,它的活动状态由 Android 以 Activity 栈的形式管理.当前活动的Activity位于栈顶.随着不同应用的运行,每个Activity都 ...

  2. 十分钟掌握Activity的生命周期与启动模式

    1. Activity的生命周期 正常情况下的Activity生命周期如下图所示(来自Android Developer): 当资源相关的系统配置变更时(比如设备屏幕方向改变,键盘可见性变化),会导致 ...

  3. Activity 之生命周期

    Activity 之生命周期 本文内容: 1. Activity 介绍 2. Activity 的生命周期 2.1 生命周期图 2.2 常见情况下生命周期的回调 2.3 关于生命周期常见问题 2.4 ...

  4. 深入了解Activity-生命周期

    一 介绍 Activity是android中使用最为频繁的组件,在官方文档中是这样描述的:An activity is a single, focused thing that the user ca ...

  5. Android Activity的生命周期详解

    应用程序中,一个Activity通常就是一个单独的屏幕,它上面可以显示一些控件也可以监听并处理用户的事件做出响应. Activity之间通过Intent进行通信.在Intent 的描述结构中,有两个最 ...

  6. Activity的生命周期

    Activity的生命周期 以往我们实现页面间的跳转都是实例化Intent类的对象,但是页面在我们眼前的出现与消失没有我们所看到的那么简单,它有一个复杂的生命周期,一个页面的出现,被覆盖,再次出现,被 ...

  7. 浅谈Android中Activity的生命周期

    引言 我想对于Android开发人员来说,Activity是再熟悉不过了,今天我们就来探讨下Activity的生命周期.熟悉的掌握Activity对于开发健壮的Android应用程序来说至关重要.下面 ...

  8. 横竖屏切换时,Activity的生命周期

    横竖屏切换时,Activity的生命周期 1.新建一个Activity,并把各个生命周期打印出来 2.运行Activity,得到如下信息 onCreate-->onStart-->onRe ...

  9. Android 横屏切换竖屏Activity的生命周期(转)

    曾经遇到过一个面试题,让你写出横屏切换竖屏Activity的生命周期.现在给大家分析一下他切换时具体的生命周期是怎么样的:  1.新建一个Activity,并把各个生命周期打印出来  2.运行Acti ...

  10. 横竖屏切换时候Activity的生命周期的总结

    1.新建一个Activity,并把各个生命周期打印出来 2.运行Activity,得到如下信息 onCreate--> onStart--> onResume--> 3.按crtl+ ...

随机推荐

  1. 转:C#生成唯一值的方法汇总

    这篇文章主要介绍了C#生成唯一值的方法汇总,有需要的朋友可以参考一下 生成唯一值的方法很多,下面就不同环境下生成的唯一标识方法一一介绍,作为工作中的一次总结,有兴趣的可以自行测试: 一.在 .NET ...

  2. 如何把mysql的ID归0?

    如何把mysql的ID归0 可以归0的,truncate table + 表名     就行了

  3. webapp之路--百度手机前端经验(转)

    看了之后收获很大,分享一下: 本文将围绕我半年来在移动前端工程化做的一些工作做的总结,主要从localstorage缓存和版本号管理,模块化,静态资源渲染方式三个方面总结手机百度前端一年内沉淀的解决方 ...

  4. TCP四次挥手

    TCP 四次挥手      TCP的连接的拆除需要发送四个包,因此称为四次挥手(four-way handshake).客户端或服务器均可主动发起挥手动作,在socket编程中,任何一方执行close ...

  5. [算法] kruskal最小生成树算法

    #include <stdio.h> #include <stdlib.h> #define MAX 100 int N, M; struct Edge { int u,v; ...

  6. 完美解决ie浏览器location.href不刷新页面的问题,进入页面只刷新一次

    /* ie不刷新列表bug */try{ var agent = navigator.userAgent.toLowerCase(); var ieflag = /(msie\s|trident.*r ...

  7. CI如何在子目录下可以设置默认控制器

    CI建立大型大型的应用程序,需要创建子文件夹在application/controllers下建立文件夹app1app1目录下有多个控制器,ca.php,cb.php我希望定义app1下的默认控制器, ...

  8. Python正则表达式学习笔记

    [] 字符类,只要匹配里面的任意字符,都算匹配 . 元字符,可以匹配除换行符之外的所有字符 大小写敏感,但是可以关闭 \d  可以匹配0-9中的任意数字 {3}大括号里面的数字,边上前面一个字符匹配的 ...

  9. Animation动画

    Animation:  1,AlphaAnimation, 透明度动画, 2, RotateAnimation, 旋转动画, 3,ScaleAnimation, 缩放动画 4,TranslateAni ...

  10. python模块 ---logging模块

    摘要by crazyhacking: 与log4cxx一样,分为三个部分,logger, handler,formatter. 详细内容参考:1官网http://docs.python.org/2/h ...