Android 12系统源码_多窗口模式相关方法的调用顺序

前言

从 Android 7.0 开始,Google 推出了一个名为“多窗口模式”的新功能,允许在设备屏幕上同时显示多个应用,多窗口模式允许多个应用同时共享同一屏幕,多窗口模式(Multi Window Supports)目前支持以下三种配置:

  • 分屏模式:让系统可以左右或上下并排显示应用。
    在这里插入图片描述

  • 画中画模式:在应用中用小窗口叠加显示其他应用
    在这里插入图片描述

  • 自由窗口模式:在可移动且可调整大小的单独窗口中显示各个应用。

一、分屏模式的适配

1、我们如何才能让自己的 APP 支持分屏模式呢?

若项目的targetSDKVersion 大于等于24,那么可以在AndroidManifest.xml 文件的Application 或Activity 节点通过设置android:resizeableActivity=[“true” | “false”] 来控制整个 APP 或某个 Activity 是否支持分屏。该属性的默认值是true ,也就是说,如果不设置该属性,在支持分屏的设备上,默认是可以分屏的。

若项目的targetSDKVersion 小于24,那么运行在支持分屏的设备上,默认可以分屏。这时如果需要禁止分屏,需要在AndroidManifest.xml 文件的Application 或Activity 节点设置android:screenOrientation 属性来控制整个 APP 或 某个 Activity 的屏幕方向,从而控制整个 APP 或某个 Activity 禁止分屏。

2、分屏模式的监听

能不能在代码中监听 APP 是否进入分屏模式呢?答案是能。由于 APP 在分屏模式发生改变时会执行onMultiWindowModeChanged 方法,因此我们在 Activity 中重写这个方法就可以实现分屏的监听了。

@Overridepublic void onMultiWindowModeChanged(boolean isInMultiWindowMode) {super.onMultiWindowModeChanged(isInMultiWindowMode);// 判断当前是否为分屏模式if (isInMultiWindowMode) {// 已进入分屏模式} else {// 未进入分屏模式}}

3、分屏模式下的生命周期

  • 进入分屏模式时,Activity 的生命周期:

onPause()- onStop()- onMultiWindowModeChanged()- onDestroy()- onCreate()- onStart()- onResume()- onPause()

  • 退出分屏模式时,Activity 的生命周期:

onStop()- onDestroy()- onCreate()- onStart()- onResume()- onPause()- onMultiWindowModeChanged()- onResume()

可以看出,在进入分屏模式时,Activity 先执行onMultiWindowModeChanged 方法,再重建自己。在退出分屏模式时,Activity 先重建自己,再执行onMultiWindowModeChanged 方法。这样会有一个问题,我们的 APP 进入分屏模式时,在onMultiWindowModeChanged 方法中如果有对 UI 等的操作,经过之后的自动重建就没有效果了。为了防止这种情况,需要在AndroidManifest.xml 的Activity 节点设置以下属性:

android:configChanges=“screenSize|smallestScreenSize|screenLayout|orientation”

设置了这个属性,在进入分屏模式时,Activity 就不会自动重建了。

  • 分屏模式下打开 Activity

如果 APP 在分屏模式下打开 Activity 时,为 Intent 设置了Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT 和Intent.FLAG_ACTIVITY_NEW_TASK 标志,那么新打开的 Activity 将显示在当前 APP 的另一侧。例如下面的代码:

	Intent intent = new Intent(this, NewActivity.class);intent.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT|Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);

二、onMultiWindowModeChanged方法调用回溯

1、结合前面的分析,可以发现onMultiWindowModeChanged是一个很重要的方法,让我们来看下这个方法是什么时候被系统调用的。

base/core/java/android/app/Activity.java

public class Activity extends ContextThemeWrapperimplements LayoutInflater.Factory2,Window.Callback, KeyEvent.Callback,OnCreateContextMenuListener, ComponentCallbacks2,Window.OnWindowDismissedCallback,AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {@Deprecatedpublic void onMultiWindowModeChanged(boolean isInMultiWindowMode) {}public void onMultiWindowModeChanged(boolean isInMultiWindowMode, Configuration newConfig) {onMultiWindowModeChanged(isInMultiWindowMode);}final void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode,Configuration newConfig) {if (DEBUG_LIFECYCLE) Slog.v(TAG,"dispatchMultiWindowModeChanged " + this + ": " + isInMultiWindowMode+ " " + newConfig);mFragments.dispatchMultiWindowModeChanged(isInMultiWindowMode, newConfig);if (mWindow != null) {mWindow.onMultiWindowModeChanged();}mIsInMultiWindowMode = isInMultiWindowMode;onMultiWindowModeChanged(isInMultiWindowMode, newConfig);}
}

onMultiWindowModeChanged方法在Activity中被初次调用,是在dispatchMultiWindowModeChanged方法中。

2、而Activity的dispatchMultiWindowModeChanged方法初次被调用,是在ActivityThread类中。

