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;}}
相关文章:

Android 12系统源码_窗口管理(八)WindowConfiguration的作用
前言 在Android系统中WindowConfiguration这个类用于管理与窗口相关的设置,该类存储了当前窗口的显示区域、屏幕的旋转方向、窗口模式等参数,应用程序通过该类提供的信息可以更好的适配不同的屏幕布局和窗口环境,以提高用户体验。 一、类定…...
已读论文创新点合集
系列文章目录 文章目录 系列文章目录一、《LAMM: Label Alignment for Multi-Modal Prompt Learning》二、《MaPLe: Multi-modal Prompt Learning》三、《Learning to Prompt for Vision-Language Models》CoOp 一、《LAMM: Label Alignment for Multi-Modal Prompt Learning》…...
12_持久化数据结构
菜鸟:老鸟,我在处理一个项目时遇到了问题。我需要频繁地修改和查询一个数据结构,但每次修改后我都得复制整个结构,性能实在是太低了。有没有什么办法可以高效地处理这种情况? 老鸟:你提到了一个很有意思的…...

【计算机网络】IP, 以太网, ARP, DNS
IP, 以太网, ARP, DNS IP协议回顾IP地址报文格式功能介绍地址管理IP地址数量问题初识 NAT 机制通信机制IP数量的解决方案网段划分特殊IP地址 路由选择 以太网协议报文格式源MAC/目的MACMAC地址是什么MAC地址格式MAC的作用 ARPDNS初识DNSDNS主要功能DNS的查询过程 IP协议 回顾I…...

OpenCore Legacy Patcher 2.0.0 发布,83 款不受支持的 Mac 机型将能运行最新的 macOS Sequoia
在不受支持的 Mac 上安装 macOS Sequoia (OpenCore Legacy Patcher v2.0.0) Install macOS on unsupported Macs 请访问原文链接:https://sysin.org/blog/install-macos-on-unsupported-mac/,查看最新版。原创作品,转载请保留出处。 作者主…...

爆改YOLOv8|使用MobileNetV4替换yolov8的Backbone
1,本文介绍 MobileNetV4 是最新的 MobileNet 系列模型,专为移动设备优化。它引入了通用反转瓶颈(UIB)和 Mobile MQA 注意力机制,提升了推理速度和效率。通过改进的神经网络架构搜索(NAS)和蒸馏…...

C语言 | Leetcode C语言题解之第406题根据身高重建队列
题目: 题解: int cmp(const void* _a, const void* _b) {int *a *(int**)_a, *b *(int**)_b;return a[0] b[0] ? a[1] - b[1] : b[0] - a[0]; }int** reconstructQueue(int** people, int peopleSize, int* peopleColSize, int* returnSize, int** …...

【Git】初识Git
本篇文章的环境是在 Ubuntu/Linux 环境下编写的 文章目录 版本控制器Git 基本操作安装 Git创建 Git 本地仓库配置 Git认识工作区、暂存区、版本库添加文件修改文件版本回退撤销修改删除文件 版本控制器 在日常工作和学习中,老板/老师要求我们修改文档,…...

vue3 透传 Attributes
前言 Vue 3 现在正式支持了多根节点的组件,也就是片段! Vue 2.x 遵循单根节点组件的规则,即一个组件的模板必须有且仅有一个根元素。 为了满足单根节点的要求,开发者会将原本多根节点的内容包裹在一个<div>元素中&#x…...

4.接口测试基础(Jmter工具/场景二:一个项目由多个人负责接口测试,我只负责其中三个模块,协同)
一、场景二:一个项目由多个人负责接口测试,我只负责其中三个模块,协同 1.什么是测试片段? 1)就相当于只是项目的一部分用例,不能单独运行,必须要和控制器(include,模块)一…...

electron react离线使用monaco-editor
目录 1.搭建一个 electron-vite 项目 2.安装monaco-editor/react和monaco-editor 3.引入并做monaco-editor离线配置 4.react中使用 5.完整代码示例 6.monaco-editor离线配置官方说明 7.测试 1.搭建一个 electron-vite 项目 pnpm create quick-start/electron 参考链接…...

Python 的 WSGI 简单了解
从 flask 的 hello world 说起 直接讨论 WSGI,很多人可能没有概念,我们还是先从一个简单的 hello world 程序开始吧。 from flask import Flaskapp Flask(__name__)app.route("/", methods[GET]) def index():return "Hello world!&q…...

基于stm32使用ucgui+GUIBuilder开发ui实例
1 项目需求 1.1 基于Tft 触摸屏实现一个自锁按键 1.2 按键在按下后背景色需要进行变化,以凸显当前按键状态(选中or 未选中) 1.3 按键选中时对某一gpio输出低电平,非选中时输出高电平 2 移植 ucgui UCGUI的文件数量很大&#x…...

Spring扩展点系列-ApplicationContextAwareProcessor
文章目录 简介源码分析示例代码示例一:扩展点的执行顺序运行示例一 示例二:获取配置文件值配置文件application.properties内容定义工具类ConfigUtilcontroller测试调用运行示例二 示例三:实现ResourceLoaderAware读取文件ExtendResourceLoad…...
基于Keil软件实现实时时钟(江协科技HAL库)
实时时钟实验是基于江协科技STM32的HAL库工程模板创建的(可以在作品“基于江科大STM32创建的HAL库工程模板”中的结尾处获取工程模板的百度网盘链接) 复制“OLED显示”的工程文件——“4-1 OLED显示屏”,并命名为“12-2 实时时钟 ”。打开工程,把下面的程序复制到相应的文…...

dedecms靶场(四种webshell姿势)
进入靶场 姿势一:过文件管理器上传WebShell 步骤一:登录后台 /dede 步骤二:核心-》文件式管理-》文件上传-》上传一句话木马 点击 步骤三:进行蚁剑连接 姿势二:修改模板文件拿WebShell 步骤一:模板-》默认…...

PHP:强大的Web开发语言
PHP:强大的Web开发语言 一、PHP 简介及优势 PHP 的基本概念 PHP(PHP: Hypertext Preprocessor)即 “超文本预处理器”,是一种通用开源脚本语言,最初由 Rasmus Lerdorf 于 1994 年创建。它可以在服务器上执行…...

06_Python数据类型_元组
Python的基础数据类型 数值类型:整数、浮点数、复数、布尔字符串容器类型:列表、元祖、字典、集合 元组 元组(Tuple)是一种不可变的序列类型,与列表类似,但有一些关键的区别。本质:只读的列表…...
【Vue】- ref获取DOM元素和购物车案例分析
文章目录 知识回顾前言源码分析1. ref2. 购物车案例分析3. 购物车计算、全选 拓展知识数据持久化localStorage 总结 知识回顾 前言 元素上使用 ref属性关联响应式数据,获取DOM元素 步骤 ● 创建 ref > const hRef ref(null) ● 模板中建立关联 > <h1 re…...

【AI大模型】ChatGPT模型原理介绍(下)
目录 🍔 GPT-3介绍 1.1 GPT-3模型架构 1.2 GPT-3训练核心思想 1.3 GPT-3数据集 1.4 GPT-3模型的特点 1.5 GPT-3模型总结 🍔 ChatGPT介绍 2.1 ChatGPT原理 2.2 什么是强化学习 2.3 ChatGPT强化学习步骤 2.4 监督调优模型 2.5 训练奖励模型 2.…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...