• Activity的启动模式--总结


     

    3. Activity的任务栈Task以及启动模式与Intent的Flag详解?

    2,Activity次级页面和主页间来回跳转,防止重复创建Activity实例

    1, activity的启动模式:

    //====================

    3. Activity的任务栈Task以及启动模式与Intent的Flag详解?--转载自(https://www.jianshu.com/p/c1386015856a)

    引用

    meizixiongActivity的四种启动模式
    android 任务栈及启动模式
    android的task任务栈
    Intent Flag的几种介绍

    什么是任务栈(Task)

    官方文档是这么解释的

    任务是指在执行特定作业时与用户交互的一系列 Activity。 这些 Activity 按照各自的打开顺序排列在堆栈(即“返回栈”)中。

    其实就是以栈的结构(先进后出)将依次打开的activity记录.

    为什么要用任务栈

    为了记录用户开启了那些activity,记录这些activity开启的先后顺序,google引入任务栈(task stack)概念,帮助维护好的用户体验。

    如何查看当前系统的任务栈

    手机中 --> 长按home或者多任务键会进到 概览屏幕 的一个界面
    命令行中 --> adb shell dumpsys activity

    概览屏幕(Overview Screen)

    概览屏幕(也称为最新动态屏幕、最近任务列表或最近使用的应用)是一个系统级别 UI,其中列出了最近访问过的Activity和任务。 用户可以浏览该列表并选择要恢复的任务,也可以通过滑动清除任务将其从列表中删除。 对于 Android 5.0 版本(API 级别 21),包含多个文档的同一 Activity 的多个实例可能会以任务的形式显示在概览屏幕中。例如,Google Drive 可能对多个 Google 文档中的每个文档均执行一个任务。每个文档均以任务的形式显示在概览屏幕中。

    Task中activity的特点:

    1. 可以来自不同的app
    2. 可以运行在不同进程

    影响Task的activity的属性和Intent标识

    Activity的属性:

    1. launchMode
    2. taskAffinity
    3. allowTaskReparenting
    4. clearTaskOnLaunch
    5. alwaysRetainTaskState
    6. finishOnTaskLaunch

    Intent的标识(四个与task直接关系的):

    1. FLAG_ACTIVITY_NEW_TASK
    2. FLAG_ACTIVITY_CLEAR_TOP
    3. FLAG_ACTIVITY_SINGLE_TOP
    4. FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
      ...

    什么是Activity的启动模式(LaunchMode)

    启动模式简单地说就是Activity启动时的策略,在AndroidManifest.xml中的标签的android:launchMode属性设置
    启动模式有4种,分别为standard、singleTop、singleTask、singleInstance;

    这四种模式影响了Activity所在的任务栈.

    使用方式:在清单文件中activity的节点加入launchMode属性

    1. standard

    默认模式,当Intent发送的时候,每次打开都会创建一个新的Activity实例。
    如果app1启动了app2的activity,则会将APP2的activity自动加入到app1的activity所在的task

    在5.0中,也没有出现跨应用会在新的task中启动activity的的情况 与该文章Understand Android Activity's launchMode: standard, singleTop, singleTask and singleInstance描述的并不太一样

    1. singleTop

    几乎和standard模式一模一样,一个singleTop的Activity的实例可以无限多,唯一的区别是如果当前activity已经在栈顶的话,则不会再创建一个新的activity,通过onNewIntent()将intent发送给现有的Activity。

    1. singleTop模式,只在当前任务栈中生效.
    2. 如果通过startActivityForResult启动一个设置了singleTop的activity,singleTop模式将无效(不知道为什么网上很多人说该设置该singleTop也会导致立即在onActivityResult中返回一个为cancel的resultCode,实测下来4.x,5.x的版本都没问题)

    onNewIntent()使用Tips

    1. 方法体中需手动调用setIntent(intent),否则之后的getIntent()获取的都是旧的intent对象;
    2. 被onNewIntent方式打开的activity,对生命周期的影响.
     1. 之前activity是resume状态,onNewIntent()后只会调用onResume()方法
      2. 否则按照 `onNewIntent->onRestart->onStart->onResume->.`
    

    应用场景

    这种启动模式的用例之一就是搜索功能。假设我们创建了一个搜索框,点击搜索的时候将导航到一个显示搜索结果列表的SearchActivity中,为了更好的用户体验,这个搜索框一般也会被放到SearchActivity中,这样用户想要再次搜索就不需要按返回键。
    想像一下,如果每次显示搜索结果的时候我们都启动一个新的activity,10次搜索10个activity,那样当我们想返回最初的那个activity的时候需要按10次返回。
    所以我们应该这样,如果栈顶已经有一个SearchActivity,我们将Intent发送给现有的activity,让它来更新搜索结果。这样就只会有一个在栈顶的SearchActivity,只需点一次back就可以回到之前的activity。
    不管怎样,singleTop和它的调用者处在一个任务中。如果你想要让intent发送给另一个任务中处于栈顶的Activity,是不行的。
    而当Intent来自于另外一个应用的时候,新的Activity的启动方式和standard模式是一致的。

    1. singleTask

    首先要引出taskAffinity这个activity的属性.

    把TASK比作一个班级,affinity则更像是这个班级的班级名称,学校比做系统,Activity更像是班级里的学生

    *如果没有对activity设置该属性的话,默认为application的**taskAffinity**,如果application也没有设置,则为app的包名.*
    

    启动一个singleTask模式的activity,会首先在系统中找与它的taskAffinity属性一致的任务栈,

    1. 先找task

      1. 没有特别指定taskAffinity,则为当前的task
      2. 如果指定了taskAffinity,先在系统中查找task,如果找不到则创建一个新的task,将activity作为root放置其中.
    2. 启动Activity

    如果第一步中的task中已经有了这个activity的实例,则将其显示(**将task中该activity上层的activity都pop出任务栈**),同时intent将被通过onNewIntent()发送. 
    

    对设置为singleTask的activity的总结

    1. `并不是一定会在新的任务栈中打开.(具体要根据taskAffinity(班级名称)看系统(学校)中是否已经有这个任务栈(班级)了).`
    2. `如果需要在新的任务栈中启动,就需要为activity设置独立的taskAffinity.`
    3. `如果任务栈中已存在该activity,那么会将上层的所有activity弹出.`
    4. `如果当前activity是在新的任务栈中打开的话,那么之后在该activity中通过默认方式启动的activity都在这个新的任务栈(这个跟我们接下里要讲的singleInstance有区别)`
    5. `如果是在新的任务栈中启动的话,最近任务列表(android的多任务键按下后)会有两个,可选择返回至相应的任务栈`
    6. 当作为startActivityForResult启动的目标时
        1. 4.x版本.会立刻在上个activity中onActivityResult中返回一个为cancel的resultCode.(不管新的activity是否是在新的任务栈中启动)
        2. 5.x版本.不管是否定义了taskAffinity,都会把将要被启动的activity的启动模式忽略,onActivityResult方法会正常回调
    

    应用场景

    该模式的使用场景多类似于邮件客户端的收件箱或者社交应用的时间线Activity(朋友圈)

    1. singleInstance

    与 "singleTask" 基本相同,总是该Activity始终是其所在task中唯一仅有的成员;之后在该activity中启动的activity都不会在其所在的task中.

    总结

    1. 当作为startActivityForResult启动的目标时(下文中的它都是指被启动的activity)
      1. 4.x版本.在新的任务栈中启动,并立刻在启动它的activity中的onActivityResult中返回一个为cancel的resultCode.singleInstance的特点还在
      2. 5.x版本.并不会在新的任务栈中启动,而是直接在当前任务栈启动(会出现多个实例),启动它的activity的onActivityResult方法会在它关闭后,正常回调.重点是被它开启的activity将运行在另外一个新的任务栈中.

    应用场景

    1. 呼叫来电界面 InCallScreen

    常用的Intent Flag

    1. FLAG_ACTIVITY_NEW_TASK

    > 文档摘录: When using this flag, if a task is already running for the activity you are now starting, then a new activity will not be started; instead, the current task will simply be brought to the front of the screen with the state it was last in. See FLAG_ACTIVITY_MULTIPLE_TASK for a flag to disable this behavior.`当使用这个flag时,如果task中已经有了你要启动的activity的话,就不再启动一个新的activity了,当前**task**会被带到前台(不管这个activity是否在前台,有可能activity上边还压有别的activity).如果不想要这种行为,可以用FLAG_ACTIVITY_MULTIPLE_TASK.
    
    > 比如说原来栈中情况是`A,B,C`,在`C`中启动`D`,如果在Manifest.xml文件中给`D`添加了Affinity的值和`C`所在的Task中的不一样的话,则会在新标记的Affinity所存在的Task中看是否这个activity已经启动,如果没启动,则直接将activity启动.如果启动了,直接将`D`所在的task带入到前台;如果是默认的或者指定的Affinity和Task一样的话,就和标准模式一样了启动一个新的Activity.
    
    1. FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET | FLAG_ACTIVITY_NEW_DOCUMENT (API21)

    > FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET在API 21的时候,被FLAG_ACTIVITY_NEW_DOCUMENT代替
    

    如果一个Intent中包含此属性,则它转向的那个Activity以及在那个Activity其上的所有Activity都会在task重置时被清除出task。当我们将一个后台的task重新回到前台时,系统会在特定情况下为这个动作附带一个FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记,意味着必要时重置task,这时FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET就会生效。经过测试发现,对于一个处于后台的应用,如果在launcher中点击应用,这个动作中含有FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记,长按Home键,然后点击最近记录,这个动作不含FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记,所以前者会清除,后者不会.
    应用场景:
    比如我们在应用主界面要选择一个图片,然后我们启动了图片浏览界面,但是把这个应用从后台恢复到前台时,为了避免让用户感到困惑,我们希望用户仍然看到主界面,而不是图片浏览界面,这个时候我们就要在转到图片浏览界面时的Intent中加入此标记

    5.0之前,Activity1用该flag启动Activity2在OverviewScreen中是没有分开的.也就是说如果back到后台后,再通过launcher中点击app的icon进入,将直接进入Activity1,并且无法回到activity2的界面.
    5.0之后,OverviewScreen中,会将两个activity分开.可以返回指定想要的activity.
    
    1. FLAG_ACTIVITY_MULTIPLE_TASK

    > 不建议使用此标记,除非你自己实现了应用程序的启动器。结合FLAG_ACTIVITY_NEW_TASK这个标记,即使要启动的activity已经存在一个task在运行,也会新启动一个task来运行要启动的activity
    

    系统缺省是不带任务管理器的,所以当你使用这个标签的时候,你必须确保你能从你启动的task中返回回来。
    如果没有设置FLAG_ACTIVITY_NEW_TASK,这个标记被忽略

    1. FLAG_ACTIVITY_CLEAR_TASK

    > 文档原文:`If set in an Intent passed to Context.startActivity(), this flag will cause any existing task that would be associated with the activity to be cleared before the activity is started. That is, the activity becomes the new root of an otherwise empty task, and any old activities are finished. This can only be used in conjunction with FLAG_ACTIVITY_NEW_TASK.` 
    个人翻译:`这个flag会导致,在这个activity启动之前,任何与该activity相关的task都会被清除.也就是说,这个activity将会是一个空task的最底部的activity,之前所有的activity都会被finish掉.这个flag只能和FLAG_ACTIVITY_NEW_TASK结合使用.`
    比如说原来栈中情况是`A,B,C,D`,在D中启动B(加入该flag),中间过程是`A,B,C`依次destory,D先onPause,随后BonCreate,onStart,onResume.D再onStop,onDestory.最后只有一个B在栈底.(无论taskAffinity..?)
    
    1. FLAG_ACTIVITY_SINGLE_TOP

    > 相当于launchMode中的singleTop,比如说原来栈中情况是`A,B,C,D`,在D中启动D(加入该flag),栈中的情况还是`A,B,C,D`.
    
    1. FLAG_ACTIVITY_CLEAR_TOP

    > 不同于launchMode中的singleTask,比如说原来栈中情况是`A,B,C,D`,在D中启动B(加入该flag), 栈中的情况将为`A,B`.但是B会重新onCreate()...,并没有执行onNewIntent().如果希望与singleTask效果相同,可以加入`FLAG_ACTIVITY_SINGLE_TOP`.
    
    1. FLAG_ACTIVITY_REORDER_TO_FRONT

    > 这个跟上边FLAG_ACTIVITY_BROUGHT_TO_FRONT的是容易混淆的.比如说原来栈中情况是`A,B,C,D`,在D中启动B(加入该flag),栈中的情况会是`A,C,D,B`.(调用onNewIntent())
    
    1. FLAG_ACTIVITY_BROUGHT_TO_FRONT

    > 这个是最容易让人误解的flag了.跟FLAG_ACTIVITY_REORDER_TO_FRONT是不一样的.不是由我们一般开发者使用的flag.
    文档中解释:This flag is not normally set by application code, but set for you by the system as described in the launchMode documentation for the singleTask mode.
    
    1. FLAG_ACTIVITY_NO_HISTORY

    > A启动B(加入该Flag),B启动C.在C返回,将直接返回到A.B在A正常onResume后,才会调用`onStop,onDestory...`
    而且被这个flag启动的activity,它的onActivityResult()永远不会被调用
    
    1. FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS

    > 我所理解的,加了这个flag启动的activity所在的task(必须是该task中最底部的activity)将不会在多任务界面出现.一般配合FLAG_ACTIVITY_NEW_TASK使用,这样新的任务栈,在最近使用列表中,就不会出现.
    
    1. FLAG_ACTIVITY_FORWARD_RESULT

    > 多个Activity的值传递。A通过startActivityForResult启动B,B启动C,但B为过渡页可以finish了,A在期望C把结果返回.这种情况,B可以在启动C的时候加入该flag.
    
    1. FLAG_ACTIVITY_NO_USER_ACTION

    > 禁止activity调用onUserLeaveHint()。
      onUserLeaveHint()作为activity周期的一部分,它在activity因为用户要跳转到别的activity而退到background时使用。比如,在用户按下Home键(用户的操作),它将被调用。比如有电话进来(不属于用户的操作),它就不会被调用。注意:通过调用finish()时该activity销毁时不会调用该函数。 
    
    1. FLAG_ACTIVITY_RETAIN_IN_RECENTS (API21)

    > 与activity设置autoRemoveFromRecents = false属性效果一样.是指当前activity销毁后,是否还在概览屏幕中显示.(5.0之后生效)
    
    1. FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

    > 一般为系统使用,比如要把一个应用从后台移到前台,有两种方式:从多任务列表中恢复(不包含该flag);从启动器中点击icon恢复(包含该flag);需结合` FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET | FLAG_ACTIVITY_NEW_DOCUMENT (API21)`理解
    
    1. FLAG_ACTIVITY_PREVIOUS_IS_TOP

    > 即 A---> B --->C,若B启动C时用了这个标志位,那在启动时B并不会被当作栈顶的Activity,而是用A做栈顶来启动C。此过程中B充当一个跳转页面。
    

    典型的场景是在应用选择页面,如果在文本中点击一个网址要跳转到浏览器,而系统中又装了不止一个浏览器应用,此时会弹出应用选择页面。在应用选择页面选择某一款浏览器启动时,就会用到这个Flag。然后应用选择页面将自己finish,以保证从浏览器返回时不会在回到选择页面。
    经常与FLAG_ACTIVITY_FORWARD_RESULT 一起使用。

    1. FLAG_ACTIVITY_TASK_ON_HOME

    > 该flag启动的activity,点击返回键会回到launcher.需要与`FLAG_ACTIVITY_NEW_TASK`一起使用,并且`FLAG_ACTIVITY_NEW_TASK`模式生效(参考该属性)后,该flag才会起作用.
    
    1. FLAG_EXCLUDE_STOPPED_PACKAGES

    > 设置之后,Intent就不会再匹配那些当前被停止的包里的组件。如果没有设置,默认的匹配行为会包含这些被停止的包。
    
    1. FLAG_DEBUG_LOG_RESOLUTION

    > debug模式可以打印log
    

    Activity的task相关属性

    参考: 基础总结篇之三:Activity的task相关

    1. allowTaskReparenting

    > 这个属性用来标记一个Activity实例在当前应用退到后台后,是否能从启动它的那个task移动到有共同affinity的task,“true”表示可以移动,“false”表示它必须呆在当前应用的task中,默认值为false。
    比如在app1的activityA中打开app2的activity2,按home键,回到后台后,这时在launcher中点击App1,页面显示的是app1的activityA(是在此时将activity2转移到app2的task中).再点击app2,则显示的是activity2,点击back,则会在app2所在的任务栈中回退.
    

    需要注意的是,如果app1退居后台之后,没有再次启动app1,而是直接启动app2,将不会出现以上现象。重新宿主的动作发生在appB再次启动的过程中

    1. alwaysRetainTaskState

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

    默认情况下,如果一个应用在后台呆的太久例如30分钟,用户从主选单再次选择该应用时,系统就会对该应用的task进行清理,除了根Activity,其他Activity都会被清除出栈,但是如果在根Activity中设置了此属性之后,用户再次启动应用时,仍然可以看到上一次操作的界面。
    这个属性对于一些应用非常有用,例如Browser应用程序,有很多状态,比如打开很多的tab,用户不想丢失这些状态,使用这个属性就极为恰当。

    1. clearTaskOnLaunch

    > 这个属性用来标记是否从task清除除根Activity之外的所有的Activity,“true”表示清除,“false”表示不清除,默认为“false”。同样,这个属性也只对根Activity起作用,其他的Activity都会被忽略。 如果设置了这个属性为“true”,每次用户重新启动这个应用时,都只会看到根Activity,task中的其他Activity都会被清除出栈。
    
    1. finishOnTaskLaunch

    > 与allowReparenting属性相似,不同之处在于allowReparenting属性是重新宿主到有共同affinity的task中,而finishOnTaskLaunch属性是销毁实例。如果这个属性和android:allowReparenting都设定为“true”,则这个属性优先级高。
    
    1. documentLaunchMode

    #### intoExisting
    > 该 Activity 会对文档重复使用现有任务。这与不设置 FLAG_ACTIVITY_MULTIPLE_TASK 标志、但设置 FLAG_ACTIVITY_NEW_DOCUMENT 标志所产生的效果相同,如上文的使用 Intent 标志添加任务中所述。
    
    #### always
    > 该 Activity 为文档创建新任务,即便文档已打开也是如此。使用此值与同时设置 FLAG_ACTIVITY_NEW_DOCUMENT 和 FLAG_ACTIVITY_MULTIPLE_TASK 标志所产生的效果相同。
    
    #### none
    > 该 Activity 不会为文档创建新任务。概览屏幕将按其默认方式对待此 Activity:为应用显示单个任务,该任务将从用户上次调用的任意 Activity 开始继续执行。
    
    #### never
    > 该 Activity 不会为文档创建新任务。设置此值会替代 FLAG_ACTIVITY_NEW_DOCUMENT 和 FLAG_ACTIVITY_MULTIPLE_TASK 标志的行为(如果在 Intent 中设置了其中一个标志),并且概览屏幕将为应用显示单个任务,该任务将从用户上次调用的任意 Activity 开始继续执行。
    

    对于除 none 和 never 以外的值,必须使用 launchMode="standard" 定义 Activity。如果未指定此属性,则使用 documentLaunchMode="none"。

    引用

    meizixiongActivity的四种启动模式
    android 任务栈及启动模式
    android的task任务栈
    Intent Flag的几种介绍



    作者:phoenixsky
    链接:https://www.jianshu.com/p/c1386015856a
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

    2, Activity次级页面和主页间来回跳转,防止重复创建Activity实例

    很多时候,在进入详情页或次级页面的时候,最后会返回到上一个Activity。在返回时,一般用Intent去启动。但是如果单纯地使用

    Intent intent = new Intent(A.this, B.class) ;
    startActivity(intent) ;

    你会发现,多次地从A进入B,又从B回到A,然后这两个Activity就会一直创建。打log发现两个Activity的onCreate方法一直调用,而栈里也一层一层地叠着这俩Activity的实例。当你按返回键准备返回时,发现并不能实现从次级页面返回到主页,然后退出应用这一流程,会把栈里所有创建的实例都出栈完了才会退出。

    怎么实现无论点击多少次互相跳转,当页面在主页A的时候,点击返回时都会退出应用。即A  Activity在栈中只有一个实例。

    方法1:在Manifest里设置主页(A)的launchMode为singleTask,这样每次从次级页面返回时,会将主页A上面的Activity清空,让A重新回到栈顶。这样无论点击多少次AB跳转,都不会出现从主页返回到了次级页面。

    方法2:在代码中由B启动A时,给Intent设置Flag。

    Intent intent = new Intent(B.this, A.class) ;
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) ;
    startActivity(intent) ;

    FLAG_ACTIVITY_CLEAR_TOP也会清空目标Activity(A)和它上面的所有Activity,并且重新创建A,所以在B跳转A时,打Log会发现,

    A onDestroy()
    A onCreate()
    B onDestroy()

    问题是解决了,但是A重新创建了一次,A毕竟是主页,是很多次级Activity返回的终点,不想A重新创建,怎么办? 
    可以给主页A设置launchMode为singleTask,这样A就不会重新创建了(A -> B ->A -> B -> A -> B ->A):

     A onCreate
     B onCreate
     B onDestroy
     B onCreate
     B onDestroy
     B onCreate
     B onDestroy

    可以看到,无论AB之间互相跳转多少次,都不会重新创建A,只是身为次级页面的B会一直创建,当然,很多情况下,次级页面只会进入一次,比如新建××,修改××,这种次级页面会随着任务的完成而结束,销毁也是应该的。

    1, activity的启动模式:

    http://www.cnblogs.com/plokmju/p/android_ActivityLauncherMode.html

    当然,在Android中,除了在AndroidManifest.xml清单文件中配置LauncherMode属性外,还可以在代码中设置启动模式。

    在组件中,启动一个Activity,需要用到startActivity()方法,其中传递一个Intent,可以使用Intent.setFlags(int flags)来设置新启动的Activity的启动模式,

    而通过代码设置Activity的启动模式的方式,优先级要高于在AndroidManifest.xml清单文件中的配置。 

      Intent.setFlag(int flags)方法传递的一个整形的数据,被Android系统设置为了常量:

    • FLAG_ACTIVITY_NEW_TASK:这个标识会使新启动的Activity独立创建一个Task。
    • FLAG_ACTIVITY_CLEAR_TOP:这个标识会使新启动的Activity检查是否存在于Task中,如果存在则清除其之上的Activity,使它获得焦点,并不重新实例化一个Activity,一般结合FLAG_ACTIVITY_NEW_TASK一起使用。
    • FLAG_ACTIVITY_SINGLE_TOP:等同于在LauncherMode属性设置为singleTop。

    前言

      在一个Android应用中,不可避免的会包含多个Activity,当开启多个Activity之后,当按后退键时,一般会回退到上一个Activity,这一点和浏览器有点类似,但是需要注意的是Android系统只能回退到上一个Activity,没办法前进到下一个Activity,维护这个功能就需要了解到一个回退栈(Back Stack)的概念。

      这篇博客就着重讲

    1. 什么是回退栈
    2. 回退栈的状态
    3. Activity的几种启动模式

    什么是回退栈?

      首先先来了解一下应用程序与进程的关系,众所周知,Android下有四大组件:Activity、Service、Receiver、ContentProvider。一般开发一个应用程序,会包含多个Android组件,所以应用程序是一组组件的集合,而进程则是运行这些组件的载体。

      而回退栈(Back Stack)只是针对Activity而言的,它是用来维护用的界面体验的,使一个Task让用户感觉就是一个应用,而无论其中的Activity是否来自同一个应用程序,所以不要把回退栈和进程弄混了。设备的Home页面是大多数Task的起始位置,当用户点击一个应用程序图标的时候,应用的Task就会来到前台,并把应用的主Activity压入BackStack的栈顶,并获得焦点,这个Activity称为根Activity,而在BackStack中的Activity可以通过点击回退键弹出栈并销毁,这时就会使上一个Activity获得焦点,直到用户返回到Home页,而当BackStack中的Activity都被弹出销毁之后,这个Task就不复存在了,但是这个程序的进程还存在(不在此时销毁)。

     

    Task的状态

      就像上面介绍的,每个Task都存在一个BackStack,而系统中可以存在多个Task,但是每次只有一个Task获得前台焦点,一般而言,系统允许用户在多个Task中切换,而被至于后台的Task中的Activity,将被置于Stopped状态。实际上,同一个Task中的Activity,只要不存在于栈顶并且获得前台焦点的Activity,那么它就是一个Stopped的状态。下图为官方文档中关于Task前后台的示例图:

    Activity的启动模式

      根据Activity的不同的启动模式,它在BackStack中的状态是不一样的。Activity可以通过AndroidManifest.xml清单文件配置,在<Activity />节点中的android:launchMode属性设置。它有四个选项:

     

    standard

      标准启动模式,也是默认启动模式,如果不设置android:launchMode属性的话。standard模式下的Activity会依照启动的顺序压入BackStack中。

      下图是standard模式下,Activity的压栈和回退操作示意图:

      

    singleTop

       单顶模式,这种Activity启动模式,启动一个Activity的时候如果发现BackStack的栈顶已经存在这个Activity了,就不会去重新创建新的Activity,而是复用这个栈顶已经存在的Activity,避免同一个Activity被重复开启。

      下图是singleTop模式下,Activity的压栈和回退操作示意图:

      singleTop的应用场景很多,一般适用于可以复用而又有多个开启渠道的Activity,避免当一个Activity已经开启并获得焦点后,再次重复开启。

    比如说Android系统浏览器的书签页面,就是一个singleTop模式的Activity。

    Android的浏览器是基于WebKit内核编写的,它是支持JavaScript脚本语言的,可以通过JavaScript脚本设置浏览器书签,这样如果存在多个页面存在保存书签的JavaScript脚本,就会导致书签页面被多次开启,所以书签页面被设置为singleTop模式,这样可以避免在保存多个书签的时候重复开启书签页面。

     

    singleTask

      开启一个Activity的时候,检查BackStack里面是否有这个Activity的实例存在,如果存在的话,情况BackStack里这个Activity上所有的其他Activity。

      下图是singleTask模式下,Activity的压栈和回退操作示意图:

      singleTask的的适用场景为一般程序的主页面,当回退到主页面的时候,清除BackStack中,它之上的所有Activity,这样避免程序导航逻辑的混乱。

    比如Android系统的浏览器的主页面,就是singleTask模式的,上面提到,android下浏览器是Webkit内核的,它是由C语言编写的,而每次打开新的网页如果重新开启一个Activity,是非常耗费系统资源的(需要解析HTML、Script脚本),所以被设置为singleTask模式,这样在浏览器应用里,无论打开多少个页面,使用的都是同一个Activity。

    所以以后如果存在很耗费系统资源的Activity,可以考虑使用singleTask开启模式。

     

    singleInstance

      被标记为singleInstance启动模式的Activity,在启动的时候,会开启一个新的BackStack,这个BackStack里只有一个Activity的实例存在,并且把这个BackStack获得焦点。

    这是一种很极端的模式,它会导致整个设备的操作系统里,只会存在一个这个Activity示例,无论是从何处被启动的。

      下图是singleInstance模式下,Activity的压栈和回退操作示意图: 

       singleInstance一般适用于需要在系统中只存在一个实例的场景,比如Android系统的来电页面,多次来电均使用的是一个Activity。

     

     

    总结

      这篇博客主要讲的是理论上的内容,也没什么示例代码,无非就是几种启动模式的特点需要注意一下,理解了Activity的启动模式,可以很好的提升用户的UI体验,对应用程序的推广是非常有好处的,毕竟一个用户体验很差的应用,是很难得到用户的推广的。

    作者:承香墨影
    更多内容,请阅读本人新书:《Android深入浅出》
    欢迎转载,但还请尊重劳动果实,保留此段声明并注明原文链接。
  • 相关阅读:
    php函数
    2、Locust压力测试 实战
    mysql常用命令
    3、加强siege性能测试
    2、使用siege进行服务端性能测试
    1、siege安装
    京东云Ubuntu下安装mysql
    1、Locust压力测试环境搭建
    1、Monkey环境搭建
    Postman和Selenium IDE开局自带红蓝BUFF属性,就问你要还是不要
  • 原文地址:https://www.cnblogs.com/awkflf11/p/4175882.html
Copyright © 2020-2023  润新知