Android开发之---Activity启动模式
在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启动模式的更多相关文章
- android:process结合activity启动模式的一次实践
会有这样的场景,一个应用崩溃了,而导致的该应用崩溃的原因是,该应用占用的内存大小超过了系统分配给它的最大堆大小.对象的分配,是发生在堆(heap)上面的,系统分配给每个应用的最大堆大小是固定的. 假设 ...
- Android开发9——Activity的启动模式
在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.在Android中Activity的启动模式决定了Activity的启动运行方式. 一. ...
- Android中Activity启动模式详解
在Android中每个界面都是一个Activity,切换界面操作其实是多个不同Activity之间的实例化操作.在Android中Activity的启动模式决定了Activity的启动运行方式. An ...
- Android Activity 启动模式详解
最近有群里的朋友问我 Activity的四种启动模式分别是什么意思? 当初因为项目比较忙,草草的解释了下, Api文档中说的也只是一般,在这里就小记一下吧,以便有更多的朋友对Activity启动模式了 ...
- 【转】Android总结篇系列:Activity启动模式(lauchMode)
[转]Android总结篇系列:Activity启动模式(lauchMode) 本来想针对Activity中的启动模式写篇文章的,后来网上发现有人已经总结的相当好了,在此直接引用过来,并加上自己的一些 ...
- AndroidのActivity启动模式
Activity启动模式 .概念 Activity启动模式定义了Activity启动的规则,它决定着Activity的实例创建与重用与否 .属性 Activity的启 ...
- Android组件体系之Activity启动模式解析
本文主要分析Activity的启动模式及使用场景. 一.Activity启动模式浅析 1.standard 标准模式,系统默认的启动模式.在启动Activity时,系统总是创建一个新的Activity ...
- Activity启动模式的深入分析
网上关于Activity启动模式的文章许多.可是看起来都千篇一律,看完之后我们都能理解这4种启动模式.只是官方api对singleTask这个启动模式解释有些争议,导致我事实上并没有真正理解这几种模式 ...
- Activity启动模式 及 Intent Flags 与 栈 的关联分析
http://blog.csdn.net/vipzjyno1/article/details/25463457 Android启动模式Flags栈Task 目录(?)[+] 什么是栈 栈 ...
随机推荐
- WPF资源字典的使用【转】
资源字典出现的初衷就在于可以实现多个项目之间的共享资源,资源字典只是一个简单的XAML文档,该文档除了存储希望使用的资源之外,不做任何其它的事情. 1. 创建资源字典 创建资源字典的过程比较简单,只 ...
- IE下get传中文乱码的问题完美解决方案
前几天做项目的时候遇到需要在easyui的combobox的url中以get的方式传中文,出现乱码. $('#cc').combobox({ url : 'xxxAction.action?para= ...
- php 如何解决“您访问的域名有误或网页不存在”
对一个域名访问,在家访问正常,到办公室就总是看到下面的页面. 清楚浏览器浏览数据是一个解决途径.这里通过Chrome浏览做示例.通过标记路径,进入清除界面. 也可以在浏览器地址中输入 chrome:/ ...
- transition
transition: all 所有属性都将获得过渡效果. property 定义应用过渡效果的 CSS 属性名称列表,列表以逗号分隔 transition-duration 规定完成过渡效果需要多少 ...
- 【Codeforces715C&716E】Digit Tree 数学 + 点分治
C. Digit Tree time limit per test:3 seconds memory limit per test:256 megabytes input:standard input ...
- POJ2763 Housewife Wind
Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 9701 Accepted: 2661 Description Aft ...
- 【Beta】Scrum05
Info 由于12.9~12.11三天,PM和测试到上海参加比赛,期间PM对博客更新暂停,功能测试暂停,Scrum会议暂停,12.12日起补充及恢复之前未能完成的工作. 时间:2016.12.08 2 ...
- mysql关联表的复制
1. 复制被参照的表: CREATE TABLE clone_product_1 LIKE product_1; INSERT INTO clone_product_1 SELECT * FROM p ...
- ThinkPHP 事务处理 (事务回滚) 、异常处理
$tran_result = true; $trans = M(); $trans->startTrans(); try { ...
- oracle数据库_实例_用户_表空间之间的关系(转)
数据库:Oracle数据库是数据的物理存储.这就包括(数据文件ORA或者DBF.控制文件.联机日志.参数文件).其实Oracle数据库的概念和其它数据库不一样,这里的数据库是一个操作系统只有一个库.可 ...