搜索内容

有一个问题?

如果您有任何疑问,可以在下面询问或输入您要寻找的!

Activity栈管理(三):Intent的Flag与taskAffinity

生成海报
bug樱樱
bug樱樱 2021-02-01 18:32
阅读需:0

创作者:anly_jun
连接:https://www.jianshu.com/p/c97688eb5056

引入上文生命期和launchMode详细介绍, Activity的生命期事实上比大家想像的繁杂得多.

文中关键根据案例, 来探寻下Activity的运行Intent Flag及其taskAffinity对生命期和Task/Back Stack的危害. 算作对生命期和launchMode的一个填补, 便于我们在开发设计全过程中灵便组成应用.

按照惯例, 大家先从一些官方网表述逐渐:

1, 有关定义

  • 对生命期和Task/Back Stack有影响的Intent Flag关键有:
    • FLAG_ACTIVITY_NEW_TASK
    • FLAG_ACTIVITY_CLEAR_TOP
    • FLAG_ACTIVITY_SINGLE_TOP
  • FLAG_ACTIVITY_NEW_TASK
    • 会造成与 “singleTask” launchMode 值同样的个人行为.
    • 在新每日任务中运行Activity. 假如现有包括该Activity的每日任务,则该每日任务会转至前台接待并修复其最终情况,另外该Activity会在onNewIntent()中接到新Intent.
  • FLAG_ACTIVITY_SINGLE_TOP
    • 会造成与 “singleTop” launchMode 值同样的个人行为.
    • 假如已经运行的Activity是当今Activity(坐落于回到栈的顶端), 则目前案例会接受对 onNewIntent()的启用,而不是建立 Activity 的新案例.
  • FLAG_ACTIVITY_CLEAR_TOP
    • 假如已经运行的 Activity 已在当前任务中运作,则会消毁当前任务顶端的全部 Activity,并根据 onNewIntent() 将此 Intent 传送给 Activity 已修复的案例(如今坐落于顶端),而不是运行该 Activity 的新案例.
    • 假如特定 Activity 的运行方式为 “standard”,则该 Activity 也会从局部变量中删掉,并在其部位运行一个新案例,便于解决传到的 Intent。 这是由于当运行方式为 “standard” 时,将自始至终为新 Intent 建立新案例.

之上为官方网文本文档表述.

在探寻Activity之launchMode一文中大家也提及了事实上文本文档因为"破旧"沒有紧跟, 有一些表述是不科学的.
我们可以追随案例一起看下.

2, 逐渐探寻

使用之前探寻生命期的Demo程序流程.
Github源代码详细地址

根据AActivity, BActivity, CActivity这三个Activity中间的自动跳转来开展intent flag的探寻.

要是没有独到之处, 默认设置A, B, C三个Activity的launchMode全是默认设置的standard方式.

2.1, FLAG_ACTIVITY_NEW_TASK

2.1.1, 实行B -> A, B运行A时加FLAG_ACTIVITY_NEW_TASK

试验目地是看看, 在当今系统软件沒有A案例时, 用FLAG_ACTIVITY_NEW_TASK来运行A是否会将A建立在独立的每日任务中.

BActivity.java中:

startActivity(new Intent(BActivity.this, AActivity.class)
                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));

生命期Log:

img

Task/Back Stack信息内容:

  Stack #1 mStackId=3:
    Task id #35
    * TaskRecord{42b60ae0 #35 A=com.anly.samples U=0 sz=3}
      numActivities=3 rootWasReset=false userId=0 mTaskType=0 numFullscreen=3 mOnTopOfHome=true
      affinity=com.anly.samples
      intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.anly.samples/.MainActivity}
      realActivity=com.anly.samples/.MainActivity
      Activities=[ActivityRecord{4285c1b0 u0 com.anly.samples/.MainActivity t35}, 
      ActivityRecord{42decc00 u0 com.anly.samples/.activity.BActivity t35}, 
      ActivityRecord{4376b9e8 u0 com.anly.samples/.activity.AActivity t35}]

能够见到:
B以FLAG_ACTIVITY_NEW_TASK运行A, A依然和B处于同一个Task中.

2.1.2 实行A -> B -> A, B运行A时加FLAG_ACTIVITY_NEW_TASK

试验目地是想认证下官方网文本文档对FLAG_ACTIVITY_NEW_TASK的表述, 在A案例早已存有的状况下, 以FLAG_ACTIVITY_NEW_TASK运行A会产生哪些.

生命期Log:

img