base/core/java/android/app/ActivityThread.java

public final class ActivityThread extends ClientTransactionHandlerimplements ActivityThreadInternal {private final Map<IBinder, Integer> mLastReportedWindowingMode = Collections.synchronizedMap(new ArrayMap<>());//启动Activity的核心方法private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {...代码省略...Activity activity = null;java.lang.ClassLoader cl = appContext.getClassLoader();//通过反射创建Activity实例对象activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);...代码省略...//创建activity对应的配置信息对象Configuration config = new Configuration(mConfigurationController.getCompatConfiguration());...代码省略...//将窗口模式信息以activity的token为key,存放到Map缓存中mLastReportedWindowingMode.put(activity.getActivityToken(),config.windowConfiguration.getWindowingMode());...代码省略...}//销毁Activity的核心方法void performDestroyActivity(ActivityClientRecord r, boolean finishing,int configChanges, boolean getNonConfigInstance, String reason) {...代码省略...//从map缓存中移除activity对应的窗口模式信息mLastReportedWindowingMode.remove(r.activity.getActivityToken());...代码省略...}/*** 有必要的话将会调用窗口模式发生变化的回调方式*/private void handleWindowingModeChangeIfNeeded(Activity activity,Configuration newConfiguration) {final int newWindowingMode = newConfiguration.windowConfiguration.getWindowingMode();final IBinder token = activity.getActivityToken();final int oldWindowingMode = mLastReportedWindowingMode.getOrDefault(token,WINDOWING_MODE_UNDEFINED);//窗口模式没有发生变化、直接返回if (oldWindowingMode == newWindowingMode) return;// PiP callback is sent before the MW one.if (newWindowingMode == WINDOWING_MODE_PINNED) {//触发画中画模式变化回调方法activity.dispatchPictureInPictureModeChanged(true, newConfiguration);} else if (oldWindowingMode == WINDOWING_MODE_PINNED) {//触发画中画模式变化回调方法activity.dispatchPictureInPictureModeChanged(false, newConfiguration);}final boolean wasInMultiWindowMode = WindowConfiguration.inMultiWindowMode(oldWindowingMode);final boolean nowInMultiWindowMode = WindowConfiguration.inMultiWindowMode(newWindowingMode);if (wasInMultiWindowMode != nowInMultiWindowMode) {//如果旧的窗口模式和新的窗口模式,二者有其一不是多窗口模式,触发多窗口模式变化回调方法activity.dispatchMultiWindowModeChanged(nowInMultiWindowMode, newConfiguration);}//更新Map缓存中Activity对应的窗口模式信息mLastReportedWindowingMode.put(token, newWindowingMode);}
}    
  • ActivityThread在启动Activity的时候,会将activity对应的窗口模式信息缓存到集合中
  • 在handleWindowingModeChangeIfNeeded方法被调用的时候,会回调activity对应的回调方法,并更新activity对应的集合中的窗口模式信息
  • ActivityThread在销毁Activity的时候,会将activity对应的窗口模式信息从集合中移除

3、继续来看下在ActivityThread中handleWindowingModeChangeIfNeeded方法是如何被层层调用的。

