马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
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处理处罚流程
- <aosp>/frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java
- ------
- final class ActivityRecord extends WindowToken implements WindowManagerService.AppFreezeListener {
- boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow,
- boolean ignoreVisibility) {
- ......
- // changes类型是int,存储着此次发生的配置改变。举个例子:修改语言后,changes是0x2004。
- // shouldRelaunchLocked用于判断Activify是否可以内部消化掉changes指示的改变
- if (shouldRelaunchLocked(changes, mTmpConfig) || forceNewConfig) {
- // 重启分支。Activify无法消化此次改变,或强制要求重启(forceNewConfig==true)
- ....
- if (mState == PAUSING) {
- ...
- // 如果Activity此时为Pause状态,先设置一个标志位
- 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;
- }
- ...
- }
复制代码- shouldRelaunchLocked用于判断app是否可以内部消化掉changes指定的改变
-
复制代码- private boolean shouldRelaunchLocked(int changes, Configuration changesConfig) {
- int configChanged = info.getRealConfigChanged();
- ...
- // changes存储着此次发生的配置改变。
- // configChanged存储着此个Activity在android:configChanges写的可消化改变。
- return (changes&(~configChanged)) != 0;
- }
- }
复制代码 假设用户在“设置”修改了语言,像从英文改为中文,这时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。
- <aosp>/frameworks/base/services/core/java/com/android/server/wm/TaskFragment.java
- ------
- void completePause(boolean resumeNext, ActivityRecord resuming) {
- ...
- if (prev != null) {
- ...
- if (prev.finishing) {
- ...
- } else if (prev.hasProcess()) {
- ...
- if (prev.deferRelaunchUntilPaused) {
- ...
- // 这里是关键,如果deferRelaunchUntilPaused为true,调用重启
- prev.relaunchActivityLocked(prev.preserveWindowOnDeferredRelaunch);
- }
- ...
- }
- ...
- }
- ...
- }
复制代码 当Activity从Pause到Resume状态过渡时,像从背景切到前台,一旦发现deferRelaunchUntilPaused是true,会调用relaunchActivityLocked。综上所述:Activity无法内部消化此次设置改变时,会调用relaunchActivityLocked方法。不同的是,如果此Activity正在前台,那立即调用;在背景的,则等切到前台后再调用。
relaunchActivityLocked实验着重启流程。内中如何转的就不分析了,终极会调用handleRelaunchActivityInner。
- <aosp>/frameworks/base/core/java/android/app/ActivityThread.java
- ------
- private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges,
- List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents,
- PendingTransactionActions pendingActions, boolean startsNotResumed,
- Configuration overrideConfig, String reason) {
- ...
- // 销毁此个Activity
- handleDestroyActivity(r, false, configChanges, true, reason);
- ...
- // 启动此个Activity
- handleLaunchActivity(r, pendingActions, customIntent);
- }
复制代码 四、确保设置改变不会导致重启Activity
按上面规则,只要在android:configChanges写上所有可能的设置改变,那无论设置怎么改变都不会导致该Activity重启。那这里为什么还要提这个问题呢?——我不知道如何写android:configChanges才能包罗所有设置改变。
- <aosp>/frameworks/base/core/java/android/content/pm/ActivityInfo.java
- ------
- public static final int CONFIG_ASSETS_PATHS = 0x80000000;
- public static final int CONFIG_WINDOW_CONFIGURATION = 0x20000000;
复制代码 在Android-12,不知道如何写android:configChanges才能包罗以上这两个设置。
- <aosp>/frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.java
- ------
- private boolean shouldRelaunchLocked(int changes, Configuration changesConfig) {
- ...
- if (packageName != null && packageName.equals("com.kos.launcher")) {
- return false;
- }
- return (changes&(~configChanged)) != 0;
- }
复制代码 如果android:configChanges无法包罗所有改变,但又要确保设置改变不会导致重启Activity,可以修改shouldRelaunchLocked。发现是白名单中的app时,逼迫返回false,即认为内部能消化掉,不必重启此Activity。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
|