Task/Back Stack信息内容:

  Stack #1 mStackId=2:
    Task id #34
    * TaskRecord{42bfb088 #34 A=com.anly.samples U=0 sz=4}
      numActivities=4 rootWasReset=false userId=0 mTaskType=0 numFullscreen=4 mOnTopOfHome=true
      affinity=com.anly.samples
      intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.anly.samples/.MainActivity}
      realActivity=com.anly.samples/.MainActivity
      Activities=[ActivityRecord{42568318 u0 com.anly.samples/.MainActivity t34}, 
      ActivityRecord{42725050 u0 com.anly.samples/.activity.AActivity t34}, 
      ActivityRecord{42dab240 u0 com.anly.samples/.activity.BActivity t34}, 
      ActivityRecord{42e293f8 u0 com.anly.samples/.activity.AActivity t34}]

能够见到:
1, 在B运行A以前, Task #34中原本就会有A, 可是B加FLAG_ACTIVITY_NEW_TASK运行A时, A仍未器重, 只是在本Task #34中在这里建立了一个A的案例. (这一点和文本文档叙述不一致)
2, 这时Task #34中的Activity案例为ABA.
3, 可是假如A的lunchMode是singleTask得话, 如lunchMode一文2.2.3所显示, 这时应当消毁A之上的案例, Task中只剩余A.
4, 综上所述, FLAG_ACTIVITY_NEW_TASK并不等同于与singleTask. 且FLAG_ACTIVITY_NEW_TASK觉得并且为起功效(在A早已存有一个案例的状况下).

2.2, FLAG_ACTIVITY_SINGLE_TOP

2.2.1, 实行A -> B -> B, 在其中B运行B时加FLAG_ACTIVITY_SINGLE_TOP

BActivity运行B时加:

startActivity(new Intent(BActivity.this, BActivity.class)
                        .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP));

生命期Log:

img

Task/Back Stack信息内容:

  Stack #1 mStackId=6:
    Task id #38
    * TaskRecord{43665a30 #38 A=com.anly.samples U=0 sz=3}
      numActivities=3 rootWasReset=true userId=0 mTaskType=0 numFullscreen=3 mOnTopOfHome=true
      affinity=com.anly.samples
      intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.anly.samples/.MainActivity}
      realActivity=com.anly.samples/.MainActivity
      Activities=[ActivityRecord{42bbfea0 u0 com.anly.samples/.MainActivity t38}, 
      ActivityRecord{433b6130 u0 com.anly.samples/.activity.AActivity t38}, 
      ActivityRecord{4324ef18 u0 com.anly.samples/.activity.BActivity t38}]

能够见到:
1, B多路复用了, 根据onNewIntent, 走onResume步骤, 多路复用以前的B案例.
2, 这时Task #38中的Activity案例为AB.

2.3, FLAG_ACTIVITY_CLEAR_TOP

2.3.1, 实行A -> B -> A, 运行B运行A时加FLAG_ACTIVITY_CLEAR_TOP

试验目地是为了更好地看看A是否会器重, 且B是否会被Clear.

BActivity运行A的编码:

startActivity(new Intent(BActivity.this, AActivity.class)
                    .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP));

生命期Log:

img

Task/Back Stack信息内容:

 Stack #1 mStackId=7:
    Task id #39
    * TaskRecord{4274e020 #39 A=com.anly.samples U=0 sz=2}
      numActivities=2 rootWasReset=false userId=0 mTaskType=0 numFullscreen=2 mOnTopOfHome=true
      affinity=com.anly.samples
      intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.anly.samples/.MainActivity}
      realActivity=com.anly.samples/.MainActivity
      Activities=[ActivityRecord{42742598 u0 com.anly.samples/.MainActivity t39}, 
      ActivityRecord{4274eb28 u0 com.anly.samples/.activity.AActivity t39}]

能够见到:
1, A并沒有器重, 只是新创建了一个案例. 这一和文本文档是一致的, 参照FLAG_ACTIVITY_CLEAR_TOP定义第二点.
2, B被消毁了(Clear Top).
3, 这时Task #39中仅有A(一个新的A).

2.4, 组成应用

之上是简易应用, 随后具体情景中会出现许多组成应用Intent Flag及其Intent Flag与taskAffinity融合应用的状况. 在其中官方网文本文档就提及了:

FLAG_ACTIVITY_CLEAR_TOP 一般与 FLAG_ACTIVITY_NEW_TASK 融合应用。一起应用时,根据这种标示,能够寻找别的每日任务中的目前 Activity,并将其放进可从这当中回应 Intent 的部位。

下边大家来试验下这类组成:

2.4.1, FLAG_ACTIVITY_CLEAR_TOP + FLAG_ACTIVITY_NEW_TASK

实行A -> B -> A, 在其中B运行A时, Intent flag加FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_NEW_TASK

B运行A的编码:

startActivity(new Intent(BActivity.this, AActivity.class)
                    .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_NEW_TASK));

