网站建设资讯

NEWS

网站建设资讯

android堆栈,手机 堆栈

Android中的Activity详解--启动模式与任务栈

目录

创新互联是专业的罗山网站建设公司,罗山接单;提供成都网站建设、网站建设,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行罗山网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!

activity的简单介绍就不写了,作为最常用的四大组件之一,肯定都很熟悉其基本用法了。

首先,是都很熟悉的一张图,即官方介绍的Activity生命周期图.

情景:打开某个应用的的FirstActivity调用方法如下:

由于之前已经很熟悉了,这里就简单贴一些图。

按下返回键:

重新打开并按下home键:

再重新打开:

在其中打开一个DialogActivity(SecondActivity)

按下返回:

修改SecondAcitvity为普通Activity,依旧是上述操作:

这里强调一下 onSaveInstanceState(Bundle outState) 方法的调用时机:

当Activity有可能被系统杀掉时调用,注意,一定是被系统杀掉,自己调用finish是不行的。

测试如下:FirstActivity启动SecondActivity:

一个App会包含很多个Activity,多个Activity之间通过intent进行跳转,那么原始的Activity就是使用栈这个数据结构来保存的。

Task

A task is a collection of activities that users interact with when performing a certain job. The activities are arranged in a stack (the back stack ), in the order in which each activity is opened.

即若干个Activity的集合的栈表示一个Task。

当App启动时如果不存在当前App的任务栈就会自动创建一个,默认情况下一个App中的所有Activity都是放在一个Task中的,但是如果指定了特殊的启动模式,那么就会出现同一个App的Activity出现在不同的任务栈中的情况,即会有任务栈中包含来自于不同App的Activity。

标准模式,在不指定启动模式的情况下都是以此种方式启动的。每次启动都会创建一个新的Activity实例,覆盖在原有的Activity上,原有的Activity入栈。

测试如下:在FirstActivity中启动FirstActivity:

当只有一个FirstActivity时堆栈情况:

此种模式下,Activity在启动时会进行判断,如果当前的App的栈顶的Activity即正在活动的Activity就是将要启动的Activity,那么就不会创建新的实例,直接使用栈顶的实例。

测试,设置FirstActivity为此启动模式,多次点击FirstActivity中的启动FirstActivity的按钮查看堆栈情况:

(其实点击按钮没有启动新Activity的动画就可以看出并没有启动新Activity)

大意就是:

对于使用singleTop启动或Intent.FLAG_ACTIVITY_SINGLE_TOP启动的Activity,当该Activity被重复启动(注意一定是re-launched,第一次启动时不会调用)时就会调用此方法。

且调用此方法之前会先暂停Activity也就是先调用onPause方法。

而且,即使是在新的调用产生后此方法被调用,但是通过getIntent方法获取到的依旧是以前的Intent,可以通过setIntent方法设置新的Intent。

方法参数就是新传递的Intent.

1.如果是同一个App中启动某个设置了此模式的Activity的话,如果栈中已经存在该Activity的实例,那么就会将该Activity上面的Activity清空,并将此实例放在栈顶。

测试:SecondActivity启动模式设为singleTask,启动三个Activity:

这个模式就很好记,以此模式启动的Activity会存放在一个单独的任务栈中,且只会有一个实例。

测试:SecondActivity启动模式设为singleInstance

结果:

显然,启动了两次ThirdActivity任务栈中就有两个实例,而SecondActivity在另外一个任务栈中,且只有一个。

在使用Intent启动一个Activity时可以设置启动该Activity的启动模式:

这个属性有很多,大致列出几个:

每个启动的Activity都在一个新的任务栈中

singleTop

singleTask

用此种方式启动的Activity,在它启动了其他Activity后,会自动finish.

官方文档介绍如下:

这样看来的话,通俗易懂的讲,就是给每一个任务栈起个名,给每个Activity也起个名,在Activity以singleTask模式启动时,就检查有没有跟此Activity的名相同的任务栈,有的话就将其加入其中。没有的话就按照这个Activity的名创建一个任务栈。

测试:在App1中设置SecondActivity的taskAffinity为“gsq.test”,App2中的ActivityX的taskAffinity也设为“gsq.test”

任务栈信息如下:

结果很显然了。

测试:在上述基础上,在ActivityX中进行跳转到ActivityY,ActivityY不指定启动模式和taskAffinity。结果如下:

