Android 12系统源码_窗口管理(八)WindowConfiguration的作用

前言

在Android系统中WindowConfiguration这个类用于管理与窗口相关的设置,该类存储了当前窗口的显示区域、屏幕的旋转方向、窗口模式等参数,应用程序通过该类提供的信息可以更好的适配不同的屏幕布局和窗口环境,以提高用户体验。

一、类定义

frameworks/base/core/java/android/app/WindowConfiguration.java

public class WindowConfiguration implements Parcelable, Comparable<WindowConfiguration> {//包含装饰窗口在内的窗口显示区域private Rect mBounds = new Rect();//不包含装饰窗口在内的窗口显示区域private Rect mAppBounds;//可显示的最大区域private final Rect mMaxBounds = new Rect();//当前屏幕设备的旋转角度private int mRotation = ROTATION_UNDEFINED;//当前窗口模式private @WindowingMode int mWindowingMode;//屏幕窗口模式private @WindowingMode int mDisplayWindowingMode;/** @hide */@IntDef(prefix = { "WINDOWING_MODE_" }, value = {WINDOWING_MODE_UNDEFINED,//未定义WINDOWING_MODE_FULLSCREEN,//全屏WINDOWING_MODE_MULTI_WINDOW,//多窗口WINDOWING_MODE_PINNED,WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,WINDOWING_MODE_FREEFORM,})public @interface WindowingMode {}//Activity的类型private @ActivityType int mActivityType;/** @hide */@IntDef(prefix = { "ACTIVITY_TYPE_" }, value = {ACTIVITY_TYPE_UNDEFINED,ACTIVITY_TYPE_STANDARD,ACTIVITY_TYPE_HOME,ACTIVITY_TYPE_RECENTS,ACTIVITY_TYPE_ASSISTANT,ACTIVITY_TYPE_DREAM,})public @interface ActivityType {}//窗口是否总是位于最上层private @AlwaysOnTop int mAlwaysOnTop;/** @hide */@IntDef(prefix = { "ALWAYS_ON_TOP_" }, value = {ALWAYS_ON_TOP_UNDEFINED,ALWAYS_ON_TOP_ON,ALWAYS_ON_TOP_OFF,})private @interface AlwaysOnTop {}
}

在这里插入图片描述
该类主要有以下几个关键属性:

  • mBounds: 屏幕尺寸
  • mAppBounds:不包含装饰窗口在内的窗口显示区域**(根据源码发现mAppBounds只排除了导航栏这个装饰窗口所在的区域,状态栏和输入法等装饰窗口所在的区域是被包含在内的)**
  • mMaxBounds:窗口可显示的最大区域
  • mRotation:当前屏幕设备的旋转角度
  • mWindowingMode:当前窗口的窗口模式,例如未定义、全屏、分屏、多窗口等
  • ActivityType:页面类型,例如未定义、标准、首页、最近任务等
  • mAlwaysOnTop:窗口是否总是位于最上层

二、WindowConfiguration的属性设置

2.1 Configuration类

WindowConfiguration在Android系统中基本都是作为Configuration类的内部属性出现的。

frameworks/base/core/java/android/content/res/Configuration.java

public final class Configuration implements Parcelable, Comparable<Configuration> {public final WindowConfiguration windowConfiguration = new WindowConfiguration();}

2.2 计算当前屏幕尺寸和当前窗口可显示的最大区域

这里我们主要是结合WMS模块的相关代码来分析WindowConfiguration的各个属性的来源;系统主要是通过DisplayContent的computeScreenConfiguration方法来计算当前屏幕对应的窗口配置信息的。

frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java

