Android 7.1 ActivityManagerService 屏幕旋转流程分析 (四)
四、Activity的更新(旋转)
sendNewConfiguration()会调用到ActivityManagerService的updateConfiguration()来update Configuration,并根据应用的配置来判断是否要重新lunch应用。
void sendNewConfiguration() {
try {
mActivityManager.updateConfiguration(null);
} catch (RemoteException e) {
}
}
public void updateConfiguration(Configuration values) {
enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
"updateConfiguration()"); synchronized(this) {
if (values == null && mWindowManager != null) {
// sentinel: fetch the current configuration from the window manager
values = mWindowManager.computeNewConfiguration();
} if (mWindowManager != null) {
mProcessList.applyDisplaySize(mWindowManager);
} final long origId = Binder.clearCallingIdentity();
if (values != null) {
Settings.System.clearConfiguration(values);
}
updateConfigurationLocked(values, null, false);
Binder.restoreCallingIdentity(origId);
}
}
先看一下总体时序图,后面详细展开:
1)updateConfigurationLocked()
updateConfigurationLocked()
(1)获取Configuration数据保存在mConfiguration
(2)调用ActivityThread的scheduleConfigurationChanged()
(3)发送ACTION_CONFIGURATION_CHANGED广播
(4)获取当前最上面活动的Activity,调用ActivityStack的ensureActivityConfigurationLocked()函数根据应用配置判断是否要重新luncher应用
private boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
boolean initLocale, boolean persistent, int userId, boolean deferResume) {
int changes = 0; if (mWindowManager != null) {
mWindowManager.deferSurfaceLayout();
}
if (values != null) {
Configuration newConfig = new Configuration(mConfiguration);
changes = newConfig.updateFrom(values);
if (changes != 0) {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,
"Updating configuration to: " + values); EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes); if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
final LocaleList locales = values.getLocales();
int bestLocaleIndex = 0;
if (locales.size() > 1) {
if (mSupportedSystemLocales == null) {
mSupportedSystemLocales =
Resources.getSystem().getAssets().getLocales();
}
bestLocaleIndex = Math.max(0,
locales.getFirstMatchIndex(mSupportedSystemLocales));
}
SystemProperties.set("persist.sys.locale",
locales.get(bestLocaleIndex).toLanguageTag());
LocaleList.setDefault(locales, bestLocaleIndex);
mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
locales.get(bestLocaleIndex)));
} mConfigurationSeq++;
if (mConfigurationSeq <= 0) {
mConfigurationSeq = 1;
}
newConfig.seq = mConfigurationSeq;
mConfiguration = newConfig;
Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + newConfig);
mUsageStatsService.reportConfigurationChange(newConfig,
mUserController.getCurrentUserIdLocked());
//mUsageStatsService.noteStartConfig(newConfig); final Configuration configCopy = new Configuration(mConfiguration); // TODO: If our config changes, should we auto dismiss any currently
// showing dialogs?
mShowDialogs = shouldShowDialogs(newConfig, mInVrMode); AttributeCache ac = AttributeCache.instance();
if (ac != null) {
ac.updateConfiguration(configCopy);
} // Make sure all resources in our process are updated
// right now, so that anyone who is going to retrieve
// resource values after we return will be sure to get
// the new ones. This is especially important during
// boot, where the first config change needs to guarantee
// all resources have that config before following boot
// code is executed.
mSystemThread.applyConfigurationToResources(configCopy); if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {
Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
msg.obj = new Configuration(configCopy);
msg.arg1 = userId;
mHandler.sendMessage(msg);
} final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
if (isDensityChange) {
// Reset the unsupported display size dialog.
mUiHandler.sendEmptyMessage(SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG); killAllBackgroundProcessesExcept(Build.VERSION_CODES.N,
ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
} for (int i=mLruProcesses.size()-1; i>=0; i--) {
ProcessRecord app = mLruProcesses.get(i);
try {
if (app.thread != null) {
if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Sending to proc "
+ app.processName + " new config " + mConfiguration);
app.thread.scheduleConfigurationChanged(configCopy);
}
} catch (Exception e) {
}
}
Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_REPLACE_PENDING
| Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
null, AppOpsManager.OP_NONE, null, false, false,
MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
intent = new Intent(Intent.ACTION_LOCALE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
if (initLocale || !mProcessesReady) {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
}
}
// Update the configuration with WM first and check if any of the stacks need to be
// resized due to the configuration change. If so, resize the stacks now and do any
// relaunches if necessary. This way we don't need to relaunch again below in
// ensureActivityConfigurationLocked().
if (mWindowManager != null) {
final int[] resizedStacks = mWindowManager.setNewConfiguration(mConfiguration);
if (resizedStacks != null) {
for (int stackId : resizedStacks) {
final Rect newBounds = mWindowManager.getBoundsForNewConfiguration(stackId);
mStackSupervisor.resizeStackLocked(
stackId, newBounds, null, null, false, false, deferResume);
}
}
}
} boolean kept = true;
final ActivityStack mainStack = mStackSupervisor.getFocusedStack();
// mainStack is null during startup.
if (mainStack != null) {
if (changes != 0 && starting == null) {
// If the configuration changed, and the caller is not already
// in the process of starting an activity, then find the top
// activity to check if its configuration needs to change.
starting = mainStack.topRunningActivityLocked();
} if (starting != null) {
kept = mainStack.ensureActivityConfigurationLocked(starting, changes, false);
// And we need to make sure at this point that all other activities
// are made visible with the correct configuration.
mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes,
!PRESERVE_WINDOWS);
}
}
if (mWindowManager != null) {
mWindowManager.continueSurfaceLayout();
}
return kept;
}
五、总结
总流程图如下
Android 7.1 ActivityManagerService 屏幕旋转流程分析 (四)的更多相关文章
- Android 7.1 WindowManagerService 屏幕旋转流程分析 (二)
一.概述 从上篇[Android 7.1 屏幕旋转流程分析]知道实际的旋转由WindowManagerService来完成,这里接着上面具体详细展开. 调了三个函数完成了三件事,即首先调用update ...
- Android 7.1 WindowManagerService 屏幕旋转流程分析 (三)
三.屏幕的绘制 performSurfacePlacement()函数来触发window的绘制,这里最大的循环次数是6,当然一般不会到最大次数就会被Scheduled. final void perf ...
- Android 7.1 屏幕旋转流程分析
Android 7.1 屏幕旋转流程分析 一.概述 Android屏幕的旋转在framework主要涉及到三个类,结构如图 PhoneWindowManager:为屏幕的横竖屏转换的管理类. Wi ...
- 【转】如何在 Android 程序中禁止屏幕旋转和重启Activity
原文网址:http://www.cnblogs.com/bluestorm/p/3665890.html 禁止屏幕随手机旋转变化 有时候我们希望让一个程序的界面始终保持在一个方向,不随手机方向旋转而变 ...
- 如何在 Android 程序中禁止屏幕旋转和重启Activity
禁止屏幕随手机旋转变化 有时候我们希望让一个程序的界面始终保持在一个方向,不随手机方向旋转而变化:在AndroidManifest.xml的每一个需要禁止转向的Activity配置中加入android ...
- Android系统分析之运营商显示流程分析之运营商信息的读取流程二
运营商显示流程分析之运营商信息的读取流程 一. SIM卡运营商信息的读取 从前面的 运营商信息的获取和赋值 可以知道SIM卡运营商的赋值最终是在 SIMRecords 中完成的, 而SIM卡信息的相关 ...
- 【Android】11.3 屏幕旋转和场景变换过程中GridView的呈现
分类:C#.Android.VS2015: 创建日期:2016-02-21 一.简介 实际上,对于布局文件中的View来说,大多数情况下,Android都会自动保存这些状态,并不需要我们都去处理它.这 ...
- 屏幕旋转时调用PopupWindow update方法更新位置失效的问题及解决方案
接到一个博友的反馈,在屏幕旋转时调用PopupWindow的update方法失效.使用场景如下:在一个Activity中监听屏幕旋转事件,在Activity主布局文件中有个按钮点击弹出一个Pop ...
- Android 4.4 Kitkat Phone工作流程浅析(六)__InCallActivity显示更新流程
本文来自http://blog.csdn.net/yihongyuelan 转载请务必注明出处 本文代码以MTK平台Android 4.4为分析对象,与Google原生AOSP有些许差异,请读者知悉. ...
随机推荐
- idea—— 模版配置
修改File Header: /** * @author: ${USER} Date: ${DATE} Time: ${TIME} */ 新增Package Header: /* * Copyrigh ...
- Win10 之最新最简单有效安装配置adb
今天在新买的笔记本上安装配置adb,开始觉得挺简单的事,公司win7电脑上有现成的,但实际过程中--没想的那么简单了!好了,废话少说,直接正题. 研究了好一会下,总算搞定,总结如下: 1.下载Andr ...
- pku 1061 青蛙的约会 扩展欧几里得
青蛙的约会Time Limit: 1000MS Memory Limit: 10000KTotal Submissions: 120482 Accepted: 25449Description 两只青 ...
- angularJS简单调用接口,实现数组页面打印
相比较jquery ,angular对这种接口数据处理起来会方便的多.这里举例调用 中国天气网的api接口. 首先肯定要引入angular.js这个不多说 <link rel="sty ...
- php+jQuery+Mysql找回密码----ThinkPHP
最近用ThinkPHP做了一个邮箱找回密码功能,在遭遇了N个bug之后终于做成了,下面分享一下邮箱找回密码功能的实现: 邮箱找回密码实际上就是在用户通过验证之后重置密码的过程,一般开发者会在验证用户信 ...
- cygwin下java报错“找不到或无法加载主类”的故障排除
win7 下安装了java,命令行下可以正常运行,cygwin下报错:找不到或无法加载主类. 经排查发现是cygwin的~/.bash_profile中画蛇添足的配置了$CLASSPATH: JAVA ...
- java.util.ConcurrentModificationException 异常问题详解
环境:JDK 1.8.0_111 在Java开发过程中,使用iterator遍历集合的同时对集合进行修改就会出现java.util.ConcurrentModificationException异常, ...
- 》》3D轮播
* { margin: 0; padding: 0; } .slide { position: absolute; top: calc(50% - 150px); left: calc(50% - 3 ...
- iOS 力学动画生成器UIKit Dynamics 之碰撞效果解说
UIKit Dynamic是iOS7 新增的一组类和方法.可赋予UIView逼真的行为和特征,不须要写动画效果那些繁琐的代码,让开发者可以轻松地改善应用的用户体验.一共同拥有6个可用于定制UIDyna ...
- 关于React组件之间如何优雅地传值的探讨
闲话不多说,开篇撸代码,你可以会看到类似如下的结构: import React, { Component } from 'react'; // 父组件 class Parent extends Com ...