这样就没问题了,ActivityY在一个新的任务栈中,名称为包名。

这时从ActivityY跳转到SecondActivity,那应该是gsq.test任务栈只有SecondActivity,ActivityX已经没有了。因为其启动模式是singleTask,在启动它时发现已经有一个实例存在,就把它所在的任务栈上面的Activity都清空了并将其置于栈顶。

还有一点需要提一下,在上面,FirstActivity是App1的lunch Activity,但是由于SecondActivity并没有指定MAIN和LAUNCHER过滤器,故在FirstActivity跳转到SecondActivity时,按下home键,再点开App1,回到的是FirstActivity。

大致就先写这么多吧,好像有点长,废话有点多,估计也有错别字,不要太在意~~~

android 中怎样能够清除activity堆栈,也就是退出整个应用

如果退出整个程序,如下操作:方式一:Intent intent=new Intent(Intent.ACTION_MAIN);intent.addCategory(Intent.CATEGORY_HOME);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);this.startActivity(intent);System.exit(0); 方式二:android.os.Process.killProcess(android.os.Process.myPid()); android 完全退出程序有几个activity,有一需求是在一个activityA点击back键退出系统而不是跳到之前的activity首先想到的是清空activityA的堆栈,使用intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 但是该activityA不是已经存在于堆栈底端的,所以清除的只是堆栈中该activityA上面的activity,但后退后还是会返回堆栈中该activityA下面的activity。

手机调试Android程序出异常时不打印堆栈信息

打印堆栈是调试的常用方法,一般在系统异常时,我们可以将异常情况下的堆栈打印出来,这样十分方便错误查找。实际上还有另外一个非常有用的功能:分析代码的行为。android代码太过庞大复杂了,完全的静态分析经常是无从下手,因此通过打印堆栈的动态分析也十分必要。

Android打印堆栈的方法,简单归类一下

1. zygote的堆栈dump

实际上这个可以同时dump java线程及native线程的堆栈,对于java线程,java堆栈和native堆栈都可以得到。

使用方法很简单,直接在adb shell或串口中输入:

[plain] view plaincopy

kill -3 pid

输出的trace会保存在 /data/anr/traces.txt文件中。这个需要注意,如果没有 /data/anr/这个目录或/data/anr/traces.txt这个文件,需要手工创建一下,并设置好读写权限。

如果需要在代码中,更容易控制堆栈的输出时机,可以用以下命令获取zygote的core dump:

[java] view plaincopy

Process.sendSignal(pid, Process.SIGNAL_QUIT);

原理和命令行是一样的。

不过需要注意两点:

adb shell可能会没有权限,需要root。

android 4.2中关闭了native thread的堆栈打印,详见 dalvik/vm/Thread.cpp的dumpNativeThread方法:

[cpp] view plaincopy

dvmPrintDebugMessage(target,

"\"%s\" sysTid=%d nice=%d sched=%d/%d cgrp=%s\n",

name, tid, getpriority(PRIO_PROCESS, tid),

schedStats.policy, schedStats.priority, schedStats.group);

dumpSchedStat(target, tid);

// Temporarily disabled collecting native stacks from non-Dalvik

// threads because sometimes they misbehave.

//dvmDumpNativeStack(target, tid);

Native堆栈的打印被关掉了!不过对于大多数情况,可以直接将这个注释打开。

2. debuggerd的堆栈dump

debuggerd是android的一个daemon进程,负责在进程异常出错时,将进程的运行时信息dump出来供分析。debuggerd生 成的coredump数据是以文本形式呈现,被保存在 /data/tombstone/ 目录下(名字取的也很形象,tombstone是墓碑的意思),共可保存10个文件,当超过10个时,会覆盖重写最早生成的文件。从4.2版本开 始,debuggerd同时也是一个实用工具:可以在不中断进程执行的情况下打印当前进程的native堆栈。使用方法是:

[plain] view plaincopy

debuggerd -b pid

这可以协助我们分析进程执行行为,但最最有用的地方是:它可以非常简单的定位到native进程中锁死或错误逻辑引起的死循环的代码位置。

3. java代码中打印堆栈

Java代码打印堆栈比较简单, 堆栈信息获取和输出,都可以通过Throwable类的方法实现。目前通用的做法是在java进程出现需要注意的异常时,打印堆栈,然后再决定退出或挽救。通常的方法是使用exception的printStackTrace()方法:

[java] view plaincopy

try {

...

} catch (RemoteException e) {

e.printStackTrace();

...

}

当然也可以只打印堆栈不退出,这样就比较方便分析代码的动态运行情况。Java代码中插入堆栈打印的方法如下:

[java] view plaincopy

Log.d(TAG,Log.getStackTraceString(new Throwable()));

4. C++代码中打印堆栈

C++也是支持异常处理的,异常处理库中,已经包含了获取backtrace的接口,Android也是利用这个接口来打印堆栈信息的。在Android的C++中,已经集成了一个工具类CallStack,在libutils.so中。使用方法:

[cpp] view plaincopy

#include utils/CallStack.h

...

CallStack stack;

stack.update();

stack.dump();

使用方式比较简单。目前Andoid4.2版本已经将相关信息解析的很到位,符号表查找,demangle,偏移位置校正都做好了。

[plain] view plaincopy

5. C代码中打印堆栈

C代码,尤其是底层C库,想要看到调用的堆栈信息,还是比较麻烦的。 CallStack肯定是不能用,一是因为其实C++写的,需要重新封装才能在C中使用,二是底层库反调上层库的函数,会造成链接器循环依赖而无法链接。 不过也不是没有办法,可以通过android工具类CallStack实现中使用的unwind调用及符号解析函数来处理。

这里需要注意的是,为解决链接问题,最好使用dlopen方式,查找需要用到的接口再直接调用,这样会比较简单。如下为相关的实现代码,只需要在要 打印的文件中插入此部分代码,然后调用getCallStack()即可,无需包含太多的头文件和修改Android.mk文件:

[cpp] view plaincopy

#define MAX_DEPTH 31

#define MAX_BACKTRACE_LINE_LENGTH 800

#define PATH "/system/lib/libcorkscrew.so"

typedef ssize_t (*unwindFn)(backtrace_frame_t*, size_t, size_t);

typedef void (*unwindSymbFn)(const backtrace_frame_t*, size_t, backtrace_symbol_t*);

typedef void (*unwindSymbFreeFn)(backtrace_symbol_t*, size_t);

static void *gHandle = NULL;

static int getCallStack(void){

ssize_t i = 0;

ssize_t result = 0;

ssize_t count;

backtrace_frame_t mStack[MAX_DEPTH];

backtrace_symbol_t symbols[MAX_DEPTH];

unwindFn unwind_backtrace = NULL;

unwindSymbFn get_backtrace_symbols = NULL;

unwindSymbFreeFn free_backtrace_symbols = NULL;

// open the so.

if(gHandle == NULL) gHandle = dlopen(PATH, RTLD_NOW);

// get the interface for unwind and symbol analyse

if(gHandle != NULL) unwind_backtrace = (unwindFn)dlsym(gHandle, "unwind_backtrace");

if(gHandle != NULL) get_backtrace_symbols = (unwindSymbFn)dlsym(gHandle, "get_backtrace_symbols");

if(gHandle != NULL) free_backtrace_symbols = (unwindSymbFreeFn)dlsym(gHandle, "free_backtrace_symbols");

if(!gHandle ||!unwind_backtrace ||!get_backtrace_symbols || !free_backtrace_symbols ){

ALOGE("Error! cannot get unwind info: handle:%p %p %p %p",

gHandle, unwind_backtrace, get_backtrace_symbols, free_backtrace_symbols );

return result;

}

count= unwind_backtrace(mStack, 1, MAX_DEPTH);

get_backtrace_symbols(mStack, count, symbols);

for (i = 0; i count; i++) {

char line[MAX_BACKTRACE_LINE_LENGTH];

const char* mapName = symbols[i].map_name ? symbols[i].map_name : "unknown";

const char* symbolName =symbols[i].demangled_name ? symbols[i].demangled_name : symbols[i].symbol_name;

size_t fieldWidth = (MAX_BACKTRACE_LINE_LENGTH - 80) / 2;

if (symbolName) {

uint32_t pc_offset = symbols[i].relative_pc - symbols[i].relative_symbol_addr;

if (pc_offset) {

snprintf(line, MAX_BACKTRACE_LINE_LENGTH, "#%02d pc %08x %.*s (%.*s+%u)",

i, symbols[i].relative_pc, fieldWidth, mapName,

fieldWidth, symbolName, pc_offset);

} else {

snprintf(line, MAX_BACKTRACE_LINE_LENGTH, "#%02d pc %08x %.*s (%.*s)",

i, symbols[i].relative_pc, fieldWidth, mapName,

fieldWidth, symbolName);

}

} else {

snprintf(line, MAX_BACKTRACE_LINE_LENGTH, "#%02d pc %08x %.*s",

i, symbols[i].relative_pc, fieldWidth, mapName);

}

ALOGD("%s", line);

}

free_backtrace_symbols(symbols, count);

return result;

}

