Android之Activity的栈管理

本文详细介绍了Android中的Task概念,一个Task是Activity的集合,按照启动顺序压入栈中。讨论了Task的管理,包括Activity的启动模式(standard、singleTop、singleTask、singleInstance)和Intent标志(FLAG_ACTIVITY_NEW_TASK、FLAG_ACTIVITY_CLEAR_TOP等)如何影响Task行为。通过实例分析了不同场景下Activity如何被创建和管理,强调了如何控制Activity在Task中的生命周期和状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Task的介绍

一个应用程序通常包含多个 activity每个 activity 在设计时都应该以执行某个用户发起的 action 作为核心目标,并且它能启动其它 activity。 Task就是多个Activity的集合,用户操作时与Activity进行交互。这些Activity根据启动顺序压入task中,如果pop task 是按照先进后出的顺序pop

       大部分 task都启动自 Home屏幕。当用户触摸 application launcher中的图标(或 Home屏幕上的快捷图标)时,应用程序的 task就进入前台。如果该应用不存在 task(最近没有使用过此应用),则会新建一个 task,该应用的“main”activity作为栈的根 activity被打开

二、Task的管理

如上所述,Activity依照顺序压入Task并按照“先进后出”的顺序pop,对Task的管理显得十分的必要。有时想让某个 activity启动一个新的 task(而不是被放入当前 task);或者,让 activity启动时只是调出已有的某个实例(而不是在 back stack顶创建一个新的实例);或者,想在用户离开 task时只保留根 activity,而 back stack中的其它 activity都要清空。

利用 "<activity> manifest元素的属性和传入 startActivity()  intent 中的标志,可以做很多事情。

常用的<activity>属性:

taskAffinity如果不设置此属性,默认一个应用程序只有一个栈,这个栈以应用包命为单位task对于Activity来说就好像它的身份证一样,可以告诉所在的task,自己属于这个task中的一员;拥有相同affinity的多个Activity理论同属于一个task,task自身的affinity决定于根Activity的affinity值。affinity在什么场合应用呢?1.根据affinity重新为Activity选择宿主task(与allowTaskReparenting属性配合工作);2.启动一个Activity过程中Intent使用了FLAG_ACTIVITY_NEW_TASK标记,根据affinity查找或创建一个新的具有对应affinity的task

·        launchMode:启动模式

·        allowTaskReparenting属性用来标记一个Activity实例在当前应用退居后台后,是否能从启动它的那个task移动到有共同affinitytask“true”表示可以移动,“false”表示它必须呆在当前应用的task中,默认值为false。如果一个这个Activity<activity>元素没有设定此属性,设定在<application>上的此属性会对此Activity起作用

·        clearTaskOnLaunch标记是否从task清除除根Activity之外的所有的Activity“true”表示清除,“false”表示不清除,默认为“false”。同样,这个属性也只对根Activity起作用,其他的Activity都会被忽略。

·        alwaysRetainTaskState标记应用的task是否保持原来的状态,“true”表示总是保持,“false”表示不能够保证,默认为“false”此属性只对task的根Activity起作用,其他的Activity都会被忽略

·        finishOnTaskLaunch销毁实例

三、常用 intent 标志

·        FLAG_ACTIVITY_NEW_TASK:Intent对象包含这个标记时,系统会寻找或创建一个新的task来放置目标Activity,寻找时依据目标ActivitytaskAffinity属性进行匹配,如果找到一个tasktaskAffinity与之相同,就将目标Activity压入此task中,如果查找无果,则创建一个新的task,并将该tasktaskAffinity设置为目标ActivitytaskActivity,将目标Activity放置于此task。注意,如果同一个应用中ActivitytaskAffinity都使用默认值或都设置相同值时,应用内的Activity之间的跳转使用这个标记是没有意义的,因为当前应用task就是目标Activity最好的宿主

创建两个应用appAappB,其中appA包含ActivityFirstAActivitySecondA两个界面。在appB中启动appA中的ActivitySecondA

appAActivitySecondA配置如下:

       <activity

            android:name=".ActivitySecondA"

            android:label="@string/title_activity_activity_second">

            <intent-filter>

                <action android:name="android.intent.action.APP_A_SECOND_ACTIVITY"/>

 

                <category android:name="android.intent.category.DEFAULT" />

            </intent-filter>

       </activity>

               情况1:在appB中启动appA中的ActivitySecondA,不设置Flag

                              Intent in= new Intent("android.intent.action.APP_A_SECOND_ACTIVITY");

                                     startActivity(in);

a.    启动appB     

 

