美文网首页
android基础-启动模式(栈内表现)

android基础-启动模式(栈内表现)

作者: Ray206 | 来源:发表于2021-03-18 11:26 被阅读0次

    先看下面的问题

    1. Activity打开A->B(singleInstance)->C,此时一共有多少个栈保存Actvity?在C页面点击返回键,出站顺序是?
    2. Activity打开A(singleTask)->B-C,在C页面打开A,此时栈内还剩下多少个Actvity?

    栈内信息查看

    先通过以下三步查看actvity栈信息
    step1:adb链接测试设备
    setp2:adb shell
    setp3:dumpsys activity activities | sed -En -e '/Stack #/p' -e '/Running activities/,/Run #0/p'
    完成后可以看到打印的luncher栈信息:


    栈内信息.png

    打印各个字符代表的意义?
    TaskRecord.java

    @Override
        public String toString() {
            StringBuilder sb = new StringBuilder(128);
            if (stringName != null) {
                sb.append(stringName);
                sb.append(" U=");
                sb.append(userId);
                sb.append(" StackId=");
                sb.append(getStackId());
                sb.append(" sz=");
                sb.append(mActivities.size());
                sb.append('}');
                return sb.toString();
            }
            sb.append("TaskRecord{");
            sb.append(Integer.toHexString(System.identityHashCode(this)));
            sb.append(" #");
            sb.append(taskId);
            if (affinity != null) {
                sb.append(" A=");
                sb.append(affinity);
            } else if (intent != null) {
                sb.append(" I=");
                sb.append(intent.getComponent().flattenToShortString());
            } else if (affinityIntent != null) {
                sb.append(" aI=");
                sb.append(affinityIntent.getComponent().flattenToShortString());
            } else {
                sb.append(" ??");
            }
            stringName = sb.toString();
            return toString();
        }
    ...
    
      int getStackId() {
            return mStack != null ? mStack.mStackId : INVALID_STACK_ID;
        }
    

    从toString方法可以看出1-7的意义:

    1. 代表当前栈对象内存地址
    2. 当前任务栈ID(这个看出一共有多少个栈)
    3. taskAffinity属性,如果没有配置,默认为app包名
    4. userId
    5. 当前栈id,应该和2的值是一致的,但是和2取值方式不同,通过取值ActivitySatck的mStackId,查看方式ActivitySatck.java源码mStackId,mStackId由final修饰,而且未赋值,所以默认值为0
    6. 栈内activity数量
    7. activity名称,排列信息为栈顶到栈底

    standard模式

    标准启动模式,也是activity的默认启动模式。在这种模式下启动的activity可以被多次实例化,即在同一个任务中可以存在多个activity的实例,每个实例都会处理一个Intent对象。
    启动顺序:A->B->C
    栈信息:


    standard.png

    singleInstance模式

    总是在新的任务中开启,并且这个新的任务中有且只有这一个实例,也就是说被该实例启动的其他activity会自动运行于另一个任务中。当再次启动该activity的实例时,会重用已存在的任务和实例。并且会调用这个实例的onNewIntent()方法,将Intent实例传递到该实例中。和singleTask相同,同一时刻在系统中只会存在一个这样的Activity实例。
    启动顺序:A->B(singleInstance)->C
    栈信息:


    QQ图片20210317164021.png

    此时点击返回键会怎么样?


    ezgif-3-b6c60de7f05a.gif
    返回顺序:C->A->B
    这里就可以回答第一个问题了
    答案(1):一共有两个栈,出栈顺序为C->A->B
    原因:通过栈信息的ID可以看出CA在同一个栈里面(#71),B在一个栈里面(#72)。C在栈顶出完后在点返回键,所以会是A页面,(#71)栈清空后,就显示(#72)栈顶Activity

    如果启动顺序改为:A->B(singleInstance)->C->B(singleInstance)?
    答案:还是两个栈,不过第一个栈为(#72)这里和singleTop类似

    singleTask模式

    谷歌的官方文档上称,如果一个activity的启动模式为singleTask,那么系统总会在一个新任务的最底部(root)启动这个activity,并且被这个activity启动的其他activity会和该activity同时存在于这个新任务中。如果系统中已经存在这样的一个activity则会重用这个实例,并且调用他的onNewIntent()方法。即,这样的一个activity在系统中只会存在一个实例。

    启动顺序:A->B(singleTask)->C

    未指定taskAffinity.png
    指定taskAffinity(com.test).png
    启动顺序:A(singleTask)->B->C->A(singleTask)-返回键
    C跳转到A
    可以看出当C跳转到A时,栈里面只剩下A页面了,通过打印日志B调用了(destroy),C调用了(onStop->onDestroy)
    在点击返回键,app会回到桌面了
    ezgif-3-b6c60de7f05a.gif
    所以启动模式为singleTask的activity,再次打开时,它会把它同栈上面的activity全部弹出销毁,它需要在栈顶

    singleTop模式

    如果一个以singleTop模式启动的activity的实例已经存在于任务桟的桟顶,那么再启动这个Activity时,不会创建新的实例,而是重用位于栈顶的那个实例,并且会调用该实例的onNewIntent()方法将Intent对象传递到这个实例中。举例来说,如果A的启动模式为singleTop,并且A的一个实例已经存在于栈顶中,那么再调用startActivity(new Intent(this,A.class))启动A时,不会再次创建A的实例,而是重用原来的实例,并且调用原来实例的onNewIntent()方法。这是任务桟中还是这有一个A的实例。
    如果以singleTop模式启动的activity的一个实例已经存在与任务桟中,但是不在桟顶,那么它的行为和standard模式相同,也会创建多个实例。
    启动顺序:A->B(singleTop)->C->B(singleTop)->C

    singleTop.png
    总结一句:栈顶复用模式,没在栈顶就创建一个,在栈顶就调用onNewIntent方法

    Task结构

    未命名文件.jpg

    总结

    • ProcessRecord变量activities保存ActivityRecord
    • activities中各个ActivityRecord属于不同的TaskRecord
    • 打开同taskAffinity的activity,会归类到对应TaskRecord(singleInstance模式打开的除外)
    • 新打开的activity,会将对应的TaskRecord排序栈顶
    • singleInstance模式打开的,会新建一个TaskRecord,如果未指定taskAffinity,会使用包名为taskAffinity
    • actvity出栈根据TaskRecord排序,先清空TaskRecord,从TaskRecord栈顶依次出栈

    相关文章

      网友评论

          本文标题:android基础-启动模式(栈内表现)

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