在Android开发中,启动一个新的activity我们可以使用startActivity或startActivityForResult,Android系统使用栈的方式来管理一个APP的页面显示与保存顺序,那么,在新启动一个activity时,栈的里面是每次都新增实例还是只有一个实例呢?这个与在清单文件注册一个activity使用的参数:launchMode有关。

  Acvitity启动模式有4种:

  1. 标准模式standard

  2. 栈顶复用模式singleTop

  3. 栈内复用模式singleTask

  4. 单实例模式singleInstance

  为了测试这几种模式,新建了一个测试工程:https://github.com/linjk/TestLaunchMode,可以下载代码进行测试。

  1. 新建测试项目:

  

  2. 新建一个类,用于管理activity栈和打印当前栈的activity名字,代码如下:

package cn.linjk.testlaunchmode.utils;

import android.app.Activity;
import android.util.Log; import java.util.Stack; /**
* Created by LinJK on 05/12/2016.
*
* <p>Class to manage activity stack, base activity
* can use it.</p>
*
* @version 1.0
*/ public class ActivityStackManager { /**
* Single Instance
* @return
*/
public static ActivityStackManager getINSTANCE() {
if (null == INSTANCE) {
INSTANCE = new ActivityStackManager();
}
return INSTANCE;
} //region Add and remove activity
public void addActivity(Activity ac) {
if (null == stack_activity) {
stack_activity = new Stack<>();
}
stack_activity.add(ac); printAllActivityName();
} public void removeActivity(Activity ac) {
if (ac != null) {
stack_activity.remove(ac);
}
printAllActivityName();    
}
//endregion //region Print Activity Stack Info public void printAllActivityName() {
for (int i = stack_activity.size()-1; i >= 0; i--) {
Log.d(TAG, "[" + i + "]Activity Name: " + stack_activity.get(i).getClass().getName());
}
}
//endregion /////////////////////////////////////////////////////////////////////////////// private ActivityStackManager() {} private static final String TAG = ActivityStackManager.class.getSimpleName(); private static ActivityStackManager INSTANCE;
private static Stack<Activity> stack_activity;

  3. MainActivity作为第一个页面,这里再新建第二个activity:

  两个页面的布局xml文件分别如下:

  MainActivity:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
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.linjk.testlaunchmode.activity.MainActivity"> <Button
android:id="@+id/btn_start_new_activity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="启动新的activity_Main"/>
</RelativeLayout>

    ActivitySecond:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"> <Button
android:id="@+id/btn_start_new_activity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="启动新的activity_Second"/> </LinearLayout>

    MainActivity.java:

    

package cn.linjk.testlaunchmode.activity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button; import cn.linjk.testlaunchmode.base.activity.BaseActivity;
import cn.linjk.testlaunchmode.R; public class MainActivity extends BaseActivity { @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); btnStartNewActivity = (Button)findViewById(R.id.btn_start_new_activity); btnStartNewActivity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View pView) {
startActivity(new Intent(MainActivity.this, ActivitySecond.class));
}
});
} ////////////////////////////////////////////////////// private Button btnStartNewActivity; }

    ActivitySecond.java:

package cn.linjk.testlaunchmode.activity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button; import cn.linjk.testlaunchmode.R;
import cn.linjk.testlaunchmode.base.activity.BaseActivity; /**
* Created by LinJK on 05/12/2016.
*/ public class ActivitySecond extends BaseActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second); btnStartNewActivity = (Button)findViewById(R.id.btn_start_new_activity); btnStartNewActivity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View pView) {
startActivity(new Intent(ActivitySecond.this, ActivitySecond.class));
}
});
} ////////////////////////////////////////////////////// private Button btnStartNewActivity;
}

    在清单文件中的application节点,activity配置如下,都是默认的启动模式配置:

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".activity.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity> <activity android:name=".activity.ActivitySecond"/>
</application>

  4. 启动模式测试:

    APP在启动后,未配置情况下,默认会分配一个任务栈,所有的actiivty默认都会在该栈启动与退出,这是通过任务共用性(Affinities)完成的,任务共用性

