• Develop系列-API Guides-应用组件-Activities-Tasks and Back Stack


    Tasks and Back Stack

    一个app一般包含多个activities,每个activity执行不同任务。

    Task是与用户交互执行一系列任务的activities集合,这些activities以打开顺序排列在一个栈列表中。

    用户点击主页面的图标或者快捷方式,如果此应用从未被执行过,那么会创建一个新的task,主界面activity作为这个task的根activity,当根activity启动其他界面,一个新的activity会被压到task的栈顶并获取焦点。此时根activity仍然在task中保存,当用户按返回键时,当前的activity会被弹出task栈堆并销毁,前一个activity重新resumes(之前UI上的状态数据重新加载)。

    Task中的activities顺序永远不会重排,只有push(入栈)和pop(出栈)两种动作,作为栈堆,保持着后进先出的原则。

    如图所示,1是task的根activity;1启动2之后,2入栈,1被压到栈底,2在栈顶;2启动3之后,3入栈;返回键,3出栈被销毁,2继续在栈顶。这个task中所有在栈顶的activity都是可见并获取用户焦点的界面。

    当所有activities都出栈后,那么这个task也就不存在了。

    Task可以作为一个整体单元,可以被整体移动到后台,当用户通过Home键返回主界面并启动新的task。

    Note:多个task可以同时在后台,但是有可能被系统在回收内存时销毁。

    如下是activities和tasks的默认行为:

    • A 启动 B,A被停止,系统保存A的状态数据。如果用户在B界面按返回键,B销毁,A恢复保存的状态数据。
    • 用户按Home键离开某个task,task中所有activities停止,并退到后台,如果用户而后通过桌面图标启动此task,此task会切到前台并恢复栈顶activity。
    • 如果用户按返回键,当前栈顶的activity会出栈,并被销毁,下一个切到栈顶的activity会恢复。activity被销毁后,系统不会保存其状态数据。
    • activities能够被实例化多次,即使在不同的tasks。

    当系统销毁后台task中的activities时,这些activities界面用户临时数据会丢失(即便如此,task中的顺序依旧存在),当这些activities重新回到栈顶时,不是通过resume,而是通过recreate。为了避免此类数据丢失,强烈建议通过onSaveInstanceState()来保存临时数据。

    管理Tasks

    有时候你需要一个activity在每次启动时都是重新创建一个新的task,而不是安排到现有的task中;或者你创建activity时,直接使用现有已经创建的activity实例,而不是在栈顶创建新的实例;又或者你想用户离开task后清除根activity之外的其他activities。

    你可以通过<activity>的属性和intent的flag来改变默认的行为。

    <activity>属性如下:

    intent的flag如下:

    Caution:多数应用不需要改变系统的默认行为,如果你确定需要改变默认行为,那么你需要确保启动、返回等场景下应用的可用性,有可能返回键的行为会与用户的预期有冲突。

    定义启动模式

    启动模式允许你定制一个新的activity实例与当前task的关联,有如下两种方式:

    • 用manifest文件:被启动时此activity该如何关联
    • 用intent flags:新启动的activity该如何关联

    如果A启动B,B能过通过manifest定义关联方式,A也能通过intent flags来定义B的关联方式,如果两个都有定义,那么A的intent flags优先。

    Note:两种方式不是对等的,有些模式只能用manifest文件来定义,有些只能用intent flags来定义。

    用manifest文件

    <activity>元素的launchMode属性:

    • standard(默认模式)
      • 默认模式,系统创建新的activity实例,activity能被实例化多次,每个实例可以属于不同的tasks,一个task能包含多个实例。
    • singleTop
      • 如果activity的实例已经存在,并在task的栈顶,那么系统会调用存在实例的onNewIntent()而不是创建新的实例。activity可以被实例化多次,每个实例可以属于不同的task,一个task可以有多个实例(栈顶不是此activity的实例的task)
      • 例如,A-B-C-D,A是栈底,D是栈顶,此时又来一个intent需要启动D,如果D是standard模式,那么会变为A-B-C-D-D,然后如果D是singleTop模式,那么仍是A-B-C-D,intent会由D的onNewIntent来接收。如果此时启动B,那么不管B是standard或者singleTop模式,都是A-B-C-D-B
    • singleTask
      • 系统创建新的task,然而如果activity的实例已经在其他task中存在,那么系统会将intent分发给存在的实例,触发其onNewIntent(),而不是创建一个新的实例,系统只能存在一个实例,浏览器就是如此。
    • singleInstance
      • 与singleTask相同,系统不能启动其他activites到存在此activity的task,标记了singleInstance的activity是task的唯一成员。

    一般来说,返回键总是给用户带来上一个界面,当你启动singleTask模式的activity时,如果此activity实例已经在后台task中存在,那么整个task会被切到前台,此时,返回键是逐个显示刚切到前台的task中的所有activities。如下图所示:

    Note:manifest中launchMode属性有可能会被intent flags所覆盖。

    使用Intent flags

    FLAG_ACTIVITY_NEW_TASK

    与singleTask一致

    FLAG_ACTIVITY_SINGLE_TOP

    与singleTop一致

    FLAG_ACTIVITY_CLEAR_TOP

    如果activity实例已经在当前task中,启动时,此实例之上的activities都会被销毁,此实例触发onNewIntent()并处于栈顶。

    FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_NEW_TASK一般联合使用。

    Note:如果launch mode是standard,那么已存在的实例也会被销毁,通过创建新的实例来替换销毁实例的位置,因为standard模式始终通过创建新实例来接收intent。

    Handling affinities

    affinity意味着activity隶属于哪个task。默认的,同一app的所有activities对于彼此有affinity,所以默认的,同一app的所有activities都在一个task中。然而,你也可以修改默认的affinity。不同app中的activities能共享一个affinity,或者同一个app中的activities能定义不同的affinities。

    可以通过<activity>的taskAffinity属性来修改affinity,taskAffinity是唯一的字串。

    两种使用affinity的场景:

    • Intent包含FLAG_ACTIVITY_NEW_TASK,一般系统会创建新的task,当然如果已存在task的taskAffinity与新启动的activity相同,那么也不会创建新的task。
    • 当allowTaskReparenting属性为true,

    Tip:如果apk包含不止一个“application”,那么可以定义taskAffinity来区分。

    Clearing the back stack

    当用户离开task很长时间后,系统会清理除根activity之外的所有activities,当用户又重新回到这些task,那么只有根activity才会显示。

    用户可以通过如下方式来修改这种默认行为:

    alwaysRetainTaskState

    如果为true在根activity中,那么上述默认行为不会发生,此task中所有activities都会长时间保持

    clearTaskOnLaunch

    如果为true在根activity中,那么上述默认行为会在用户离开task后立即发生

    finishOnTaskLaunch

    与clearTaskOnLaunch类似,但是只针对某个activity,而不是整个task,根activity如果定义属性为true也会被清除

    启动一个task

    同时定义"android.intent.action.MAIN""android.intent.category.LAUNCHER"的activity在桌面上有入口图标。

    这个非常重要:用户可以离开这个task,也可以通过桌面图标返回这个task,所以定义这两种filiter的activites通常会初始化一个task。

    singleTask和singleInstance应当在这种activity上定义,试想一下,singleTask启动的activity在一个新的task中,此时用户按Home键,如果桌面上无入口图标,那这个task将永远无法返回。

    如果你真心不想用户能够返回一个activity,可以设置finishOnTAskLaunch属性。

  • 相关阅读:
    php composer 相关及版本约束等小技巧
    Jquery 获取表单值如input,select等方法
    Apache benchmark 压力测试工具
    Linux中的随机数文件 /dev/random /dev/urandom
    redis持久化
    Python---装饰器
    高仿拉手网底部菜单实现FragmentActivity+Fragment+RadioGroup
    python实现二叉树和它的七种遍历
    Spring AOP应用实例demo
    二维数组的列排序
  • 原文地址:https://www.cnblogs.com/konger/p/3913752.html
Copyright © 2020-2023  润新知