android:configChanges分析

打印 上一主题 下一主题

主题 1577|帖子 1577|积分 4731

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
android:configChanges



  • 如果要在android源码确认是否是configChanges导致了Activity重启,发起把ActivityThread.DEBUG_CONFIGURATION改为true。
  • Activity无法内部消化此次设置改变时,会调用relaunchActivityLocked方法。不同的是,如果此Activity正在前台,那立即调用;在背景的,则等切到前台后再调用

一、configChanges作用
Android程序在运行时,一些设备的设置可能会改变,如:横竖屏的切换、软键盘的弹出等。这些事件一旦发生,当前活动的Activity会重新启动,其中的过程是:在销毁之前会先调用onSaveInstanceState()方法去保存你应用中的一些数据,然后调用onDestroy()方法,最后调用onCreate()、onStart()、onResume()等方法启动一个新的Activity。
如果想让某些设置在发生改变的时间不重启Activity,需要为Activity添加android:configChanges属性,该属性可以设置多个值,用"|"隔开,例如:“locale|navigation|orientation。设置了android:configChanges属性后,当指定的属性发生变革时,不会去重新启动Activity,而是关照程序去调用Activity的onConfigurationChanged()方法。例如:在进行横竖屏的切换时,会重新启动Activity,而定义了android:configChanges=“orientation|keyboardHidden”,就不会重新启动Activity了,而是去调用onConfigurationChanged()方法。
简言之,在Activity中添加了android:configChanges属性,目的是当android:configChanges所设置的属性值对应的设置属性发生改变时,关照程序调用 onConfigurationChanged()函数,而不会重启Activity。

二、android:configChanges属性可以指定的值


  • mcc(0x0001):国际移动用户识别码所属国家代号改变了-----sim被侦测到了,去更新mcc,mcc是移动用户所属国家代号
  • mnc(0x0002):国际移动用户识别码的移动网号码改变了------sim被侦测到了,去更新mnc,MNC是移动网号码,最多由两位数字组成,用于识别移动用户所归属的移动通信网
  • locale(0x0004):语言改变了-----用户选择了一个新的语言,一般和layoutDirection同时发生
  • touchscreen(0x0008):触摸屏改变了------通常是不会发生的
  • keyboard(0x0010):键盘发生了改变----例如用户用了外部的键盘
  • keyboardHidden(0x0020):键盘的可用性发生了改变
  • navigation(0x0040):导航发生了变革-----通常也不会发生
  • orientation(0x0080):屏幕方向改变了
  • screenLayout(0x0100):屏幕的显示发生了变革------不同的显示被激活
  • uiMode(0x0200): 用户的模式发生了变革
  • screenSize(0x0400):屏幕巨细改变了
  • smallestScreenSize(0x0800):屏幕的物理巨细改变了,如:毗连到一个外部的屏幕上
  • layoutDirection(0x2000):文字誊写朝向变革----一般和locale同时发生
  • fontScale(0x40000000):字体比例发生了变革----选择了不同的全局字体

三、(android-12)frameworks处理处罚流程
  1. <aosp>/frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java
  2. ------
  3. final class ActivityRecord extends WindowToken implements WindowManagerService.AppFreezeListener {
  4.     boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow,
  5.             boolean ignoreVisibility) {
  6.         ......
  7.         // changes类型是int,存储着此次发生的配置改变。举个例子:修改语言后,changes是0x2004。
  8.         // shouldRelaunchLocked用于判断Activify是否可以内部消化掉changes指示的改变 
  9.         if (shouldRelaunchLocked(changes, mTmpConfig) || forceNewConfig) {
  10.             // 重启分支。Activify无法消化此次改变,或强制要求重启(forceNewConfig==true)
  11.             ....
  12.             if (mState == PAUSING) {
  13.                 ...
  14.                 // 如果Activity此时为Pause状态,先设置一个标志位
  15.                 deferRelaunchUntilPaused = true;
  16.                 preserveWindowOnDeferredRelaunch = preserveWindow;
  17.                 return true;
  18.             } else {
  19.                 ...
  20.                 relaunchActivityLocked(preserveWindow);
  21.             }
  22.             // All done...  tell the caller we weren't able to keep this activity around.
  23.             return false;
  24.         }
  25.         ...
  26.     }  
复制代码
  1.     shouldRelaunchLocked用于判断app是否可以内部消化掉changes指定的改变
  2.     
