当前位置: 首页 > news >正文

Android屏幕旋转流程(2)

(1)疑问

(1)settings put system user_rotation 1是什么意思?

答:设置用户期望的屏幕转向,0代表:Surface.ROTATION_0竖屏;1代表:Surface.ROTATION_90横屏;

(2)设置user_rotation和GSensor哪个优先级更高,比如user_rotation = 0期待竖屏,但是打开屏幕旋转且处于横屏时,应该是横屏还是竖屏?

答:此时GSensor优先级更高,横屏显示,具体原因看第三个问题。

(3)SystemUI中的“自动旋转”按钮影响的是哪个数据和系统的值?

答:会影响Settings.System.ACCELEROMETER_ROTATION和DisplayRotation.userRotationMode的值。

// When not otherwise specified by the activity's screenOrientation, rotation should be determined by the system (that is, using sensors).
public final int USER_ROTATION_FREE = 0;//When not otherwise specified by the activity's screenOrientation, rotation is set by the user.
public final int USER_ROTATION_LOCKED = 1;USER_ROTATION_FREE :如果应用不指定屏幕方向,sensor传感器决定
USER_ROTATION_LOCKED:如果应用不指定屏幕方向,user决定方向,即user_rotation数据库值

打开自动旋转时候设置的是Settings.System.ACCELEROMETER_ROTATION的值,并且为1,否则设置成0,这个值会直接影响DisplayRotation.userRotationMode的值。

final int userRotationMode = Settings.System.getIntForUser(resolver,Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) !=0? WindowManagerPolicy.USER_ROTATION_FREE: WindowManagerPolicy.USER_ROTATION_LOCKED;

也就说如果打开了自动旋转,userRotationMode = USER_ROTATION_FREE,代表通过sensor决定;
否则设置成USER_ROTATION_LOCKED,由user_rotation决定。

(2)屏幕旋转流程

在Framework中,屏幕旋转功能主要是由WMS模块中的DisplayRotation对象来完成,在启动WindowManagerService过程中,创建DisplayContent对象时,会创建一个对应的DisplayRotation负责屏幕旋转逻辑,一个DisiplayContent对象对应一个DisplayRotation对象,或者说DisplayContent对象中持有一个DisplayRotation对象。

在DisplayRotation中,将获取Sensor数据并转换成具体方向旋转角度值的逻辑交给了OrientationListener对象来负责。

总结如下:DisplayContent负责控制,DisplayRotation负责执行,OrientationListener负责获取数据。

(A)DisplayRotation的初始化

//frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.javaDisplayRotation(WindowManagerService service, DisplayContent displayContent,DisplayPolicy displayPolicy, DisplayWindowSettings displayWindowSettings,Context context, Object lock) {// 是否支持自动旋转mSupportAutoRotation =mContext.getResources().getBoolean(R.bool.config_supportAutoRotation);// lid open 时指定的旋转角度mLidOpenRotation = readRotation(R.integer.config_lidOpenRotation);// 放在car dock时指定的旋转角度mCarDockRotation = readRotation(R.integer.config_carDockRotation);// 放在desk dock时指定的旋转角度mDeskDockRotation = readRotation(R.integer.config_deskDockRotation);// Hdmi连接时指定的旋转角度mUndockedHdmiRotation = readRotation(R.integer.config_undockedHdmiRotation);if (isDefaultDisplay) {final Handler uiHandler = UiThread.getHandler();// 创建OrientationListener对象mOrientationListener = new OrientationListener(mContext, uiHandler);// 初始化mOrientationListener.setCurrentRotation(mRotation);// 监听SettingsProvider中的变化mSettingsObserver = new SettingsObserver(uiHandler);mSettingsObserver.observe();}}

屏幕旋转离不开Sensor的监听,具体是由OrientationListener来负责,它会获取Sensor对象、监听Sensor数据、将Sensor的数据转换成旋转角度,并通知WindowManagerService更新方向。

(B)OrientationListener监听Gsensor数据

//frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java
private class OrientationListener extends WindowOrientationListener implements Runnable {transient boolean mEnabled;OrientationListener(Context context, Handler handler,@Surface.Rotation int defaultRotation) {super(context, handler, defaultRotation);}@Overridepublic void onProposedRotationChanged(@Surface.Rotation int rotation) {ProtoLog.v(WM_DEBUG_ORIENTATION, "onProposedRotationChanged, rotation=%d", rotation);// Send interaction power boost to improve redraw performance.mService.mPowerManagerInternal.setPowerBoost(Boost.INTERACTION, 0);dispatchProposedRotation(rotation);if (isRotationChoiceAllowed(rotation)) {mRotationChoiceShownToUserForConfirmation = rotation;final boolean isValid = isValidRotationChoice(rotation);sendProposedRotationChangeToStatusBarInternal(rotation, isValid);} else {mRotationChoiceShownToUserForConfirmation = ROTATION_UNDEFINED;mService.updateRotation(false /* alwaysSendConfiguration */,false /* forceRelayout */);}}@Overridepublic void enable() {mEnabled = true;getHandler().post(this);ProtoLog.v(WM_DEBUG_ORIENTATION, "Enabling listeners");}@Overridepublic void disable() {mEnabled = false;getHandler().post(this);ProtoLog.v(WM_DEBUG_ORIENTATION, "Disabling listeners");}@Overridepublic void run() {if (mEnabled) {super.enable();} else {super.disable();}}}

我们看一下它的父类WindowOrientationListener相关。

//frameworks/base/services/core/java/com/android/server/wm/WindowOrientationListener.java
public abstract class WindowOrientationListener {public WindowOrientationListener(Context context, Handler handler,@Surface.Rotation int defaultRotation) {this(context, handler, defaultRotation, SensorManager.SENSOR_DELAY_UI);}private WindowOrientationListener(Context context, Handler handler,@Surface.Rotation int defaultRotation, int rate) {mContext = context;mHandler = handler;mDefaultRotation = defaultRotation;mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);mRate = rate;List<Sensor> l = mSensorManager.getSensorList(Sensor.TYPE_DEVICE_ORIENTATION);Sensor wakeUpDeviceOrientationSensor = null;Sensor nonWakeUpDeviceOrientationSensor = null;for (Sensor s : l) {if (s.isWakeUpSensor()) {wakeUpDeviceOrientationSensor = s;} else {nonWakeUpDeviceOrientationSensor = s;}}if (wakeUpDeviceOrientationSensor != null) {mSensor = wakeUpDeviceOrientationSensor;} else {mSensor = nonWakeUpDeviceOrientationSensor;}if (mSensor != null) {//优先使用此种Sensor监听mOrientationJudge = new OrientationSensorJudge();}if (mOrientationJudge == null) {mSensor = mSensorManager.getDefaultSensor(USE_GRAVITY_SENSOR? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER);if (mSensor != null) {// Create listener only if sensors do exist//还有另外一种选择mOrientationJudge = new AccelSensorJudge(context);}}}abstract boolean isRotationResolverEnabled();public abstract void onProposedRotationChanged(int rotation);
}

OrientationSensorJudge和AccelSensorJudge都是继承自OrientationJudge,而OrientationJudge类作为SensorEventListener的实现类来接收Sensor事件,根据不同的Sensor会有不同的OrientationJudge对象与之匹配,之所以这样做是因为不同的Sensor上报的原始数据不同,因此需要做不同的转换才能获得最终的旋转角度值。

//frameworks/base/services/core/java/com/android/server/wm/WindowOrientationListener.java
abstract class OrientationJudge implements SensorEventListener {//...@Overridepublic abstract void onAccuracyChanged(Sensor sensor, int accuracy);@Overridepublic abstract void onSensorChanged(SensorEvent event);}
final class OrientationSensorJudge extends OrientationJudge {public void onSensorChanged(SensorEvent event) {int reportedRotation = (int) event.values[0];if (reportedRotation < 0 || reportedRotation > 3) {return;}//...finalizeRotation(reportedRotation);}@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) { }
}private void finalizeRotation(int reportedRotation) {int newRotation;synchronized (mLock) {mDesiredRotation = reportedRotation;newRotation = evaluateRotationChangeLocked();}if (newRotation >= 0) {mLastRotationResolution = newRotation;mLastRotationResolutionTimeStamp = SystemClock.uptimeMillis();//最终回调子类实现的onProposedRotationChanged函数onProposedRotationChanged(newRotation);}}

最终调用到OrientationListener的onProposedRotationChanged函数。

//frameworks/base/services/core/java/com/android/server/wm/WindowOrientationListener.java
final class AccelSensorJudge extends OrientationJudge {public void onSensorChanged(SensorEvent event) {float x = event.values[ACCELEROMETER_DATA_X];float y = event.values[ACCELEROMETER_DATA_Y];float z = event.values[ACCELEROMETER_DATA_Z];	  final long now = event.timestamp;final long then = mLastFilteredTimestampNanos;final float timeDeltaMS = (now - then) * 0.000001f;//各种计算函数// Determine new proposed rotation.oldProposedRotation = mProposedRotation;if (mPredictedRotation < 0 || isPredictedRotationAcceptableLocked(now)) {mProposedRotation = mPredictedRotation;}proposedRotation = mProposedRotation;// Tell the listener.if (proposedRotation != oldProposedRotation && proposedRotation >= 0) {//最终回调子类实现的onProposedRotationChanged函数onProposedRotationChanged(proposedRotation);}}@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {}//判断当前的方向改变是否需要更新到系统private boolean isPredictedRotationAcceptableLocked(long now) {// The predicted rotation must have settled long enough.//当前角度需要保持40ms以上if (now < mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS) {return false;}// The last flat state (time since picked up) must have been sufficiently long ago.//从手机平放着拿起需要500ms才会转屏if (now < mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS) {return false;}// The last swing state (time since last movement to put down) must have been sufficiently long ago.//晃动后300ms内都不能转屏if (now < mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS) {return false;}// The last acceleration state must have been sufficiently long ago.//加速转动的时候500ms都不能转屏if (now < mAccelerationTimestampNanos+ PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS) {return false;}// The last touch must have ended sufficiently long ago.//手没有触摸屏幕500ms才能转屏if (mTouched || now < mTouchEndedTimestampNanos+ PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS) {return false;}// Looks good!return true;}
}

可以看出以上二种实现,最终都会调用子类的onProposedRotationChanged函数来更新屏幕方向。

(C)监听SettingsProvider字段

另外在涉及到方向旋转功能上,DisplayRotation中还监听了以下四个SettingsProvider中的字段:

//frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.javaprivate class SettingsObserver extends ContentObserver {SettingsObserver(Handler handler) {super(handler);}void observe() {final ContentResolver resolver = mContext.getContentResolver();resolver.registerContentObserver(Settings.Secure.getUriFor(Settings.Secure.SHOW_ROTATION_SUGGESTIONS), false, this,UserHandle.USER_ALL);resolver.registerContentObserver(Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION), false, this,UserHandle.USER_ALL);resolver.registerContentObserver(Settings.System.getUriFor(Settings.System.USER_ROTATION), false, this,UserHandle.USER_ALL);resolver.registerContentObserver(Settings.Secure.getUriFor(Settings.Secure.CAMERA_AUTOROTATE), false, this,UserHandle.USER_ALL);updateSettings();}@Overridepublic void onChange(boolean selfChange) {if (updateSettings()) {mService.updateRotation(true /* alwaysSendConfiguration */,false /* forceRelayout */);}}}
  • Settings.System.ACCELEROMETER_ROTATION:该字段表示屏幕旋转模式,是否使用加速度传感器控制屏幕的方向旋转,开启时表示自由模式,关闭表示锁定模式;
  • Settings.System.USER_ROTATION:用户设置的屏幕旋转方向值,当没有使用加速度传感器,且顶层Activity没有指定旋转方向时作为默认值使用;
//frameworks/base/services/core/java/com/android/server/wm/DisplayRotation.java
private boolean updateSettings() {final ContentResolver resolver = mContext.getContentResolver();// 是否更新旋转方向值boolean shouldUpdateRotation = false;synchronized (mLock) {// 是否更新旋转方向监听boolean shouldUpdateOrientationListener = false;// Configure rotation suggestions.final int showRotationSuggestions =ActivityManager.isLowRamDeviceStatic()? Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DISABLED: Settings.Secure.getIntForUser(resolver,Settings.Secure.SHOW_ROTATION_SUGGESTIONS,Settings.Secure.SHOW_ROTATION_SUGGESTIONS_DEFAULT,UserHandle.USER_CURRENT);if (mShowRotationSuggestions != showRotationSuggestions) {mShowRotationSuggestions = showRotationSuggestions;shouldUpdateOrientationListener = true;}// Configure rotation lock.final int userRotation = Settings.System.getIntForUser(resolver,Settings.System.USER_ROTATION, Surface.ROTATION_0,UserHandle.USER_CURRENT);if (mUserRotation != userRotation) {mUserRotation = userRotation;shouldUpdateRotation = true;}final int userRotationMode = Settings.System.getIntForUser(resolver,Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) != 0? WindowManagerPolicy.USER_ROTATION_FREE: WindowManagerPolicy.USER_ROTATION_LOCKED;if (mUserRotationMode != userRotationMode) {mUserRotationMode = userRotationMode;shouldUpdateOrientationListener = true;shouldUpdateRotation = true;}// 更新方向旋转监听状态if (shouldUpdateOrientationListener) {updateOrientationListenerLw(); // Enable or disable the orientation listener.}final int cameraRotationMode = Settings.Secure.getIntForUser(resolver,Settings.Secure.CAMERA_AUTOROTATE, 0,UserHandle.USER_CURRENT);if (mCameraRotationMode != cameraRotationMode) {mCameraRotationMode = cameraRotationMode;shouldUpdateRotation = true;}}return shouldUpdateRotation;}
  • shouldUpdateRotation = true表示需要更新旋转角度;
  • shouldUpdateOrientationListener = true表示要更新旋转方向的监听状态;
  • mUserRotationMode表示当前的方向旋转模式;

(D)方向旋转Sensor监听的注册与解除

旋转角度监听状态的更新在DisplayRotation.updateOrientationListenerLw()方法中,这里会进行旋转角度相关Sensor的注册和解除流程。

查看代码发现,在亮灭屏流程中,当keyguard绘制状态、window状态发生变化后,也都会通过DisplayRotation.updateOrientationListener()方法更新方向旋转Sensor的监听状态。

public void updateOrientationListener() {synchronized (mLock) {updateOrientationListenerLw();}}

下面就来看一下,系统在什么场景下需要监听相关Sensor来进行方向旋转,什么情况下不需要监听。

private void updateOrientationListenerLw() {if (mOrientationListener == null || !mOrientationListener.canDetectOrientation()) {// If sensor is turned off or nonexistent for some reason.return;}// 是否正在进行点亮屏幕的操作final boolean screenOnEarly = mDisplayPolicy.isScreenOnEarly();// 是否唤醒系统final boolean awake = mDisplayPolicy.isAwake();// keyguard绘制是否完成final boolean keyguardDrawComplete = mDisplayPolicy.isKeyguardDrawComplete();// 窗口绘制是否完成final boolean windowManagerDrawComplete = mDisplayPolicy.isWindowManagerDrawComplete();boolean disable = true;// 只有在屏幕唤醒状态,且keyguard和窗口全部绘制完成的情况下,才会有资格注册sensor监听if (screenOnEarly&& (awake || mOrientationListener.shouldStayEnabledWhileDreaming())&& ((keyguardDrawComplete && windowManagerDrawComplete))) {if (needSensorRunning()) {disable = false;// Enable listener if not already enabled.if (!mOrientationListener.mEnabled) {mOrientationListener.enable();}}}// Check if sensors need to be disabled.if (disable) {mOrientationListener.disable();}}

对于旋转角度Sensor的注册/解除,会有多个因素决定,如是否亮屏、Keyguard绘制是否完成等。其规则是,在屏幕唤醒状态,且keyguard和窗口全部绘制完成的情况下,如果needSensorRunning()方法返回true,就会注册Sensor去监听方向旋转。

相关文章:

Android屏幕旋转流程(2)

&#xff08;1&#xff09;疑问 &#xff08;1&#xff09;settings put system user_rotation 1是什么意思&#xff1f; 答&#xff1a;设置用户期望的屏幕转向&#xff0c;0代表&#xff1a;Surface.ROTATION_0竖屏&#xff1b;1代表&#xff1a;Surface.ROTATION_90横屏&a…...

gaussdb hccdp认证模拟题(判断)

1.在事务ACID特性中&#xff0c;原子性指的是事务必须始终保持系统处于一致的状态。(1 分) 错。 2.某IT公司在开发软件时&#xff0c;需要使用GaussDB数据库&#xff0c;因此需要实现软件和数据的链接&#xff0c;而DBeaver是一个通用的数据库管理工具和 SQL 客户端&#xff…...

高效架构设计:JPA 实现单据管理,MyBatis 赋能报表查询的最佳实践

在现代企业应用开发中&#xff0c;数据持久层的设计与实现是至关重要的部分。开发者常常会面临选择如何合理地使用不同的数据访问框架&#xff0c;以最大限度地提升系统性能和开发效率。本文将讨论一种有效的搭配方案&#xff1a;使用 JPA 处理单据的增删改查操作&#xff0c;使…...

深入理解 CSS 浮动(Float):详尽指南

“批判他人总是想的太简单 剖析自己总是想的太困难” 文章目录 前言文章有误敬请斧正 不胜感恩&#xff01;目录1. 什么是 CSS 浮动&#xff1f;2. CSS 浮动的历史背景3. 基本用法float 属性值浮动元素的行为 4. 浮动对文档流的影响5. 清除浮动clear 属性清除浮动的技巧1. 使用…...

ElasticSearch学习笔记(三)Ubuntu 2204 server elasticsearch集群配置

如果你只是学习elasticsearch的增、删、改、查等相关操作&#xff0c;那么在windows上安装一个ES就可以了。但是你如果想在你的生产环境中使用Elasticsearch提供的强大的功能&#xff0c;那么还是建议你使用Linux操作系统。 本文以在Ubuntu 2204 server中安装elasticsearch 8.…...

基于STM32的简易交通灯proteus仿真设计(仿真+程序+设计报告+讲解视频)

基于STM32的简易交通灯proteus仿真设计(仿真程序设计报告讲解视频&#xff09; 仿真图proteus 8.9 程序编译器&#xff1a;keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;C0091 **1.**主要功能 功能说明&#xff1a; 以STM32单片机和数码管、LED灯设计简易交通…...

linux下新增加一块sata硬盘并使用

1&#xff09;确认新硬盘能被正确识别到 2&#xff09;对新硬盘进行分区 说明&#xff1a;fdisk指令中输入“m”&#xff0c;可以看到详细的指令含义。 3&#xff09;确认新创建的分区 5&#xff09;格式化新创建的分区 6&#xff09;挂载新分区并使用...

主从复制遇到的问题点

1.解决主从复制的配置问题 大致逻辑&#xff1a; 主库&#xff1a; 进入mysql的my.in文件&#xff0c;配置 server-id 1 log-bin mysql-bin log-bin D:/mysql/log binlog-do-db 数据库名 从库 进入mysql的my.in文件&#xff0c;配置 server-id 2 replicate-do-db 数据库名…...

Macbook ToDesk 无法连接网络

描述 网络连接的是 Wi-Fi&#xff0c;打开浏览器能跟正常浏览内容&#xff0c;说明 Wi-Fi 是正常的。 现象&#xff1a;显示网络连接失败&#xff0c;一直无法登陆&#xff01; 检查防火墙是没有阻止ToDesk 的任何连接&#xff0c;说明防火墙也是正常的。 解决 检查登录项&a…...

C++-容器适配器- stack、queue、priority_queue和仿函数

目录 1.什么是适配器 2.deque 1.简单了解结构 2.deque的缺陷 3.为什么选择deque作为stack和queue的底层默认容器 3.stack&#xff08;栈&#xff09; 4.queue&#xff08;队列&#xff09; 5.仿函数 6.priority_queue&#xff08;优先级队列&#xff09;&#xff08;堆…...

C++游戏开发指南

C游戏开发指南 引言 在这个数字娱乐时代&#xff0c;游戏行业炙手可热&#xff0c;你是否也憧憬着能亲自开发出一款独特的游戏呢&#xff1f;你是否想过&#xff0c;为什么越来越多的开发者选择C作为他们的开发语言&#xff1f;没错&#xff0c;C不仅是一种高效的编程语言&am…...

k8s的pod管理及优化

资源管理介绍 资源管理方式 命令式对象管理&#xff1a;直接用命令去操作kubernetes资源 命令式对象配置&#xff1a;通过命令配置和配置文件去操作kubernets资源 声明式对象配置&#xff1a;通过apply命令和配置文件去操作kubernets资源 命令式对象管理&#xff1a; 资源类…...

HTML 常用的块级元素和行内元素

1. 常用的块级元素 块级元素具有如下特点&#xff1a; 占据父容器的整行宽度。通常从新的一行开始。可以包含其他块级元素和行内元素。 常用的块级元素&#xff1a; div&#xff1a;通用的容器&#xff0c;用于布局和分块内容。 h1 到 h6&#xff1a;标题标签&#xff0c;定义…...

js短路求值

短路求值&#xff08;short-circuit evaluation&#xff09;是指在逻辑运算中&#xff0c;如果前面的表达式已经能够确定整个表达式的结果&#xff0c;后面的表达式就不会被执行。短路求值常见于逻辑运算符 &&&#xff08;与&#xff09;和 ||&#xff08;或&#xff0…...

react 知识点汇总(非常全面)

React 是一个用于构建用户界面的 JavaScript 库&#xff0c;由 Facebook 开发并维护。它的核心理念是“组件化”&#xff0c;即将用户界面拆分为可重用的组件。 React 的组件通常使用 JSX&#xff08;JavaScript XML&#xff09;。JSX 是一种 JavaScript 语法扩展&#xff0c;…...

如何加密重要U盘?U盘怎么加密保护?

在日常生活中&#xff0c;我们常常使用U盘来存储和传输重要文件。然而&#xff0c;U盘的便携性也意味着它容易丢失或被盗。为了保护U盘中的数据安全&#xff0c;我们需要对U盘进行加密。本文将为您介绍如何加密重要U盘&#xff0c;以及U盘加密保护的方法。 BitLocker BitLocke…...

js编写一个中奖程序

好的&#xff0c;以下是一个用JavaScript编写的抽奖程序&#xff0c;它根据给定的概率来决定奖项。我们将使用随机数生成器来模拟抽奖过程。 function drawPrize() {const prizes [{ name: 特等奖, probability: 0.00000001 },{ name: 一等奖, probability: 0.00000003 },{ n…...

Mybatis-plus的基础用法

文章目录 1. 核心功能1.1 配置与编写规则1.2 条件构造器1.3 自定义SQL1.4 IService接口1.4.1 Lambda方法1.4.2 批量新增 1.5 分页查询 2. 拓展功能2.1 代码生成器2.2 DB静态工具2.3 逻辑删除2.4 枚举处理器 参考 1. 核心功能 1.1 配置与编写规则 Maven依赖&#xff1a; <…...

【网络篇】计算机网络——应用层详述(笔记)

目录 一、应用层协议原理 1. 进入应用层 2. 网络应用程序体系结构 &#xff08;1&#xff09;客户-服务器体系结构&#xff08;client-server architecture&#xff09; &#xff08;2&#xff09; P2P 体系结构&#xff08;P2P architecture&#xff09; 3. 进程间通讯 …...

力扣10.9

3171. 找到按位或最接近 K 的子数组 给你一个数组 nums 和一个整数 k 。你需要找到 nums 的一个 子数组 &#xff0c;满足子数组中所有元素按位或运算 OR 的值与 k 的 绝对差 尽可能 小 。换言之&#xff0c;你需要选择一个子数组 nums[l..r] 满足 |k - (nums[l] OR nums[l 1…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持&#xff0c;不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

vulnyx Blogger writeup

信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面&#xff0c;gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress&#xff0c;说明目标所使用的cms是wordpress&#xff0c;访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...