Android starActivity的一些研究

前言

总所周知,Activity有四种启动方式,但很少谈到它还有多种flag帮帮助我们来设定不同的Activity启动方式,这里我们就来踩一踩starActivity的那些坑

任务栈

要了解Activity的启动方式那些事,首先要先了解下任务栈

  • 每次打开应用都会创建一个任务栈,用于存储当前程序的,所有的activity属于一个任务栈。
  • 一个任务栈包含了一个activity的集合, 只有在栈顶的activity才可以跟用户进行交互。
  • 任务栈可以移动到后台, 并且保留了每一个activity的状态。
  • 当把所有的任务栈中所有的activity清除出栈时,任务栈会被销毁,程序退出。

任务栈的缺陷

  • 每开启一次页面都会在任务栈中添加一个Activity,而只有任务栈中的Activity全部清除出栈时,任务栈被销毁,程序才会退出,这样就造成了用,户体验差, 需要点击多次返回才可以把程序退出了。
  • 每开启一次页面都会在任务栈中添加一个Activity还会造成数据冗余, 重复数据太多, 会导致内存溢出的问题(OOM)。

启动模式

启动模式就是为了解决任务栈的缺点而提出来的。

启动模式(launchMode)在多个Activity跳转的过程中扮演着重要的角色,它可以决定是否生成新的Activity实例,是否重用已存在的Activity实例,是否和其他Activity实例公用一个task里。这里简单介绍一下task的概念,task是一个具有栈结构的对象,一个task可以管理多个Activity,启动一个应用,也就创建一个与之对应的task。

  • standard(默认的启动模式,每次开启都会创建一个新的Activity实例)
  • singleTop(栈顶复用模式)
  • singleTask(栈内复用模式)
  • singleInstance(单实例模式)

正文

前三种启动模式相信大家已经很熟悉了,这篇博客相信很多人也看过,但还有很多情况没有提及到,这里就做一下补充

Q:如何如何查看有多少个任务栈和任务栈里有多少个Activity及分别是那些Activity?

使用adb,里面有一条指令可以查看手机中的任务栈

  1. 打开SDK Manager,查看自己的SDK安装目录
  2. SDK安装目录下有一个platform-tools目录,里面就是你adb的安装目录
  3. 打开cmd,cd 到adb目录下,使用adb shell dumpsys activity activities查看任务栈
Android starActivity的一些研究_第1张图片

可以看到在栈ID为80的栈下有4个Activity,栈顶是e985b73这个Activity

singleInstance

Q:singleInstance是开启一个新的任务栈,那么把Activity设定为singleInstance重复启动会是什么情况?

Activity A 是standrad启动模式,Activity B是singleInstance启动模式,A ->B之后,B重复启动B会发生什么?


Android starActivity的一些研究_第2张图片

看来singleInstance启动之后在再启动自己不会创建新的实例

那么继续,再加一个Activity C,standrad启动模式,A->B->C->B 会发生什么事?

Android starActivity的一些研究_第3张图片
Android starActivity的一些研究_第4张图片

gif演示的比较快,不方便看,可以看下这个图


Android starActivity的一些研究_第5张图片

那回退呢?是怎么样的


Android starActivity的一些研究_第6张图片

Android starActivity的一些研究_第7张图片

上面的是A->B-C->B->C启动,如果是A->B->C->B启动的话,回退是这个样子的
Android starActivity的一些研究_第8张图片
Android starActivity的一些研究_第9张图片

因为通过singleInstance启动的Activity会单独的压入一个新的栈中,有且只有一个,又居于栈内复用的特性,所以不会重复创建新的实例

Q:使用singleInstance模式的Activity通过startActivityForResult会发生什么事

Activity A 是standard,Activity B是singleInstance启动模式,从B返回A会弹出一个吐司显示valus


Android starActivity的一些研究_第10张图片

可以看到,singleInstance失效了,它还是在栈77里面,并没有开启新的栈
我试验了多次,发现了如下规则,具体原因是Android底层做的优化,但为什么这样做是不知道的
Android 5.0 之前:
A通过startActivityForResult启动B会在一个新的任务栈中,但onActivityResult是拿不到返回的intent的
Android 5.0之后:
A通过startActivityForResult启动B会在同一个任务栈中,在通过startActivity启动C(C是standard),C会在新的任务栈中,如果还是startActivityForResult,则依旧在同一个任务栈中,所以onActivityResult方法也会正确触发。
这一规则同样适用于singleTask设置不同的taskAffinity来新的栈

Q:A、B在不同的任务栈,通过A启动B后,在从B回到A,如何获取到B的数据?

我们知道正常情况下是可以通过startActivityForResult获取到传回的数据,但是在不同任务栈中会失效,startActivityForResult的源码也有注释

   /**
     * 

Note that this method should only be used with Intent protocols * that are defined to return a result. In other protocols (such as * {@link Intent#ACTION_MAIN} or {@link Intent#ACTION_VIEW}), you may * not get the result when you expect. For example, if the activity you * are launching uses {@link Intent#FLAG_ACTIVITY_NEW_TASK}, it will not * run in your task and thus you will immediately receive a cancel result. */

singleTop和singleTask复用自己的时候都会调用onNewIntent,可以在这里获取到intent来取出从B传回的值

Activity的常用Flag

  • FLAG_ACTIVITY_NEW_TASK
    和“SingleTask”一模一样
  • FLAG_ACTIVITY_SINGLE_TOP
    和“SingleTOP”一模一样
  • FLAG_ACTIVITY_CLEAR_TOP
    当它启动时,在同一个任务栈所以位于它上面的Activity都要出栈,SingleTask默认有此标记效果;
    如果Activity是standrad,那么它连同它之上的Activity都要出栈,并创建一个新的Activity实例放入栈内。
  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
    具有该flag的Activity不会出现在历史Activity的列表中,同excludeFromRecents="true"

你可能感兴趣的:(Android starActivity的一些研究)