生命期Log:

img

Task/Back Stack信息内容:

  Stack #1 mStackId=8:
    Task id #40
    * TaskRecord{429c96b0 #40 A=com.anly.samples U=0 sz=2}
      numActivities=2 rootWasReset=false userId=0 mTaskType=0 numFullscreen=2 mOnTopOfHome=true
      affinity=com.anly.samples
      intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.anly.samples/.MainActivity}
      realActivity=com.anly.samples/.MainActivity
      Activities=[ActivityRecord{427907d0 u0 com.anly.samples/.MainActivity t40}, 
      ActivityRecord{42dd24b8 u0 com.anly.samples/.activity.AActivity t40}]

能够见到:
1, 結果和2.3.1独立应用Intent.FLAG_ACTIVITY_CLEAR_TOP是一样的.

2.5, taskAffinity填补试验

有2.1.1, 2.1.2及其2.4.1这三个包括Intent.FLAG_ACTIVITY_NEW_TASK的试验, 能够见到, 字面Intent.FLAG_ACTIVITY_NEW_TASK的意思是在新的task运行Activity, 殊不知实际上, 新Activity還是在原先的task上建立的.

这儿必须明确提出官方网站有关taskAffinity的表述了:

taskAffinity标示Activity优先选择归属于哪一个task. 默认设置状况下, 同一运用中的全部 Activity 彼此之间关系. 因而, 默认设置状况下, 同一运用中的全部 Activity 优先选择坐落于同样每日任务中.
taskAffinity在二种状况下能起功效:
运行 Activity 的 Intent 包括 FLAG_ACTIVITY_NEW_TASK 标示.
— Activity 将其 allowTaskReparenting 特性设定为 “true”.

使我们来融合taskAffinity做下试验:

2.5.1, taskAffinity + FLAG_ACTIVITY_NEW_TASK

设定A和B不一样的taskAffinity, 实行Main -> A -> B -> A -> B -> A, 在其中B运行A应用FLAG_ACTIVITY_NEW_TASK

为何要实行2次B -> A? 大家追随试验結果, 稍候看来.

设定A的taskAffinity为com.anly.aactivity, B默认设置(包名).






B运行A:

startActivity(new Intent(BActivity.this, AActivity.class)
                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));

生命期Log:

img

Task/Back Stack信息内容:

Stack #1 mStackId=10:
    Task id #44
    * TaskRecord{43085768 #44 A=com.anly.aactivity U=0 sz=2}
      numActivities=2 rootWasReset=false userId=0 mTaskType=0 numFullscreen=2 mOnTopOfHome=false
      affinity=com.anly.aactivity
      intent={flg=0x10000000 cmp=com.anly.samples/.activity.AActivity}
      realActivity=com.anly.samples/.activity.AActivity
      Activities=[ActivityRecord{4303fe00 u0 com.anly.samples/.activity.AActivity t44}, ActivityRecord{4324bb10 u0 com.anly.samples/.activity.BActivity t44}]
    Task id #43
    * TaskRecord{426d0a78 #43 A=com.anly.samples U=0 sz=3}
      numActivities=3 rootWasReset=true userId=0 mTaskType=0 numFullscreen=3 mOnTopOfHome=true
      affinity=com.anly.samples
      intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.anly.samples/.MainActivity}
      realActivity=com.anly.samples/.MainActivity
      Activities=[ActivityRecord{4256ae80 u0 com.anly.samples/.MainActivity t43}, 
      ActivityRecord{4372db08 u0 com.anly.samples/.activity.AActivity t43}, 
      ActivityRecord{4273f478 u0 com.anly.samples/.activity.BActivity t43}]

能够见到:
1, Stack #1中有两个Task, #43(affinity=com.anly.samples)和#44(affinity=com.anly.aactivity).
2, 第一轮Main -> A -> B时, 再Task #43中造成了Main,A,B三个Activity案例.
3, 然后B -> A时, A在一个新的Task #44中建立了新的A案例.
4, 随后A -> B, 由于B不用一切主要参数(运行方式, affinity, flag等), B会建立在运行他的Activity也就是A所属的Task.
5, 这时Task #44中就拥有A, B.
6, 再度在B中点一下运行A(带上Intent.FLAG_ACTIVITY_NEW_TASK)时. 并沒有一切反映.

怎么会发生第六点叙述的那样的难题呢?
我了解:
这时B运行A, 由于带上Intent.FLAG_ACTIVITY_NEW_TASK, 且A的taskAffnity为"com.anly.aactivity". 系统软件会在affinity=com.anly.aactivity的Task中找是否有早已存有的A的案例, 发觉Task #44中有. 因此, 想器重A. 殊不知并沒有能消毁B, 让A弹出窗口接受新的Intent.
所以说, 这类状况下, Intent.FLAG_ACTIVITY_NEW_TASK务必融合Intent.FLAG_ACTIVITY_CLEAR_TOP来一起用.

使我们再做一个试验认证下念头.

2.5.1, taskAffinity + FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TOP

设定A和B不一样的taskAffinity, 实行Main -> A -> B -> A -> B -> A, 在其中B运行A应用FLAG_ACTIVITY_NEW_TASK + FLAG_ACTIVITY_CLEAR_TOP

A的affinity還是设成com.anly.aactivity, B默认设置.

B运行A的编码:

startActivity(new Intent(BActivity.this, AActivity.class)
                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP));