复制代码
  1. private boolean shouldRelaunchLocked(int changes, Configuration changesConfig) {
  2.         int configChanged = info.getRealConfigChanged();
  3.         ...
  4.         // changes存储着此次发生的配置改变。
  5.         // configChanged存储着此个Activity在android:configChanges写的可消化改变。
  6.         return (changes&(~configChanged)) != 0;
  7.     }
  8. }
复制代码
假设用户在“设置”修改了语言,像从英文改为中文,这时android会依次调用各个正运行着的Activity的ensureActivityConfiguration。一个ActivityRecord对象对应一个Activity,成员变量packageName存储着此Activity归属app的Application ID,像com.kos.launcher,成员函数ensureActivityConfiguration也就对应一个Activity的处理处罚过程。
在ensureActivityConfiguration,起首得到此次发生的设置改变值0x2004,值存储在变量changes,然后调用shouldRelaunchLocked,判断是否能内部消化掉这次改变。shouldRelaunchLocked逻辑分两步,第一步调用info.getRealConfigChanged()读出android:configChanges写的那改变值0x00C4,值存储在configChanged,第二步用“(changes&(~configChanged)) != 0”判断此次发生的改变(changes)是否有的不在configChanged。如果有,像示例的0x2004和0x00C4,shouldRelaunchLocked返回true,表示内部没法消化掉此次改变,否则返回false。
如果内部没法消化掉,或调用者要求一定要重启(forceNewConfig==true),那进入重启分支。在这分支,如果此app的生命周期正处于停息状态,像运行在背景,则把deferRelaunchUntilPaused设为true。否则立即调用relaunchActivityLocked。
  1. <aosp>/frameworks/base/services/core/java/com/android/server/wm/TaskFragment.java
  2. ------
  3.     void completePause(boolean resumeNext, ActivityRecord resuming) {
  4.         ...
  5.         if (prev != null) {
  6.             ...
  7.             if (prev.finishing) {
  8.                 ...
  9.             } else if (prev.hasProcess()) {
  10.                 ...
  11.                 if (prev.deferRelaunchUntilPaused) {
  12.                     ...
  13.                     // 这里是关键,如果deferRelaunchUntilPaused为true,调用重启
  14.                     prev.relaunchActivityLocked(prev.preserveWindowOnDeferredRelaunch);
  15.                 }
  16.                 ...
  17.             }
  18.             ...
  19.         }
  20.         ...
  21.     }
复制代码
当Activity从Pause到Resume状态过渡时,像从背景切到前台,一旦发现deferRelaunchUntilPaused是true,会调用relaunchActivityLocked。综上所述:Activity无法内部消化此次设置改变时,会调用relaunchActivityLocked方法。不同的是,如果此Activity正在前台,那立即调用;在背景的,则等切到前台后再调用
relaunchActivityLocked实验着重启流程。内中如何转的就不分析了,终极会调用handleRelaunchActivityInner。
  1. <aosp>/frameworks/base/core/java/android/app/ActivityThread.java
  2. ------
  3.     private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges,
  4.             List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents,
  5.             PendingTransactionActions pendingActions, boolean startsNotResumed,
  6.             Configuration overrideConfig, String reason) {
  7.         ...
  8.         // 销毁此个Activity
  9.         handleDestroyActivity(r, false, configChanges, true, reason);
  10.         ...
  11.         // 启动此个Activity
  12.         handleLaunchActivity(r, pendingActions, customIntent);
  13.     }
复制代码
四、确保设置改变不会导致重启Activity
按上面规则,只要在android:configChanges写上所有可能的设置改变,那无论设置怎么改变都不会导致该Activity重启。那这里为什么还要提这个问题呢?——我不知道如何写android:configChanges才能包罗所有设置改变。
  1. <aosp>/frameworks/base/core/java/android/content/pm/ActivityInfo.java
  2. ------
  3. public static final int CONFIG_ASSETS_PATHS = 0x80000000;
  4. public static final int CONFIG_WINDOW_CONFIGURATION = 0x20000000;
复制代码
在Android-12,不知道如何写android:configChanges才能包罗以上这两个设置。
  1. <aosp>/frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java
  2. ------
  3.     private boolean shouldRelaunchLocked(int changes, Configuration changesConfig) {
  4.         ...
  5.         if (packageName != null && packageName.equals("com.kos.launcher")) {
  6.             return false;
  7.         }
  8.         return (changes&(~configChanged)) != 0;
  9.     }
复制代码
如果android:configChanges无法包罗所有改变,但又要确保设置改变不会导致重启Activity,可以修改shouldRelaunchLocked。发现是白名单中的app时,逼迫返回false,即认为内部能消化掉,不必重启此Activity。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

前进之路

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表