对sched_policy.c的堆栈调用分析如下,注意具体是否要打印,在哪里打印,还可以通过pid、uid、property等来控制一下,这样就不会被淹死在trace的汪洋大海中。

[plain] view plaincopy

D/SchedPolicy( 1350): #00 pc 0000676c /system/lib/libcutils.so

D/SchedPolicy( 1350): #01 pc 00006b3a /system/lib/libcutils.so (set_sched_policy+49)

D/SchedPolicy( 1350): #02 pc 00010e82 /system/lib/libutils.so (androidSetThreadPriority+61)

D/SchedPolicy( 1350): #03 pc 00068104 /system/lib/libandroid_runtime.so (android_os_Process_setThreadPriority(_JNIEnv*, _jobject*, int, int)+7)

D/SchedPolicy( 1350): #04 pc 0001e510 /system/lib/libdvm.so (dvmPlatformInvoke+112)

D/SchedPolicy( 1350): #05 pc 0004d6aa /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+417)

D/SchedPolicy( 1350): #06 pc 00027920 /system/lib/libdvm.so

D/SchedPolicy( 1350): #07 pc 0002b7fc /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)

D/SchedPolicy( 1350): #08 pc 00060c30 /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+271)

D/SchedPolicy( 1350): #09 pc 0004cd34 /system/lib/libdvm.so

D/SchedPolicy( 1350): #10 pc 00049382 /system/lib/libandroid_runtime.so

D/SchedPolicy( 1350): #11 pc 00065e52 /system/lib/libandroid_runtime.so

D/SchedPolicy( 1350): #12 pc 0001435e /system/lib/libbinder.so (android::BBinder::transact(unsigned int, android::Parcel const, android::Parcel*, unsigned int)+57)

D/SchedPolicy( 1350): #13 pc 00016f5a /system/lib/libbinder.so (android::IPCThreadState::executeCommand(int)+513)

D/SchedPolicy( 1350): #14 pc 00017380 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+183)

D/SchedPolicy( 1350): #15 pc 0001b160 /system/lib/libbinder.so

D/SchedPolicy( 1350): #16 pc 00011264 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+111)

D/SchedPolicy( 1350): #17 pc 000469bc /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+63)

D/SchedPolicy( 1350): #18 pc 00010dca /system/lib/libutils.so

D/SchedPolicy( 1350): #19 pc 0000e3d8 /system/lib/libc.so (__thread_entry+72)

D/SchedPolicy( 1350): #20 pc 0000dac4 /system/lib/libc.so (pthread_create+160)

D/SchedPolicy( 1350): #00 pc 0000676c /system/lib/libcutils.so

D/SchedPolicy( 1350): #01 pc 00006b3a /system/lib/libcutils.so (set_sched_policy+49)

D/SchedPolicy( 1350): #02 pc 00016f26 /system/lib/libbinder.so (android::IPCThreadState::executeCommand(int)+461)

D/SchedPolicy( 1350): #03 pc 00017380 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+183)

D/SchedPolicy( 1350): #04 pc 0001b160 /system/lib/libbinder.so

D/SchedPolicy( 1350): #05 pc 00011264 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+111)

D/SchedPolicy( 1350): #06 pc 000469bc /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+63)

D/SchedPolicy( 1350): #07 pc 00010dca /system/lib/libutils.so

D/SchedPolicy( 1350): #08 pc 0000e3d8 /system/lib/libc.so (__thread_entry+72)

D/SchedPolicy( 1350): #09 pc 0000dac4 /system/lib/libc.so (pthread_create+160)

6. 其它堆栈信息查询

Android中的activity的堆栈有什么作用