为这个运行一个或多个Activity的Task提供了一个独特的静态名称,默认的一个活动的任务共用性(Affinity)是实现了该Activity的.apk包的名字,可以在acitivty的onCreate启动后通过getTaskID获取其所在任务栈id,新启动一个页面后,新的页面会在启动它的任务栈打开,如果加了标志:FLAG_ACTIVITY_NEW_TASK,那个这两个activity就会在两个不同的任务栈里面。

    注意,只有actvitivy的上下文才可以启动activity,因为这才存在任务栈,而application级别的,如getApplicationContext().startActivity(new Intent(MainActivity.this, ActivitySecond.class));则无法启动,因为application的上下文并不会分配上下文,需要加新增任务栈标记位:FLAG_ACTIVITY_NEW_TASK。

  4.1 standard

    从第一个页面进入第二个页面后,在第二个页面再启动第二个页面,打印的日志如下:

    可以看到,默认的standard模式,每次都会新建实例来启动activity.

  4.2 singleTop

    配置第二个页面的启动模式:

<activity
android:launchMode="singleTop"
android:name=".activity.ActivitySecond"/>

    第一次进入第二个页面日志如下:

    再点击启动新页面:

    这是发现只打印多红色圈住的这一句日志,没调用onCreate() ?

    查看一下activity源码,发现这部分:

    

    原来,配置了singleTop模式后,会调用onNewIntent()重新加载页面,我们修改ActivitySecond代码,增加如下部分:

@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent); Log.d("ActivitySecond", "[Task ID]" + getTaskId());
ActivityStackManager.getINSTANCE().printAllActivityName(); }

    重复刚才操作,日志如下:

    可以发现,当栈顶是ActivitySecond,重复打开时只有一个ActivitySecond实例。注意,如果ActivitySecond不是在栈顶,新打开还是会新建的!

  4.3 singleTask

    与singleTop类似,就不重复测试了,大概说明一下差异:

    1. singleTop是在栈顶在复用,不在栈顶则新建,而singleTask是只要在任务栈内就复用,不会新建

    2. singleTask模式中,默认具有clearTop效果,如果当前栈状态ABCD, 此时新建B,会把B页面移到栈顶,并清除原来B以上的栈页面,此时变为AB。

    3. 使用singleTask,可以在清单文件加上taskAffinity属性,其值不能与包名一致,否则会无效,这样,后面以singleTask启动的activity,如果该属性一样,就会分配到同一个新的任务栈中。

    (

    附:如一个activity的taskAffnity与allowTasReparenting属性配合使用,那么该activity可以在两个app的任务栈共用,假设该activity叫C,现有两个应用A、B,名叫activity的C注册在B应用的清单文件中,配置如下:

<activity
android:name=".activity.ActivitySecond">
<intent-filter>
<action android:name="android.intent.action.TESTLAUNCHMODE_SECOND_ACTIVITY"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>

    则应用A中启动该activity可如下启动:

Intent intent = new Intent("android.intent.action.TESTLAUNCHMODE_SECOND_ACTIVITY"); 
startActivity(intent);

    此时,如果应用B打开C,会把C从应用A的任务栈中转移过来。

    )

  4.4 singleInstance

    singleTask的加强版本,以此模式启动的activtiy,系统会新建一个任务栈并把它独立存放,这个activity后面会被重复使用,直到系统把该任务栈kill掉。

