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有些许差异,请读者知悉. ...
随机推荐
- 自己动手编写IOC框架(三)
刚写博客浏览量第一天就有1000多人次,给了我很大的鼓舞决定熬夜再写一篇.对于前两篇来说无非就是使用dtd验证xml,然后解析xml,和IOC的核心还是差的很远,相信很多小伙伴们都感觉看得不过瘾了,这 ...
- maven jetty struts异常 There is no Action mapped for namespace [/] and action name [] associated with context path
毕业设计中用maven jetty插件调试时,struts出现这个错误,直接http://localhost:8080 无法进入默认主页,但换tomcat就没问题,最后在这篇文章找到答案 http:/ ...
- SpringBoot 整合Ehcache3
SpringBootLean 是对springboot学习与研究项目,是依据实际项目的形式对进行配置与处理,欢迎star与fork. [oschina 地址] http://git.oschina.n ...
- 怎样将word文件转化为Latex文件:word-to-latex-2.56具体解释
首先推荐大家读一读这篇博文:http://blog.csdn.net/ibingow/article/details/8613556 --------------------------------- ...
- B. Simple Game( Codeforces Round #316 (Div. 2) 简单题)
B. Simple Game time limit per test 1 second memory limit per test 256 megabytes input standard input ...
- wps 操作
wps选择视图-->文档结构图
- LintCode-丑数
设计一个算法.找出仅仅含素因子3,5,7 的第 k 大的数. 符合条件的数如:3.5.7,9,15...... 您在真实的面试中是否遇到过这个题? Yes 例子 假设k=4, 返回 9 挑战 要求时间 ...
- Deming管理系列(2)——怎样开发度量能力
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMTI1MDQ1NQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...
- Apache HTTPserver安装后报:无法启动,由于应用程序的并行配置不对-(已解决)
原创作品.出自 "深蓝的blog" 博客.欢迎转载,转载时请务必注明出处.否则有权追究版权法律责任. 深蓝的blog:http://blog.csdn.net/huangyanlo ...
- A. Arrays(Codeforces Round #317 水题)
A. Arrays time limit per test 2 seconds memory limit per test 256 megabytes input standard input out ...