我的理解是堆栈就是后进先出,那么稍微想像一下,你打开的Activity是一层一层往上盖的,当你退出当前这个Activity的时候,使用堆栈机制才会显示你底下那一层的Activity,提高Activity复用率吧。如果你觉得这个Activity可以不用再保留那么也给你提供了相应的打开另一个Activity之后就清理掉自己的方法。这样做的用户体验会比较好吧;那么反过来讲如果没有采用堆栈机制,在这么有限的显示区域里应该怎么去分配多个Activity呢?

理解任务和后台堆栈(活动四)

任务是用户在执行特定作业时与之交互的活动的集合。

活动按堆栈排列 - (返回栈) - 按每个活动打开的顺序排列。 例如,电子邮件应用可能有一个活动来显示新消息列表。 当用户选择消息时,将打开一个新活动以查看该消息。 此新活动将添加到后台堆栈。 如果用户按下“返回”按钮,则表示新活动已完成并从堆栈中弹出。 以下视频概述了后端堆栈的工作原理。

当应用程序在多窗口环境中同时运行时,在Android 7.0(API级别24)及更高版本中受支持,系统会为每个窗口单独管理任务; 每个窗口可能有多个任务。 对于在Chromebook上运行的Android应用程序也是如此:系统基于每个窗口管理任务或任务组。

设备主屏幕是大多数任务的起始位置。 当用户触摸应用程序启动器中的图标(或主屏幕上的快捷方式)时,该应用程序的任务将进入前台。 如果应用程序不存在任务(最近未使用该应用程序),则会创建一个新任务,该应用程序的“主”活动将作为堆栈中的根活动打开。

当前活动从另一个活动开始时,新活动将被推到堆栈顶部并获得焦点。 之前的活动仍在堆栈中,但已停止。 当活动停止时,系统将保留其用户界面的当前状态。 当用户按下“返回”按钮时,当前活动将从堆栈顶部弹出(活动被销毁),之前的活动将恢复(其UI的先前状态将恢复)。 堆栈中的活动永远不会重新排列,只能在当前活动启动时从堆栈中推送并弹出到堆栈中,并在用户使用“返回”按钮离开时弹出。 因此,后堆栈作为“后进先出”对象结构操作。 图1显示了这种行为,时间轴显示了活动之间的进度以及每个时间点的当前后栈。

如果用户继续按Back,则弹出堆栈中的每个活动以显示前一个活动,直到用户返回主屏幕(或任务开始时运行的任何活动)。 从堆栈中删除所有活动后,该任务不再存在。

任务是一个内聚单元,当用户开始新任务或通过主页按钮进入主屏幕时,可以移动到“后台”。在后台,任务中的所有活动都会停止,但任务的后台堆栈保持不变 - 任务在发生另一项任务时完全失去焦点,如图2所示。然后任务可以返回到“前台“所以用户可以从中断的地方继续前进。例如,假设当前任务(任务A)在其堆栈中有三个活动 - 在当前活动下有两个活动。用户按下主页按钮,然后从应用启动器启动新应用。出现主屏幕时,任务A进入后台。当新应用程序启动时,系统会使用自己的一系列活动为该应用程序(任务B)启动任务。在与该应用程序交互之后,用户再次返回Home并选择最初启动任务A的应用程序。现在,任务A进入前台 - 其堆栈中的所有三个活动都完好无损,并且堆栈顶部的活动将恢复。此时,用户还可以通过返回主页并选择启动该任务的应用程序图标(或从“最近”屏幕中选择应用程序的任务)切换回任务B.这是Android上的多任务处理的一个示例。

图2.两个任务:任务B在前台接收用户交互,而任务A在后台,等待恢复。

图3.单个活动多次实例化。

由于后备堆栈中的活动永远不会重新排列,如果您的应用程序允许用户从多个活动启动特定活动,则会创建该活动的新实例并将其推送到堆栈(而不是带来任何先前的活动实例) 到顶部)。 因此,您的应用中的一个活动可能会被多次实例化(甚至来自不同的任务),如图3所示。因此,如果用户使用“后退”按钮向后导航,则活动的每个实例都按顺序显示 被打开(每个都有自己的UI状态)。 但是,如果您不希望多次实例化活动,则可以修改此行为。 有关如何执行此操作将在后面的“管理任务”一节中讨论。

总结活动和任务的默认行为:

Android管理任务和后台堆栈的方式,如上所述 - 通过将所有活动连续启动到同一任务和“后进先出”堆栈 - 对于大多数应用程序而言非常有用,您不必担心 关于您的活动如何与任务相关联或它们如何存在于后台堆栈中。 但是,您可能决定要中断正常行为。 也许您希望应用程序中的活动在启动时开始新任务(而不是放在当前任务中); 或者,当你开始一个活动时,你想要提出它的现有实例(而不是在后面的堆栈顶部创建一个新的实例); 或者,您希望在用户离开任务时清除除了根活动之外的所有活动的后台堆栈。

您可以使用activity清单元素中的属性以及传递给startActivity()的intent中的标记来执行这些操作。

在这方面,您可以使用的主要activity属性是:

您可以使用的主要意图标志是:

在以下部分中,您将了解如何使用这些清单属性和意图标志来定义活动与任务的关联方式以及它们在后端堆栈中的行为方式。

另外,单独讨论的是在“最近”屏幕中如何表示和管理任务和活动的注意事项。 有关详细信息,请参阅最近屏幕。 通常,您应该允许系统在“最近”屏幕中定义您的任务和活动的表示方式,而不需要修改此行为。

启动模式允许您定义活动的新实例与当前任务的关联方式。 您可以通过两种方式定义不同的启动模式:

因此,如果活动A启动活动B,活动B可以在其清单中定义它应该如何与当前任务相关联(如果有的话),活动A也可以请求活动B应该如何与当前任务相关联。 如果两个活动都定义了活动B应该如何与任务相关联,则活动A的请求(如意图中所定义)将遵循活动B的请求(如其清单中所定义)。

在清单文件中声明活动时,可以使用activity元素的launchMode属性指定活动应如何与任务关联。

launchMode属性指定有关如何将活动启动到任务的说明。 您可以为launchMode属性分配四种不同的启动模式:

"standard" (the default mode)

默认。 系统在启动它的任务中创建活动的新实例,并将意图路由到该实例。 活动可以多次实例化,每个实例可以属于不同的任务,一个任务可以有多个实例。

"singleTop"

果活动的实例已存在于当前任务的顶部,则系统通过调用其onNewIntent()方法将意图路由到该实例,而不是创建活动的新实例。活动可以多次实例化,每个实例可以属于不同的任务,一个任务可以有多个实例(但只有当后端堆栈顶部的活动不是活动的现有实例时)。

例如,假设任务的后向堆栈由根活动A组成,活动B,C和D位于顶部(堆栈为A-B-C-D; D位于顶部)。意图到达类型D的活动。如果D具有默认的“标准”启动模式,则启动该类的新实例并且堆栈变为A-B-C-D-D。但是,如果D的启动模式是“singleTop”,则现有的D实例通过onNewIntent()接收意图,因为它位于堆栈的顶部 - 堆栈仍然是A-B-C-D。但是,如果意图到达类型B的活动,则即使其启动模式为“singleTop”,也会将新的B实例添加到堆栈中。

"singleTask"

系统创建新任务并在新任务的根目录下实例化活动。 但是,如果活动的实例已存在于单独的任务中,则系统会通过调用其onNewIntent()方法将意图路由到现有实例,而不是创建新实例。 一次只能存在一个活动实例。

"singleInstance"

与“singleTask”相同,但系统不会在持有实例的任务中启动任何其他活动。 活动始终是其任务的唯一成员; 任何由此开始的活动都在一个单独的任务中打开。

作为另一个示例,Android浏览器应用程序声明Web浏览器活动应始终在其自己的任务中打开 - 通过在activity元素中指定singleTask启动模式。这意味着,如果您的应用发出打开Android浏览器的意图,则其活动不会与您的应用放在同一任务中。相反,要么为浏览器启动新任务,要么如果浏览器已经在后台运行任务,则该任务将被提前处理新意图。

无论活动是在新任务中启动还是在与启动它的活动相同的任务中启动,“返回”按钮始终会将用户带到上一个活动。但是,如果启动指定singleTask启动模式的活动,则如果后台任务中存在该活动的实例,则将整个任务带到前台。此时,后端堆栈现在包括堆栈顶部提出的任务中的所有活动。图4说明了这种情况。

图4.表示如何将具有启动模式“singleTask”的活动添加到后台堆栈。 如果活动已经是具有自己的后台堆栈的后台任务的一部分,那么整个后台堆栈也会在当前任务的基础上出现。

有关在清单文件中使用启动模式的更多信息,请参阅activity元素文档,其中详细讨论了launchMode属性和接受的值。