class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowContainer>implements WindowManagerPolicy.DisplayContentInfo {DisplayInfo computeScreenConfiguration(Configuration outConfig, int rotation) {final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);//屏幕旋转角度final int dw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;//屏幕宽度final int dh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;//屏幕高度//注释1,对屏幕的实际宽高进行存储outConfig.windowConfiguration.setMaxBounds(0, 0, dw, dh);outConfig.windowConfiguration.setBounds(outConfig.windowConfiguration.getMaxBounds());final int uiMode = getConfiguration().uiMode;//UI模式final DisplayCutout displayCutout = calculateDisplayCutoutForRotation(rotation).getDisplayCutout();//计算屏幕的显示切口//注释2,调用computeScreenAppConfiguration方法computeScreenAppConfiguration(outConfig, dw, dh, rotation, uiMode, displayCutout);...代码省略...   }}

在注释1处根据屏幕旋转角度和基本显示尺寸,确定屏幕的实际宽高,并将其存储到WindowConfiguration的mMaxBounds属性和mBounds属性中。
在注释2处将屏幕实际宽度、高度、旋转角度、UI模式、屏幕显示切口作为参数,调用computeScreenAppConfiguration方法计算当前窗口可显示的安全区域。

2.3 计算当前窗口可显示的安全区域

class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowContainer>implements WindowManagerPolicy.DisplayContentInfo {private final DisplayPolicy mDisplayPolicy;private void computeScreenAppConfiguration(Configuration outConfig, int dw, int dh,int rotation, int uiMode, DisplayCutout displayCutout) {//注释1,获取不包含系统装饰窗口的可显示屏幕区域final Point appSize = mDisplayPolicy.getNonDecorDisplaySize(dw, dh, rotation, uiMode, displayCutout);//注释2,获取不包含系统装饰窗口的可显示屏幕边界mDisplayPolicy.getNonDecorInsetsLw(rotation, dw, dh, displayCutout, mTmpRect);final int leftInset = mTmpRect.left;final int topInset = mTmpRect.top;//注释3,存储应用的可显示的安全区域outConfig.windowConfiguration.setAppBounds(leftInset /* left */, topInset /* top */,leftInset + appSize.x /* right */, topInset + appSize.y /* bottom */);//存储屏幕旋转角度outConfig.windowConfiguration.setRotation(rotation);//存储屏幕是横屏还是竖屏outConfig.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;//屏幕像素密度final float density = mDisplayMetrics.density;final Point configSize = mDisplayPolicy.getConfigDisplaySize(dw, dh, rotation, uiMode,displayCutout);outConfig.screenWidthDp = (int) (configSize.x / density);outConfig.screenHeightDp = (int) (configSize.y / density);outConfig.compatScreenWidthDp = (int) (outConfig.screenWidthDp / mCompatibleScreenScale);outConfig.compatScreenHeightDp = (int) (outConfig.screenHeightDp / mCompatibleScreenScale);final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);outConfig.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, uiMode, dw,dh);}}

frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.java

public class DisplayPolicy {Point getNonDecorDisplaySize(int fullWidth, int fullHeight, int rotation, int uiMode,DisplayCutout displayCutout) {int width = fullWidth;int height = fullHeight;int navBarReducedHeight = 0;int navBarReducedWidth = 0;//获取导航栏的位置final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);if (hasNavigationBar()) {if (navBarPosition == NAV_BAR_BOTTOM) {navBarReducedHeight = getNavigationBarHeight(rotation, uiMode);} else if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) {navBarReducedWidth = getNavigationBarWidth(rotation, uiMode, navBarPosition);}}if (mExtraNavBarAlt != null) {final LayoutParams altBarParams = mExtraNavBarAlt.getLayoutingAttrs(rotation);final int altBarPosition = getAltBarPosition(altBarParams);if (altBarPosition == ALT_BAR_BOTTOM || altBarPosition == ALT_BAR_TOP) {if (altBarPosition == navBarPosition) {navBarReducedHeight = Math.max(navBarReducedHeight,getAltBarHeight(ITYPE_EXTRA_NAVIGATION_BAR));} else {navBarReducedHeight += getAltBarHeight(ITYPE_EXTRA_NAVIGATION_BAR);}} else if (altBarPosition == ALT_BAR_LEFT || altBarPosition == ALT_BAR_RIGHT) {if (altBarPosition == navBarPosition) {navBarReducedWidth = Math.max(navBarReducedWidth,getAltBarWidth(ITYPE_EXTRA_NAVIGATION_BAR));} else {navBarReducedWidth += getAltBarWidth(ITYPE_EXTRA_NAVIGATION_BAR);}}}//当前窗口的安全显示区域为屏幕宽高减去导航栏所在的区域height -= navBarReducedHeight;width -= navBarReducedWidth;//如果屏幕显示切口对象不为空,还要减去该区域if (displayCutout != null) {height -= displayCutout.getSafeInsetTop() + displayCutout.getSafeInsetBottom();width -= displayCutout.getSafeInsetLeft() + displayCutout.getSafeInsetRight();}return new Point(width, height);}public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,DisplayCutout displayCutout, Rect outInsets) {outInsets.setEmpty();//系统存在导航栏if (hasNavigationBar()) {final int uiMode = mService.mPolicy.getUiMode();//获取导航栏的位置,最终返回的边界区域要去掉导航栏所在的区域int position = navigationBarPosition(displayWidth, displayHeight, displayRotation);if (position == NAV_BAR_BOTTOM) {outInsets.bottom = getNavigationBarHeight(displayRotation, uiMode);} else if (position == NAV_BAR_RIGHT) {outInsets.right = getNavigationBarWidth(displayRotation, uiMode, position);} else if (position == NAV_BAR_LEFT) {outInsets.left = getNavigationBarWidth(displayRotation, uiMode, position);}}if (mExtraNavBarAlt != null) {final LayoutParams extraNavLayoutParams =mExtraNavBarAlt.getLayoutingAttrs(displayRotation);final int position = getAltBarPosition(extraNavLayoutParams);if (position == ALT_BAR_BOTTOM) {outInsets.bottom = Math.max(outInsets.bottom,getAltBarHeight(ITYPE_EXTRA_NAVIGATION_BAR));} else if (position == ALT_BAR_RIGHT) {outInsets.right = Math.max(outInsets.right,getAltBarWidth(ITYPE_EXTRA_NAVIGATION_BAR));} else if (position == ALT_BAR_LEFT) {outInsets.left = Math.max(outInsets.left,getAltBarWidth(ITYPE_EXTRA_NAVIGATION_BAR));} else if (position == ALT_BAR_TOP) {outInsets.top = Math.max(outInsets.top,getAltBarHeight(ITYPE_EXTRA_NAVIGATION_BAR));}}//如果屏幕显示切口对象不为空,还要减去该区域if (displayCutout != null) {outInsets.left += displayCutout.getSafeInsetLeft();outInsets.top += displayCutout.getSafeInsetTop();outInsets.right += displayCutout.getSafeInsetRight();outInsets.bottom += displayCutout.getSafeInsetBottom();}}}

在注释1处调用DisplayPolicy的getNonDecorDisplaySize方法,获取不包含系统装饰窗口的可显示屏幕区域,将结果存放在类型为Point的appSize对象中,结合getNonDecorDisplaySize方法源码可以发现该方法只是去除了导航栏窗口所在的区域,另外如果有屏幕显示切口区域,还会去除屏幕显示切口区域。
在注释2处调用DisplayPolicy的getNonDecorInsetsLw方法,获取不包含系统装饰窗口的可显示屏幕边界,将结果存放在类型为Rect的mTmpRect对象中,结合getNonDecorInsetsLw方法源码可以发现该方法只是去除了导航栏窗口所在的区域,另外如果有屏幕显示切口区域,还会去除屏幕显示切口区域。
在注释3处会结合appSize和mTmpRect,将当前窗口可显示的安全区域存储到Configuration的WindowConfiguration中。

三、WindowConfiguration的作用

WindowConfiguration的toString方法包含了此类的所有关键信息。

public class WindowConfiguration implements Parcelable, Comparable<WindowConfiguration> {@Overridepublic String toString() {return "{ mBounds=" + mBounds+ " mAppBounds=" + mAppBounds+ " mMaxBounds=" + mMaxBounds+ " mWindowingMode=" + windowingModeToString(mWindowingMode)+ " mDisplayWindowingMode=" + windowingModeToString(mDisplayWindowingMode)+ " mActivityType=" + activityTypeToString(mActivityType)+ " mAlwaysOnTop=" + alwaysOnTopToString(mAlwaysOnTop)+ " mRotation=" + (mRotation == ROTATION_UNDEFINED? "undefined" : rotationToString(mRotation))+ "}";}public static String windowingModeToString(@WindowingMode int windowingMode) {switch (windowingMode) {case WINDOWING_MODE_UNDEFINED: return "undefined";case WINDOWING_MODE_FULLSCREEN: return "fullscreen";case WINDOWING_MODE_MULTI_WINDOW: return "multi-window";case WINDOWING_MODE_PINNED: return "pinned";case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: return "split-screen-primary";case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY: return "split-screen-secondary";case WINDOWING_MODE_FREEFORM: return "freeform";}return String.valueOf(windowingMode);}public static String activityTypeToString(@ActivityType int applicationType) {switch (applicationType) {case ACTIVITY_TYPE_UNDEFINED: return "undefined";case ACTIVITY_TYPE_STANDARD: return "standard";case ACTIVITY_TYPE_HOME: return "home";case ACTIVITY_TYPE_RECENTS: return "recents";case ACTIVITY_TYPE_ASSISTANT: return "assistant";case ACTIVITY_TYPE_DREAM: return "dream";}return String.valueOf(applicationType);}public static String alwaysOnTopToString(@AlwaysOnTop int alwaysOnTop) {switch (alwaysOnTop) {case ALWAYS_ON_TOP_UNDEFINED: return "undefined";case ALWAYS_ON_TOP_ON: return "on";case ALWAYS_ON_TOP_OFF: return "off";}return String.valueOf(alwaysOnTop);}
}
//frameworks/base/core/java/android/view/Surface.java
public class Surface implements Parcelable {public static String rotationToString(int rotation) {switch (rotation) {case Surface.ROTATION_0: {return "ROTATION_0";}case Surface.ROTATION_90: {return "ROTATION_90";}case Surface.ROTATION_180: {return "ROTATION_180";}case Surface.ROTATION_270: {return "ROTATION_270";}default: {return Integer.toString(rotation);}}}
}

当我们调用如下方法