Android开发之---Activity启动模式的更多相关文章

  1. android:process结合activity启动模式的一次实践

    会有这样的场景,一个应用崩溃了,而导致的该应用崩溃的原因是,该应用占用的内存大小超过了系统分配给它的最大堆大小.对象的分配,是发生在堆(heap)上面的,系统分配给每个应用的最大堆大小是固定的. 假设 ...

  2. Android开发9——Activity的启动模式

    在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.在Android中Activity的启动模式决定了Activity的启动运行方式. 一. ...

  3. Android中Activity启动模式详解

    在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.在Android中Activity的启动模式决定了Activity的启动运行方式. An ...

  4. Android Activity 启动模式详解

    最近有群里的朋友问我 Activity的四种启动模式分别是什么意思? 当初因为项目比较忙,草草的解释了下, Api文档中说的也只是一般,在这里就小记一下吧,以便有更多的朋友对Activity启动模式了 ...

  5. 【转】Android总结篇系列:Activity启动模式(lauchMode)

    [转]Android总结篇系列:Activity启动模式(lauchMode) 本来想针对Activity中的启动模式写篇文章的,后来网上发现有人已经总结的相当好了,在此直接引用过来,并加上自己的一些 ...

  6. AndroidのActivity启动模式

    Activity启动模式      .概念      Activity启动模式定义了Activity启动的规则,它决定着Activity的实例创建与重用与否    .属性     Activity的启 ...

  7. Android组件体系之Activity启动模式解析

    本文主要分析Activity的启动模式及使用场景. 一.Activity启动模式浅析 1.standard 标准模式,系统默认的启动模式.在启动Activity时,系统总是创建一个新的Activity ...

  8. Activity启动模式的深入分析

    网上关于Activity启动模式的文章许多.可是看起来都千篇一律,看完之后我们都能理解这4种启动模式.只是官方api对singleTask这个启动模式解释有些争议,导致我事实上并没有真正理解这几种模式 ...

  9. Activity启动模式 及 Intent Flags 与 栈 的关联分析

     http://blog.csdn.net/vipzjyno1/article/details/25463457    Android启动模式Flags栈Task   目录(?)[+] 什么是栈 栈 ...

随机推荐

  1. 简单所以不要忽视,关于\r\n和\n程序员应了解的实际应用

    众所周知,\r叫回车符,\n叫换行符. 由于历史原因,windows环境下的换行符是\r\n;(文章最后会稍微解释这个历史原因) linux和html等开源或公开标准中的换行符是\n. 记录这篇笔记的 ...

  2. Tp缓存

    系统默认的缓存方式是采用File方式缓存,我们可以在项目配置文件里面定义其他的缓存方式,例如,修改默认的缓存方式为Xcache(当然,你的环境需要支持Xcache) 对于File方式缓存下的缓存目录下 ...

  3. 删除部分字符使其变成回文串问题——最长公共子序列(LCS)问题

    先要搞明白:最长公共子串和最长公共子序列的区别.    最长公共子串(Longest Common Substirng):连续 最长公共子序列(Longest Common Subsequence,L ...

  4. 基于MST的立体匹配及相关改进(A Non-Local Cost Aggregation Method for Stereo Matching)

    怀着很纠结的心情来总结这篇论文,这主要是因为作者提虽然供了源代码,但是我并没有仔细去深究他的code,只是把他的算法加进了自己的项目.希望以后有时间能把MST这一结构自己编程实现!! 论文题目是基于非 ...

  5. Bioinformatics Glossary

    原文:http://homepages.ulb.ac.be/~dgonze/TEACHING/bioinfo_glossary.html Affine gap costs: A scoring sys ...

  6. wpf *和auto的区别

    Auto 表示自动适应显示内容的宽度, 如自动适应文本的宽度,文本有多长,控件就显示多长. * 则表示按比例来分配宽度. <ColumnDefinition Width="3*&quo ...

  7. JSVirtualMachine与JSContext

    JSVirtualMachine相当于进程: JSContext相当于线程:

  8. 深入理解springAOP

    概念:AOP(Aspect-Oriented Programming)即面向切面编程.它是对传统的OOP(面向对象)编程的一种补充,在OOP中往往一个对象有什么行为我们就定义什么方法,对象与对象之间存 ...

  9. unity之初识shader

    自己做个总结先.当然文中很多内容都是从各位大神的文档当中看的.我只是站在巨人的肩膀上.       首先什么是shader?其实就是一个在显示屏当中的显示程序,俗称着色器.它可以定义物体在硬件显示屏当 ...

  10. Nessus的安装/激活/更新

    0x1,安装 百度:Nessus,随意下载一个就好了. 0x2,激活 开启代理,获取register code,如图: 获取到register code,填写,进行激活,意外报错: NOTICE: A ...