启动活动时,您可以通过在传递给startActivity()的intent中包含标志来修改活动与其任务的默认关联。 您可以用来修改默认行为的标志是:

FLAG_ACTIVITY_NEW_TASK

在新任务中启动活动。 如果任务已在为您正在启动的活动运行,则该任务将返回到前台,并恢复其上一个状态,并且活动将在onNewIntent()中接收新的意图。

这会产生与上一节中讨论的“singleTask”launchMode值相同的行为。

FLAG_ACTIVITY_SINGLE_TOP

如果正在启动的活动是当前活动(在后台堆栈的顶部),则现有实例将接收对onNewIntent()的调用,而不是创建活动的新实例。

这会产生与上一节中讨论的“singleTop”launchMode值相同的行为。

FLAG_ACTIVITY_CLEAR_TOP

如果正在启动的活动已在当前任务中运行,则不会启动该活动的新实例,而是销毁其上的所有其他活动,并将此意图传递给活动的恢复实例(现在开启) top),通过onNewIntent())。

生成此行为的launchMode属性没有任何值。

FLAG_ACTIVITY_CLEAR_TOP通常与FLAG_ACTIVITY_NEW_TASK结合使用。 当一起使用时,这些标志是一种在另一个任务中定位现有活动并将其置于可以响应意图的位置的方法。

亲和力指示活动喜欢属于哪个任务。 默认情况下,同一应用程序中的所有活动都具有彼此的关联。 因此,默认情况下,同一个应用程序中的所有活动都希望处于同一任务中。 但是,您可以修改活动的默认关联。 在不同应用中定义的活动可以共享亲和力,或者可以为同一应用中定义的活动分配不同的任务亲和力。

您可以使用activity元素的taskAffinity属性修改任何给定活动的亲缘关系。

taskAffinity属性采用字符串值,该值必须与manifest元素中声明的默认包名称唯一,因为系统使用该名称来标识应用程序的默认任务关联。

亲和力在两种情况下起作用:

如果用户长时间离开任务,系统将清除除根活动之外的所有活动的任务。 当用户再次返回任务时,仅还原根活动。 系统以这种方式运行,因为在很长一段时间之后,用户可能已经放弃了之前正在做的事情并返回任务以开始新的事情。

您可以使用一些活动属性来修改此行为:

alwaysRetainTaskState:

如果在任务的根活动中将此属性设置为“true”,则不会发生刚才描述的默认行为。 即使经过很长一段时间,任务仍会保留堆栈中的所有活动。

clearTaskOnLaunch:

如果在任务的根活动中将此属性设置为“true”,则只要用户离开任务并返回到该任务,就会将堆栈清除为根活动。 换句话说,它与alwaysRetainTaskState相反。 即使在离开任务片刻之后,用户也始终以初始状态返回任务。

finishOnTaskLaunch:

此属性类似于clearTaskOnLaunch,但它在单个活动上运行,而不是整个任务。 它还可以导致任何活动消失,包括根活动。 当它设置为“true”时,活动仍然是当前会话的任务的一部分。 如果用户离开然后返回任务,它将不再存在。

您可以将活动设置为任务的入口点,方法是为其指定一个过滤器,其中“android.intent.action.MAIN”作为指定的操作,“android.intent.category.LAUNCHER”作为指定的类别。 例如:

这种意图过滤器会导致活动的图标和标签显示在应用程序启动器中,从而为用户提供启动活动并返回其在启动后随时创建的任务的方法。

第二种能力很重要:用户必须能够离开任务,然后使用此活动启动器返回该任务。因此,仅当活动具有ACTION_MAIN和CATEGORY_LAUNCHER过滤器时,才应使用将活动标记为始终启动任务的两种启动模式“singleTask”和“singleInstance”。例如,想象一下,如果缺少过滤器会发生什么:intent会启动“singleTask”活动,启动新任务,并且用户会花一些时间在该任务中工作。然后用户按下主页按钮。该任务现在发送到后台并且不可见。现在用户无法返回任务,因为它未在应用启动器中显示。

对于您不希望用户能够返回活动的情况,请将activity元素的finishOnTaskLaunch设置为“true”(请参阅清除后台堆栈)。

有关如何在“概述”屏幕中表示和管理任务和活动的更多信息,请参见“最近用户”屏幕。


当前题目:android堆栈,手机 堆栈
网站网址:http://njwzjz.com/article/dsdopoo.html