b.    在appB中启动appA中的ActivitySecondA


         c.再次启动appB


d.点击Home键启动appA


此时发现appB启动appA中的ActivitySecondA后,ActivitySecondA似乎压入appBTask中,对appA启动没有任何影响。

       情景2:修改Flag属性为FLAG_ACTIVITY_NEW_TASK

a.    启动appB     


b.    在appB中启动appA中的ActivitySecondA


c.    再次启动B


d.   启动A


当我们再次启动appB时已经看不到刚才启动的appA中的SecondActivity,而启动appA时却直接看到了,说明这个SecondActivity实例并不在appBtask内,而是创建了一个task,这个taskaffinity就是SecondActivity默认的affinity,由于appASecondActivityaffinity是从Application继承而来,所以当appA启动时会直接找到这个task,而不是创建新的task

FLAG_ACTIVITY_CLEAR_TOP: 当Intent对象包含这个标记时,如果在栈中发现存在Activity实例,则清空这个实例之上的Activity,使其处于栈顶。例如:我们的FirstActivity跳转到SecondActivity,SecondActivity跳转到ThirdActivity,而ThirdActivity又跳到SecondActivity,那么ThirdActivity实例将被弹出栈,使SecondActivity处于栈顶,显示到幕前,栈内只剩下FirstActivity和SecondActivity。这个SecondActivity既可以在onNewIntent()中接收到传来的Intent,也可以把自己销毁之后重新启动来接受这个Intent。在使用默认的“standard”启动模式下,如果没有在Intent使用到FLAG_ACTIVITY_SINGLE_TOP标记,那么它将关闭后重建,如果使用了这个FLAG_ACTIVITY_SINGLE_TOP标记,则会使用已存在的实例;对于其他启动模式,无需再使用FLAG_ACTIVITY_SINGLE_TOP,它都将使用已存在的实例,Intent会被传递到这个实例的onNewIntent()中。

例如:

情景1.所有Activity的启动模式都为默认

ThirdActivity启动 SecondActivity,设置Flag

                   Intentin = newIntent(ActivityThird.this,ActivitySecond.class);

                   in.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 

                   startActivity(in);

1.       FirstActivity启动SecondActivity


2.       ThirdActivity 启动SecondActivity


                   此时发现两次SecondActivity的实例是不同的,证明了它是经过了销毁重建的过程。

 

                  情景2. Second的启动模式设置为非默认模式

1.       FirstActivity启动SecondActivity


2.       ThirdActivity 启动SecondActivity


明显可以看出,两个SecondActivity的实例是一样的。

如果我们不想添加FLAG_ACTIVITY_SINGLE_TOP,那么把SecondActivity的启动模式改为“standard”之外的三种即可,效果和上面一样,都不会创建新的实例。 

·        FLAG_ACTIVITY_SINGLE_TOP:task中存在目标Activity实例并且位于栈的顶端时,不再创建一个新的

FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET:如果一个Intent中包含此属性,则它转向的那个Activity以及在那个Activity其上的所有Activity都会在task重置时被清除出task。当我们将一个后台的task重新回到前台时,系统会在特定情况下为这个动作附带一个FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记,意味着必要时重置task,这时FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET就会生效。经过测试发现,对于一个处于后台的应用,如果在主选单点击应用,这个动作中含有FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记,长按Home键,然后点击最近记录,这个动作不含FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记,所以前者会清除,后者不会。

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED:这个标记在以下情况下会生效:1.启动Activity时创建新的task来放置Activity实例;2.已存在的task被放置于前台。系统会根据affinity对指定的task进行重置操作,task会压入某些Activity实例或移除某些Activity实例。我们结合上面的CLEAR_WHEN_TASK_RESET可以加深理解。

四、Activity的启动模式

Activity的启动模式在Task管理中也扮演着重要的角色,它决定了Task中的Activity是否重用,或者和其他Activity共用一个Task,或者是否生成新的Activity。以下是Activity的四种启动模式的理解。

1.       starndard:默认的启动模式,不需要再Manifest里面设置。此启动模式下,Activity创建新的实例,并据启动的先后顺序压入Task中。

2.       singleTop:如果启动的Avtivity在栈顶,重用当前Activity,否则创建Activity。

3.       singleTask:如果要激活的那个Activity在任务栈中存在该实例,则不需要创建,只需要把此Activity放入栈顶,并把该Activity以上的Activity实例都pop。

4.       singleInstance:如果应用1的任务栈中创建了MainActivity实例,如果应用2也要激活MainActivity,则不需要创建,两应用共享该Activity实例;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值