public final class ActivityThread extends ClientTransactionHandlerimplements ActivityThreadInternal {private Configuration performActivityConfigurationChanged(Activity activity,Configuration newConfig, Configuration amOverrideConfig, int displayId) {//调用handleWindowingModeChangeIfNeededhandleWindowingModeChangeIfNeeded(activity, newConfig);...代码省略...}private Configuration performConfigurationChangedForActivity(ActivityClientRecord r,Configuration newBaseConfig, int displayId) {r.tmpConfig.setTo(newBaseConfig);if (r.overrideConfig != null) {r.tmpConfig.updateFrom(r.overrideConfig);}//调用performActivityConfigurationChanged方法final Configuration reportedConfig = performActivityConfigurationChanged(r.activity,r.tmpConfig, r.overrideConfig, displayId);freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig));return reportedConfig;}public void handleActivityConfigurationChanged(ActivityClientRecord r,@NonNull Configuration overrideConfig, int displayId) {...代码省略...// Perform updates.r.overrideConfig = overrideConfig;final ViewRootImpl viewRoot = r.activity.mDecor != null? r.activity.mDecor.getViewRootImpl() : null;//调用performConfigurationChangedForActivity方法final Configuration reportedConfig = performConfigurationChangedForActivity(r,mConfigurationController.getCompatConfiguration(),movedToDifferentDisplay ? displayId : r.activity.getDisplayId());// Notify the ViewRootImpl instance about configuration changes. It may have initiated this// update to make sure that resources are updated before updating itself.if (viewRoot != null) {if (movedToDifferentDisplay) {viewRoot.onMovedToDisplay(displayId, reportedConfig);}//调用viewRootImpl的updateConfiguration方法,这里会触发Activity页面View内容的刷新变化viewRoot.updateConfiguration(displayId);}mSomeActivitiesChanged = true;}}

4、结合前面的分析,这里对Activity的和多窗口模式相关方法的调用顺序做个简单梳理。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/572916.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go-js,css,html压缩和混淆(可直接使用)

前提条件: 本地安装nodejs环境然后配置全局环境变量。 运行以下命令安装uglify压缩工具 npm install uglify-js -g 测试是否安装成功 uglifyjs -v 使用方式: 根据不同的操作系统取对应的压缩工具,然后将压缩工具放到项目根目录下,然后执行即可 工具文件: https://gitee.com…

喜讯!聚铭网络荣获《日志分类方法及系统》发明专利

近日&#xff0c;聚铭网络又喜获一项殊荣&#xff0c;其申报的《日志分类方法及系统》发明专利成功获得国家知识产权局的授权&#xff0c;正式荣获国家发明专利证书。 在信息化时代&#xff0c;网络安全问题日益凸显&#xff0c;日志分析作为保障网络安全的重要手段&#xff…

qt-C++笔记之QSpinBox控件

qt-C笔记之QSpinBox控件 code review! 文章目录 qt-C笔记之QSpinBox控件1.运行2.main.cpp3.main.pro4.《Qt6 C开发指南》&#xff1a;4.4 QSpinBox 和QDoubleSpinBox 1.运行 2.main.cpp #include <QApplication> #include <QSpinBox> #include <QPushButton&g…

CUDA安装 Windows版

目录 一、说明 二、安装工具下载 三、CUDA安装 四、cuDNN配置 五、验证安装是否成功 一、说明 windows10 版本安装 CUDA &#xff0c;首先需要下载两个安装包 CUDA toolkitcuDNN 官方教程 CUDA&#xff1a;https://docs.nvidia.com/cuda/cuda-installation-guide-micro…

栈——数据结构

本博客将讲述栈的相关知识 1.栈 1.1栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操 作的一端 称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In Fi…

AI大模型学习——AI领域技术发展

目录 前言 一、AI大模型学习的理论基础 二、AI大模型的训练与优化 三、AI大模型在特定领域的应用 四、AI大模型学习的伦理与社会影响 五、未来发展趋势与挑战 总结 前言 在当前技术环境下&#xff0c;AI大模型学习不仅要求研究者具备深厚的数学基础和编程能力&#xff…

Machine Learning机器学习之K近邻算法(K-Nearest Neighbors,KNN)

目录 前言 背景介绍&#xff1a; 思想&#xff1a; 原理&#xff1a; KNN算法关键问题 一、构建KNN算法 总结&#xff1a; 博主介绍&#xff1a;✌专注于前后端、机器学习、人工智能应用领域开发的优质创作者、秉着互联网精神开源贡献精神&#xff0c;答疑解惑、坚持优质作品共…

PPT没保存怎么恢复?3个方法(更新版)!

“我刚做完一个PPT&#xff0c;正准备保存的时候电脑没电自动关机了&#xff0c;打开电脑后才发现我的PPT没保存。这可怎么办&#xff1f;还有机会恢复吗&#xff1f;” 在日常办公和学习中&#xff0c;PowerPoint是制作演示文稿的重要工具。我们会在各种场景下使用它。但有时候…

备考ICA----Istio实验9---熔断Circuit Breaking 实验

备考ICA----Istio实验9—熔断Circuit Breaking 实验 1. 环境准备 创建httpbin环境 kubectl apply -f istio/samples/httpbin/httpbin.yaml kubectl get svc httpbin2. 创建测试用客户端 kubectl apply -f istio/samples/httpbin/sample-client/fortio-deploy.yaml3. 创建Ht…

Vue.js概述

一、概述 数据驱动的响应式框架&#xff0c;我们只关注Vue对象里面设置的数据即可&#xff0c;数据发生改变时&#xff0c;页面自动重新渲染 最典型的MVVM框架 二、挂载点 什么是“挂载点”&#xff1f;一个标签 作用&#xff1a;被Vue实例接收后&#xff0c;实例中设置的各…

标定系列——预备知识-OpenCV中与标定板处理相关的函数(四)

标定系列——预备知识-OpenCV中与标定板处理相关的函数&#xff08;四&#xff09; 说明记录棋盘格圆网格 说明 记录了OpenCV中与标定板处理相关的函数用法 记录 棋盘格 圆网格

酷开科技依托酷开系统用“平台+产品+场景”塑造全屋智能生活!

杰弗里摩尔的“鸿沟理论”中写道&#xff1a;高科技企业推进产品的早期市场和产品被广泛接受的主流市场之间&#xff0c;存在着一条巨大的“鸿沟”。“鸿沟”&#xff0c;指产品吸引早期接纳者后、赢得更多客户前的那段间歇&#xff0c;以及其中可预知和不可预知的阻碍。多数产…