• android 12 framework开发第53节-Activity的reLaunch及onConfigurationChanged android源码分析


    hi,同学们大家好!

    1、Configuration应用开发背景

    今天要给大家分享内容就是我们应用开发时候经常会遇到问题,那就是如果系统一些属性变化了,比如语言,横竖屏幕,深色模式等。就会导致系统当前的TopActivity会进行destory后进行重新create情况。如果不想要reCreate Activity那么我们就需要到AndroidManifest中去声明对应的configChange,这个 时候就会让Activity不重新reCreate,即Activity可以不需要重建,但是Activity就会执行对应回调onConfigurationChanged。

    在这里插入图片描述在这里插入图片描述

    2、源码分析Activity的relaunch部分

    这里 我们可以先分析Activity的reLaunch部分即Activity的重建
    那怎么分析呢?
    这里我们就以一些log线索来入手,因为大家知道源码分析的话因为源码太多,你得找到一个合适的切入点,不然确实分析源码基本等于大海捞针。
    寻找切入点:
    这里我们都是知道Activity重新创建会执行onDestroy,我们就在onDestroy进行堆栈拦截看看是哪里调用过来的。
    在这里插入图片描述

    这里很明显我们看出来了,其实是因为应用进程执行了ActivityRelaunchItem这个跨进程通信类,导致执行了对应的handleRelaunchActivityInner,再执行到handleDestroyActivity方法

    那么这里其实 我们重点就应该放到具体服务端是哪里传递了ActivityRelaunchItem。

    这里通过堆栈或者 调试方法 已经不起作用了,因为 是跨进程方式,当然无法追踪。
    那就只能grep方式:
    结果如下
    在这里插入图片描述
    明显我们就知道在ActivityRecord类中
    在这里插入图片描述
    这里调用其实是被 ensureActivityConfiguration调用的

    具体调用栈:
    在这里插入图片描述
    这里就有个疑问了,config变化了难道就一定要进行relaunch么?这个就是我们接下来要分析的
    onConfigurationChanged情况

    3、源码分析非relaunch情况,执行onConfigurationChanged情况

    前面我们已经知道config变化后就2种情况
    1 Activity重启
    2 Activity不进行重启,但要进行AndroidManifest的声明,然后会会回调onConfigurationChanged的方法

    直接重启和Manifest中声明的差异到底在哪里呢?

        boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow,
                boolean ignoreVisibility) {
                //省略
    
            if (shouldRelaunchLocked(changes, mTmpConfig) || forceNewConfig) {
              //省略
                if (mState == PAUSING) {
                    deferRelaunchUntilPaused = true;
                    preserveWindowOnDeferredRelaunch = preserveWindow;
                    return true;
                } else {
          //省略
                    relaunchActivityLocked(preserveWindow);
                    }
                                // All done...  tell the caller we weren't able to keep this activity around.
                return false;
                }
      // Default case: the activity can handle this new configuration, so hand it over.
            // NOTE: We only forward the override configuration as the system level configuration
            // changes is always sent to all processes when they happen so it can just use whatever
            // system level configuration it last got.
            if (displayChanged) {
                scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig);
            } else {
                scheduleConfigurationChanged(newMergedOverrideConfig);
            }
    
            return true;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    这里其实就可以看出来执行scheduleConfigurationChanged其实最后就会导致Activity的onConfigurationChanged的执行
    但是前面shouldRelaunchLocked如果为true,那么就会导致Activity的重启

    故问题关键变成了 shouldRelaunchLocked方法

    /**
         * When assessing a configuration change, decide if the changes flags and the new configurations
         * should cause the Activity to relaunch.
         *
         * @param changes the changes due to the given configuration.
         * @param changesConfig the configuration that was used to calculate the given changes via a
         *        call to getConfigurationChanges.
         */
         //这里就判断十分会导致Activity进行重启,根据changes这个值与manifet中值比较
        private boolean shouldRelaunchLocked(int changes, Configuration changesConfig) {
        //这里 非常关键会获取和activity相关的configChange,其实也就是manifest中声明的那些
            int configChanged = info.getRealConfigChanged();
            boolean onlyVrUiModeChanged = onlyVrUiModeChanged(changes, changesConfig);
    //省略
    
            return (changes&(~configChanged)) != 0;//这里会进行比较,如果不再manifest,则返回true
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    那么来看看info.getRealConfigChanged();具体实现情况:

    public int getRealConfigChanged() {
        return applicationInfo.targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB_MR2
                ? (configChanges | ActivityInfo.CONFIG_SCREEN_SIZE
                        | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE)
                : configChanges;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这里其实就是ActivityInfo类中的configChanges变量
    那么configChanges变量又是哪来的呢?
    在这里插入图片描述

    其实在包解析时候就已经进行了获取

  • 相关阅读:
    架构思考(七)
    drools-加载流程
    【GIT版本控制】--子模块
    【案例】3D地球
    FL Studio21傻瓜式编曲音乐编辑器FL水果软件
    Docker部署Logstash 7.2.0
    软考 系统架构设计师系列知识点之设计模式(2)
    leecode#Excel表列序号#组合两个表
    IDEA新建.xml文件显示为普通文本
    地图选择器datav怎么使用?
  • 原文地址:https://blog.csdn.net/learnframework/article/details/126447172