 Log.i(TAG, "getWindowInfo: config = " + getResources().getConfiguration());

或者通过dumpsys window windows导出当前所有窗口的堆栈信息,都可以得到和Configuration类相关的以下信息:

config={1.0 ?mcc?mnc [zh_CN] ldltr sw360dp w764dp h324dp 480dpi nrml long land finger -keyb/h/h -nav/h winConfig={ mBounds=Rect(0, 0 - 2400, 1080) mAppBounds=Rect(107, 0 - 2400, 1080) mMaxBounds=Rect(0, 0 - 2400, 1080) mDisplayRotation=ROTATION_90 mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=standard mAlwaysOnTop=undefined mRotation=ROTATION_90} s.2 fontWeightAdjustment=0mThemeChanged= 0, mThemeChangedFlags= 0, mFlipFont= 0, mAccessibleChanged= -1, mUxIconConfig= 3468921665126662176, mMaterialColor= 0, mUserId= 0, mFontUserId= 0, mFontVariationSettings= 226, mFoldingAngle = -1.0, mIconPackName= , mDarkModeBackgroundMaxL= 0.0, mDarkModeDialogBgMaxL= 27.0, mDarkModeForegroundMinL= 100.0, mOplusConfigType= 1, mOplusChangedConfigs= 0, OpSans= 0, mBurmeseFontFlag= 2, mFlag= 0, mPuttDisplayFlag= -1}

这里我们重点关注和WindowConfiguration相关的信息:

winConfig={ mBounds=Rect(0, 0 - 2400, 1080) mAppBounds=Rect(107, 0 - 2400, 1080) mMaxBounds=Rect(0, 0 - 2400, 1080) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=standard mAlwaysOnTop=undefined mRotation=ROTATION_90}
  • mBounds=Rect(0, 0 - 2400, 1080):屏幕尺寸
  • mAppBounds=Rect(107, 0 - 2400, 1080):窗口可显示的安全区域,此属性会影响应用具体加载那个layout下面的布局文件,系统会优先选择尺寸最接近2293x1080的布局文件。
  • mMaxBounds=Rect(0, 0 - 2400, 1080):窗口可显示的最大区域
  • mWindowingMode=fullscreen:窗口为全屏模式
  • mDisplayWindowingMode=fullscreen:屏幕设备窗口为全屏模式
  • mActivityType=standard:页面类型未定义
  • mAlwaysOnTop=undefined:窗口悬浮模式未定义
  • mRotation=ROTATION_90:屏幕设备的旋转角度为90度

借助这些属性,开发者能够更好地适配不同的设备配置和屏幕状态,确保应用在不同环境下的一致性和优化。

四、修改WindowConfiguration的配置信息,刷新窗口UI视图

4.1 通过adb 修改屏幕旋转角度

我们可以通过以下指令获取当前屏幕的旋转角度

adb shell settings get system user_rotation #0:自然方向(竖屏)1:右旋转 90 度(横屏)2:倒转 180 度(反向竖屏)3:左旋转 270 (横屏)

还可以通过如下配置修改当前屏幕的旋转角度

adb shell settings put system user_rotation <value>

4.2 实现原理

当我们修改system数据库中的user_rotation字段的时候,会触发以下代码逻辑。

frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java

//frameworks/base/core/java/android/provider/Settings.java
public final class Settings {public static final String USER_ROTATION = "user_rotation";
}
public class DisplayRotation {private final WindowManagerService mService;private class SettingsObserver extends ContentObserver {SettingsObserver(Handler handler) {super(handler);}void observe() {final ContentResolver resolver = mContext.getContentResolver();...代码省略...//注释1,监听system数据库user_rotation字段的变化resolver.registerContentObserver(Settings.System.getUriFor(Settings.System.USER_ROTATION), false, this,UserHandle.USER_ALL);updateSettings();}@Overridepublic void onChange(boolean selfChange) {//注释2,判断设置是否发生了变化,如果发生了变化调用WMS的updateRotation方法if (updateSettings()) {mService.updateRotation(true /* alwaysSendConfiguration */,false /* forceRelayout */);}}}private boolean updateSettings() {final ContentResolver resolver = mContext.getContentResolver();boolean shouldUpdateRotation = false;synchronized (mLock) {...代码省略...//获取当前屏的旋转角度final int userRotation = Settings.System.getIntForUser(resolver,Settings.System.USER_ROTATION, Surface.ROTATION_0,UserHandle.USER_CURRENT);if (mUserRotation != userRotation) {mUserRotation = userRotation;shouldUpdateRotation = true;}...代码省略...return shouldUpdateRotation;}}

在注释1处DisplayRotation类会监听system数据库的user_rotation字段的变化,当该字段发生变化的时候,会在注释2处调用WindowManagerServices的updateRotation方法来通知窗口当前屏幕的旋转角度发生了变化。

4.3 WindowManagerService的updateRotation方法

frameworksbase/services/core/java/com/android/server/wm/WindowManagerService.java

public class WindowManagerService extends IWindowManager.Stubimplements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {//更新当前的屏幕的旋转角度@Overridepublic void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) {updateRotationUnchecked(alwaysSendConfiguration, forceRelayout);}private void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {...代码省略...try {synchronized (mGlobalLock) {boolean layoutNeeded = false;final int displayCount = mRoot.mChildren.size();for (int i = 0; i < displayCount; ++i) {final DisplayContent displayContent = mRoot.mChildren.get(i);Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation: display");final boolean rotationChanged = displayContent.updateRotationUnchecked();Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);if (rotationChanged) {mAtmService.getTaskChangeNotificationController().notifyOnActivityRotation(displayContent.mDisplayId);}if (!rotationChanged || forceRelayout) {displayContent.setLayoutNeeded();layoutNeeded = true;}if (rotationChanged || alwaysSendConfiguration) {//更新屏幕设备的配置信息displayContent.sendNewConfiguration();}}...代码省略...}} finally {Binder.restoreCallingIdentity(origId);Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);}} }    
class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.DisplayContentInfo {void setLayoutNeeded() {mLayoutNeeded = true;}void sendNewConfiguration() {if (!isReady()) {return;}if (mDisplayRotation.isWaitingForRemoteRotation()) {return;}//更新屏幕设备的配置信息final boolean configUpdated = updateDisplayOverrideConfigurationLocked();if (configUpdated) {return;}}boolean updateDisplayOverrideConfigurationLocked() {final RecentsAnimationController recentsAnimationController =mWmService.getRecentsAnimationController();if (recentsAnimationController != null) {recentsAnimationController.cancelAnimationForDisplayChange();}Configuration values = new Configuration();computeScreenConfiguration(values);mAtmService.mH.sendMessage(PooledLambda.obtainMessage(ActivityManagerInternal::updateOomLevelsForDisplay, mAtmService.mAmInternal,mDisplayId));Settings.System.clearConfiguration(values);updateDisplayOverrideConfigurationLocked(values, null /* starting */,false /* deferResume */, mAtmService.mTmpUpdateConfigurationResult);return mAtmService.mTmpUpdateConfigurationResult.changes != 0;}}

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

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

相关文章

水库监测布点的核心要求与策略解析

在水库的安全监测体系中&#xff0c;监测点位的合理布置是确保数据准确性和监测效果的关键。涵盖了常规监测、形变监控、应力分析以及地质灾害预警等多个维度&#xff0c;其中&#xff0c;形变监测尤为关键&#xff0c;直接关乎大坝的安全状态。形变监测通过测斜仪相关的传感器…

Qt开发技巧(四)“tr“使用,时间类使用,Qt容器取值,类对象的删除,QPainter画家类,QString的转换,用好 QVariant类型

继续讲一些Qt技巧操作 1.非必要不用"tr" 如果程序运行场景确定是某一固定语言&#xff0c;就不需要用tr,"tr"之主要针对多语种翻译的&#xff0c;因为tr的本意是包含英文&#xff0c;然后翻译到其他语言比如中文&#xff0c;不要滥用tr&#xff0c;如果没有…

【渗透测试】——DVWA靶场搭建

&#x1f4d6; 前言&#xff1a;DVWA&#xff08;Damn Vulnerable Web Application&#xff09;是一个用于安全漏洞测试的 PHP/MySQL 网络应用&#xff0c;旨在为安全专业人士提供一个合法的环境&#xff0c;以测试他们的技能和工具&#xff0c;同时帮助 Web 开发者更好地理解 …

大棚分割数据集,40765对影像,16.9g数据量,0.8米高分二,纯手工标注(arcgis标注)的大规模农业大棚分割数据集。

数据集名称&#xff1a; &#xff09;“Greenhouse Segmentation Dataset (GSD)” 数据集规模&#xff1a; 包含40,765对用于大棚分割的影像数据&#xff0c;每对影像包括一张原始图像和相应的分割标签图。 数据量&#xff1a; 总数据量约为16.9GB&#xff0c;适合存储在现…

【数据仓库】数据仓库常见的数据模型——维度模型

文章部分图参考自&#xff1a;多维数据模型各种类型&#xff08;星型、雪花、星座、交叉连接&#xff09; - 知乎 (zhihu.com) 文章部分文字canla一篇文章搞懂数据仓库&#xff1a;四种常见数据模型&#xff08;维度模型、范式模型等&#xff09;-腾讯云开发者社区-腾讯云 (ten…

第14章 存储器的保护

第14章 存储器的保护 该章主要介绍了GDT、代码段、数据段、栈段等的访问保护机制。 存储器的保护功能可以禁止程序的非法内存访问。利用存储器的保护功能&#xff0c;也可以实现一些有价值的功能&#xff0c;比如虚拟内存管理。 代码清单14-1 该章节的代码主要实现的功能就…

详解Transformer位置编码Positional Encoding

提到 Transformer&#xff0c;大家就会联想到位置编码、注意力机制、编码器-解码器结构&#xff0c;本系列教程将探索 Transformer 的不同模块在故障诊断等信号分类任务中扮演什么样角色&#xff0c;到底哪些模块起作用&#xff1f; 前言 本期基于凯斯西储大学&#xff08;CWR…

Qt QSerialPort数据发送和接收DataComm

文章目录 Qt QSerialPort数据发送和接收DataComm2.添加 Qt Serial Port 模块3.实例源码 Qt QSerialPort数据发送和接收DataComm Qt 框架的Qt Serial Port 模块提供了访问串口的基本功能&#xff0c;包括串口通信参数配置和数据读写&#xff0c;使用 Qt Serial Port 模块就可以…

C# WinForm 中 DataGridView 实现单元格cell 能进编辑状态但是不能修改单元格的效果

在Windows Forms&#xff08;WinForms&#xff09;开发中&#xff0c;DataGridView 控件是一个功能强大的组件&#xff0c; 用于显示和管理表格数据。无论是展示大量数据&#xff0c;还是实现交互式的数据操作&#xff0c; DataGridView 都能提供多样的功能支持&#xff0c;比如…

C++设计模式(更新中)

文章目录 1、创建型模式1.1 简单工厂&#xff08;Simple Factory&#xff09;&#xff08;1&#xff09;示例&#xff08;2&#xff09;总结 1.2 工厂方法&#xff08;Factory Method&#xff09;&#xff08;1&#xff09;示例&#xff08;2&#xff09;总结 1.3 抽象工厂&…

Sass实现文字两侧横线及Sass常用方案

Sass常用方案及Sass实现文字两侧横线 1.Sass实现文字两侧横线2.用Sass简化媒体查询3.使用继承占位符实现样式复用4.Sass 模块化5.lighten 和 darken 自我记录 1.Sass实现文字两侧横线 mixin 的基本作用&#xff1a; 代码复用&#xff1a;把常用的样式封装在一起&#xff0c;…

SpringCloud-04 OpenFeign服务调用与负载均衡

OpenFeign是一个声明式、模板化的HTTP客户端&#xff0c;它简化了在Java应用程序中调用RESTful API的过程。OpenFeign是Netflix开发的一个开源项目&#xff0c;它构建在Feign的基础上&#xff0c;为开发者提供了更加简单、灵活的方式来实现HTTP请求。OpenFeign的特点包括&#…

地平线秋招2025

【地平线秋招】 中秋卷起来&#xff01;&#xff01;&#xff01; 内推码 kbrfck 内推码 kbrfck 内推码 kbrfck 投递链接&#xff1a;https://wecruit.hotjob.cn/SU62d915040dcad43c775ec12c/mc/position/campus?acotycoCodekbrfck&recruitType1&isLimitShowPostScope…

【Google Chrome Windows 64 version及 WebDriver 版本】

最近升级到最新版本Chrome后发现页面居然显示错乱实在无语, 打算退回原来的版本, 又发现官方只提供最新的版本下载, 为了解决这个问题所有收集了Chrome历史版本的下载地址分享给大家. Google Chrome Windows version 64 位 VersionSize下载地址Date104.0.5112.10282.76 MBhtt…

STL相关简介

string 看到这个词&#xff0c;相信大家一定都很好奇什么是string&#xff0c;它有什么作用呢&#xff1f;今天&#xff0c;就让我们一起来了解一下关于string的简介吧~ 目录 string 1. 什么是STL 2. STL的版本 3. STL的六大组件 4. STL的重要性 5. 如何学习STL 6.STL的…

Unity实战案例全解析 :PVZ 植物脚本分析

植物都继承了Pants脚本&#xff0c;但是我因为没注意听讲&#xff0c;把Pants也挂在植物上了&#xff0c;所以子类的PlantEnableUpdate和PlantDisableUpdate抢不过父类&#xff0c;无法正确触发动画&#xff0c;我还找不到哪里出了问题&#xff0c;所以就使用了携程加while强行…

bpf的了解以及bpftrace的简单练习

最近接触到bpf的概念&#xff0c;简单做一些练习&#xff0c;做以下整理&#xff0c;学习笔记。 0&#xff1a;总结 使用ebpf可以实现的功能打开新世界&#xff0c;可以不改变源码的情况下&#xff0c;实现内存&#xff0c;网络&#xff0c;对应接口等各种期望内容的监控。 …

王者荣耀改重复名(java源码)

王者荣耀改重复名 项目简介 “王者荣耀改重复名”是一个基于 Spring Boot 的应用程序&#xff0c;用于生成王者荣耀游戏中的唯一名称。通过简单的接口和前端页面&#xff0c;用户可以输入旧名称并获得一个新的、不重复的名称。 功能特点 生成新名称&#xff1a;提供一个接口…

C++基础知识7 list

list 1. list的介绍及使用1.1 list的介绍1.2 list的使用1.2.1 list的构造1.2.2 list iterator的使用1.2.3 list capacity1.2.4 list element access1.2.5 list modifiers1.2.6 list的迭代器失效 2.1 模拟实现list 1. list的介绍及使用 1.1 list的介绍 1.2 list的使用 1.2.1 l…

aspcms 获取webshell漏洞复现

1.通过访问/admin_aspcms/login.asp来到后台 使用admin 123456 登录 2.点击扩展功能-幻灯片设置-保存&#xff0c;同时进行抓包 3.修改数据包中的slideTextStatus字段&#xff0c;将其更改为 1%25><%25Eval(Request (chr(65)))%25><%25 密码为a 4.访问木马的地…