生命期Log:

img

Task/Back Stack信息内容:

 Stack #1 mStackId=11:
    Task id #46
    * TaskRecord{4338bc08 #46 A=com.anly.aactivity U=0 sz=1}
      numActivities=1 rootWasReset=false userId=0 mTaskType=0 numFullscreen=1 mOnTopOfHome=false
      affinity=com.anly.aactivity
      intent={flg=0x14000000 cmp=com.anly.samples/.activity.AActivity}
      realActivity=com.anly.samples/.activity.AActivity
      Activities=[ActivityRecord{42d88890 u0 com.anly.samples/.activity.AActivity t46}]

    Task id #45
    * TaskRecord{42eee4d0 #45 A=com.anly.samples U=0 sz=3}
      numActivities=3 rootWasReset=false userId=0 mTaskType=0 numFullscreen=3 mOnTopOfHome=true
      affinity=com.anly.samples
      intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.anly.samples/.MainActivity}
      realActivity=com.anly.samples/.MainActivity
      Activities=[ActivityRecord{42ed9690 u0 com.anly.samples/.MainActivity t45}, ActivityRecord{42e507b8 u0 com.anly.samples/.activity.AActivity t45}, ActivityRecord{42714cd0 u0 com.anly.samples/.activity.BActivity t45}]

能够见到:
果真, 这时第二次B -> A, 有实际效果了, 自动跳转到A了.
殊不知, 大家发觉, 尽管Task #46中只有一个A(B被clear top,消毁了). 殊不知A并并不是器重的, 只是先消毁了解来的A案例, 复建了一个A案例.
参照有关定义Intent.FLAG_ACTIVITY_CLEAR_TOP的第二点表述, 确实是那样, 由于A是默认设置的standard方式, 因此 务必新创建案例.

3, 结果

到此, 大家有关Intent flag和taskAffinity的试验完毕, 大家看来下有关结果:

  1. FLAG_ACTIVITY_NEW_TASK并不象官方网文本文档常说的等同于与singleTask.
  2. 在沒有一切别的flag组成和taskAffinity设定的状况下, 同一运用内FLAG_ACTIVITY_NEW_TASK运行此外一个Activity, 不容易在新的Task中建立案例, 也不会有案例多路复用.
  3. FLAG_ACTIVITY_SINGLE_TOP功效等同于与singleTop, 当Task的top Activity是该Activity时, Activity多路复用.
  4. FLAG_ACTIVITY_CLEAR_TOP会clear top, 换句话说假如Task中有ABCD, 在D中运行B, 会clear掉B之上的CD. CD消毁.
  5. 留意, FLAG_ACTIVITY_CLEAR_TOP并不代表着器重, 默认设置Activity为standard方式得话, 仅仅会clear其top的别的Activity案例, 该Activity并不会器重, 只是也会消毁, 随后建立一个新的该Activity案例来回应此Intent.
  6. 在沒有设定taskAffinity的状况下, 同一运用内FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TOP组成运行此外一个Activity, 功效和独立应用FLAG_ACTIVITY_CLEAR_TOP是一样.(此点相似与第二点)
  7. 如taskAffinity表述的一样, 在大家沒有引进taskAffinity的2.1, 2.2, 2.3, 2.4的有关试验中, 同一个运用中, 应用各种各样Intent flag都并不会建立新的Task.
  8. taskAffinity需融合FLAG_ACTIVITY_NEW_TASK应用, 这时会再新的Task中找寻/建立待运行的Activity案例.
  9. 强烈要求FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TOP融合应用, 独立应用FLAG_ACTIVITY_NEW_TASK很有可能会碰到2.5.1那般的难题.
  10. Intent Flag并不可以替代launchMode, 最少在想器重Activity的状况下, 你需要做的是考虑到launchMode并非Intent Flag.
  11. 本人了解, Intent Flag大量是趋向于用于做Task中的Activity机构. 而launchMode兼具Task机构和Activity案例的器重.
评论
  • 消灭零回复