美文网首页
启动模式相关

启动模式相关

作者: 一个追寻者的故事 | 来源:发表于2020-05-28 16:47 被阅读0次

本篇关于Activity启动模式相关的内容。

一、现象及说明

定义三个Activity:MainActivity、FirstActivity、SecondActivity。并按照上述的顺序依次启动这三个页面。manifest文件配置如下:

<activity android:name=".SecondActivity"
    android:launchMode="singleTask"
    android:taskAffinity="com.test"/>
<activity android:name=".FirstActivity" />
<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

当 SecondActivity 页面展示的时候。此时的栈组织情况是什么样的。
adb shell dumpsys activity activities 查看应用栈的使用情况。

➜  ~ adb shell dumpsys activity activities
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):
  Stack #1:
  mResumedActivity=ActivityRecord{b23d936 u0 com.daddyno1.activityintentflagdemo/.SecondActivity t879}
    Task id #879
    ...
    * TaskRecord{a284dad #879 A=com.test U=0 StackId=1 sz=1}
      userId=0 effectiveUid=u0a194 mCallingUid=u0a194 mUserSetupComplete=true mCallingPackage=com.daddyno1.activityintentflagdemo
      affinity=com.test
      intent={flg=0x10000000 cmp=com.daddyno1.activityintentflagdemo/.SecondActivity}
      realActivity=com.daddyno1.activityintentflagdemo/.SecondActivity
      ...
      * Hist #0: ActivityRecord{b23d936 u0 com.daddyno1.activityintentflagdemo/.SecondActivity t879}
          packageName=com.daddyno1.activityintentflagdemo processName=com.daddyno1.activityintentflagdemo
          launchedFromUid=10194 launchedFromPackage=com.daddyno1.activityintentflagdemo userId=0
          app=ProcessRecord{ba1f8e2 22102:com.daddyno1.activityintentflagdemo/u0a194}
          Intent { flg=0x10000000 cmp=com.daddyno1.activityintentflagdemo/.SecondActivity }
          frontOfTask=true task=TaskRecord{a284dad #879 A=com.test U=0 StackId=1 sz=1}
          taskAffinity=com.test
          realActivity=com.daddyno1.activityintentflagdemo/.SecondActivity
          ...
          realComponentName=com.daddyno1.activityintentflagdemo/.SecondActivity

    Task id #878
    ...
    * TaskRecord{e980473 #878 A=com.daddyno1.activityintentflagdemo U=0 StackId=1 sz=2}
      userId=0 effectiveUid=u0a194 mCallingUid=u0a23 mUserSetupComplete=true mCallingPackage=com.miui.home
      affinity=com.daddyno1.activityintentflagdemo
      intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.daddyno1.activityintentflagdemo/.MainActivity}
      realActivity=com.daddyno1.activityintentflagdemo/.MainActivity
      ...
      * Hist #1: ActivityRecord{10ba47f u0 com.daddyno1.activityintentflagdemo/.FirstActivity t878}
          packageName=com.daddyno1.activityintentflagdemo processName=com.daddyno1.activityintentflagdemo
          launchedFromUid=10194 launchedFromPackage=com.daddyno1.activityintentflagdemo userId=0
          app=ProcessRecord{ba1f8e2 22102:com.daddyno1.activityintentflagdemo/u0a194}
          Intent { cmp=com.daddyno1.activityintentflagdemo/.FirstActivity }
          frontOfTask=false task=TaskRecord{e980473 #878 A=com.daddyno1.activityintentflagdemo U=0 StackId=1 sz=2}
          taskAffinity=com.daddyno1.activityintentflagdemo
          realActivity=com.daddyno1.activityintentflagdemo/.FirstActivity
          ...
          realComponentName=com.daddyno1.activityintentflagdemo/.FirstActivity
      * Hist #0: ActivityRecord{c07acc u0 com.daddyno1.activityintentflagdemo/.MainActivity t878}
          packageName=com.daddyno1.activityintentflagdemo processName=com.daddyno1.activityintentflagdemo
          launchedFromUid=10023 launchedFromPackage=com.miui.home userId=0
          app=ProcessRecord{ba1f8e2 22102:com.daddyno1.activityintentflagdemo/u0a194}
          Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.daddyno1.activityintentflagdemo/.MainActivity bnds=[82,1305][250,1473] (has extras) }
          frontOfTask=true task=TaskRecord{e980473 #878 A=com.daddyno1.activityintentflagdemo U=0 StackId=1 sz=2}
          taskAffinity=com.daddyno1.activityintentflagdemo
          realActivity=com.daddyno1.activityintentflagdemo/.MainActivity
          ...
          realComponentName=com.daddyno1.activityintentflagdemo/.MainActivity

    Running activities (most recent first):
      TaskRecord{a284dad #879 A=com.test U=0 StackId=1 sz=1}
        Run #2: ActivityRecord{b23d936 u0 com.daddyno1.activityintentflagdemo/.SecondActivity t879}
      TaskRecord{e980473 #878 A=com.daddyno1.activityintentflagdemo U=0 StackId=1 sz=2}
        Run #1: ActivityRecord{10ba47f u0 com.daddyno1.activityintentflagdemo/.FirstActivity t878}
        Run #0: ActivityRecord{c07acc u0 com.daddyno1.activityintentflagdemo/.MainActivity t878}

    mResumedActivity: ActivityRecord{b23d936 u0 com.daddyno1.activityintentflagdemo/.SecondActivity t879}
    mLastPausedActivity: ActivityRecord{10ba47f u0 com.daddyno1.activityintentflagdemo/.FirstActivity t878}

根据 博文 这一篇的讲解,我们很容易看懂打印的信息,其中 Stack #1 就代表 ActivityStack。

一个 ActivityRecord实例 代表了一个 Activity实例,保存了Activity的所有信息,一个Activity可能会有多个ActivityRecord实例,因为可以被多次启动,跟具体启动模式有关。
一个 TaskRecord 由一个或多个 ActivityRecord 组成。它就是我们通常所说的任务栈,具有后进先出的特点。
一个应用可以有多个任务栈(TaskRecord),ActivityStack就是来管理 TaskRecord的。

这里的栈是概念上的,具体实现上可以有多种多样,源码里使用 ArrayList来实现。

二、管理任务

如果你想进行任务栈的管理,按照自己的想法组织 任务栈 和 页面的关系。你可以借助清单文件<activity>中的属性 以及 传递给 startActivity()的Intent中的Flag来实现上述目的,即可以使用这两种方式定义启动模式。

有些启动模式可以通过清单文件定义,但不能通过Intent标记定义。同样,有些启动模式可以通过Intent标记定义,却不能在清单中定义。

2.1 使用清单文件

standard
默认值。系统在启动该Activity的任务栈中创建Activity的新实例(不是绝对的,比如此时任务栈中的Activity是 singleInstance,此时新建的standard模式的Activity就一定会在其它的任务栈中),并将Intent传递给该实例。Activity可以多次实例化,每个实例可以属于不同任务栈。一个任务栈可以拥有多个实例。

singleTop
如果当前任务栈的栈顶已存在 Activity的实例,则系统会通过调用其onNewIntent方法将 intent 转送给该实例,而不是创建新的实例。Activity 可以多次实例化,每个实例可以属于不同的任务,一个任务可以拥有多个实例。

singleTask
Activity 一次只能有一个实例存在。
1、如果任务栈中已存在该 Activity 的实例(可以是前台任务栈,也可以是后台任务栈。如果是后台的任务栈,会先将整个任务栈转到前台),则系统会调用onNewIntent方法将 intent 转送到现有实例,同时将此Activity实例上边(后入栈)的 Activity全部弹出栈;
2、如果任务栈都不存在该 Activity的实例,如果已存在与 新Activity具有相同 affinity的任务栈,则会将Activity启动到该任务中。如果不存在,则启动一个新的任务栈。

singleInstance
singleTask类似,唯一不同的是:Activity 一次只能有一个实例存在,且该Activity 始终是其任务栈唯一的成员 ,所以由该 Activity启动的任何Activity都会在其他任务栈中打开。

以上的四种启动模式表现正常的前提是:使用默认Intent,没有添加任何Flag

2.2 使用Intent 标记

常用标记:
FLAG_ACTIVITY_SINGLE_TOPFLAG_ACTIVITY_CLEAR_TOPFLAG_ACTIVITY_NEW_TASK
写到这里,真的写不下去了,因为单问一个 Flag 的作用是没有意义的,Flag 和不同启动模式组合在一起,很可能会出现不同效果。我在做Demo测试的时候,想尽可能确定某一个Flag的作用,可能真的没办法,不同搭配有不同的效果,真的没办法说 某一个 Flag的作用。 这篇有点赞 所以一抓一大把讲启动模式的博文也不害羞,真是误人子弟。

举例1:使用 FLAG_ACTIVITY_NEW_TASK 开启一个页面时,如果目标Activity 的taskAffinity 和 当前任务栈的 affinity 相同,则不会新建任务栈,否则创建新的任务栈。如果启动Activity 或者 目标Activity 又跟singleInstance 有关的话,情况又会不一样。

举例2:FLAG_ACTIVITY_CLEAR_TOP
如果单独使用Intent.FLAG_ACTIVITY_CLEAR_TOP,并且没有设置特殊的launchMode,那么,Google官方的示例是:如果ABCD Task中的D采用Intent.FLAG_ACTIVITY_CLEAR_TOP唤起B,这个时候首先会将CD出栈,但是至于B是否会重建,要视情况而定,如果没有设置FLAG_ACTIVITY_SINGLE_TOP,则会将B finish掉,之后创建新的入栈。如果同时设置了FLAG_ACTIVITY_SINGLE_TOP,在当前栈已有的情况下就不会重建,而是直接回调B的onNewIntent。 同样,如果跟 singleInstance 组合的话效果又会不一样。

相关文章

  • 启动模式相关

    本篇关于Activity启动模式相关的内容。 一、现象及说明 定义三个Activity:MainActivity、...

  • Android-收集-持续更新中...

    1、Activity相关: 1、Activity的生命周期 2、Activity的启动模式以及使用场景 启动模式 ...

  • 详解Activity启动模式(一)一些相关的基本概念

    本系列将分三篇文章详细分析Android中Activity启动模式相关的林林总总。 详解Activity启动模式(...

  • Android知识总结

    Android 基础知识相关 activity 的四种启动模式。 activity 启动过程源码解析。 activ...

  • Android启动模式完全解析(下)

    在这篇文章中,我会继续跟大家分享有关于Android中启动模式的相关知识。当然,如果对这个启动模式还不完全了解或者...

  • Android面试题汇总

    Activity相关 Android 基础知识 Activity 的几种启动模式及应用场景 onSaveInsta...

  • Android 知识

    四大组件相关问题Activity四种启动模式Standard、SingleTop、SingleTask、Singl...

  • JVM基础

    参数 启动相关 -client client模式,启动速度比较快,但运行时性能和内存管理效率不高(客户端或测试) ...

  • Activity启动模式

    .有哪几种启动模式? 1.standard(标准启动模式--默认的启动模式)当通过这种模式来启动Activity时...

  • Activity的启动模式

    启动模式 Activity共有四种启动模式,分别是 standard Activity的默认启动模式,每次启动都会...

网友评论

      本文标题:启动模式相关

      本文链接:https://www.haomeiwen.com/subject/pogoahtx.html