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去监听方向旋转。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

智能的三大问题:何以、所以、可以

智能具有三大问题&#xff0c;即何以、所以、可以。“何以&#xff08;Why&#xff09;”涉及探讨智能的本质及其产生的原因。智能是什么&#xff1f;它的定义和特征是什么&#xff1f;为什么人类或机器需要智能&#xff1f;它如何帮助我们解决复杂问题、做出决策和适应环境&am…

(五)Proteus仿真STM32单片机串口数据流收发

&#xff08;五&#xff09;Protues仿真STM32单片机串口数据流收发 – ARMFUN 1&#xff0c;打开STM32CubeMX&#xff0c;找到USART1,配置模式Asynchronous&#xff0c;此时PA9、PA10自动变成串口模式 串口默认参数:115200bps 8bit None 1stop 2&#xff0c;NVIC Settings使能…

【Ubuntu】在Ubuntu上安装IDEA

【Ubuntu】在Ubuntu上安装IDEA 零、前言 最近换了Ubuntu系统&#xff0c;但是还得是要写代码&#xff0c;这样就不可避免地用到IDEA&#xff0c;接下来介绍一下如何在Ubuntu上安装IDEA。 壹、下载 这一步应该很容易的&#xff0c;直接打开IDEA的下载页面&#xff0c;点击下…

科研绘图系列:R语言绘制SCI文章图2

文章目录 介绍加载R包导入数据图a图b图d系统信息介绍 文章提供了绘制图a,图b和图d的数据和代码 加载R包 library(ggplot2) library(dplyr) library(readxl) library(ggpmisc)导入数据 数据可从以下链接下载(画图所需要的所有数据): 百度网盘下载链接: https://pan.baid…

2024年软件设计师中级(软考中级)详细笔记【3】数据结构(下)(分值5分)

上午题第3章数据结构下部目录 前言第3章 数据结构【下】(5分)3.5 查找3.5.1 查找的基本概念【考点】3.5.2 静态查找表的查找方法3.5.3 动态查找表3.5.4 哈希表3.5.4.1 哈希表的定义3.5.4.2 哈希函数的构造方法3.5.4.3 处理冲突的方法 3.6 排序3.6.1 排序的基本概念3.6.2 简单排…

Java 获取热搜并生成图片

效果图如下&#xff1a; 第一步获取热搜 public List<String> getHotNews4(Integer size) {if (size < 0 || StringUtils.isEmpty(size)) {return null;}try {//set 转listreturn new ArrayList<>(getHotNews(size));} catch (Exception e) {logger.error(&qu…

Java 集合 Collection常考面试题

理解集合体系图 collection中 list 是有序的,set 是无序的 什么是迭代器 主要遍历 Collection 集合中的元素,所有实现了 Collection 的集合类都有一个iterator()方法,可以返回一个 iterator 的迭代器。 ArrayList 和 Vector 的区别? ArrayList 可以存放 null,底层是由数…

Java控制台实现《多线程模拟龟兔赛跑》(实现Runnale接口,重写run()方法)

&#xff08;温馨提示&#xff1a;本题最重要的是学习思路&#xff0c;代码还有待优化和改进&#xff01;&#xff09; 下一篇博客进行优化。实现Callable接口&#xff1a;V call() throws Exception 。可以返回结果&#xff0c;以及可以抛出异常。&#xff08;启动线程比较麻烦…

JavaSE——集合2:List(Iterator迭代器、增强for、普通for循环遍历集合)

目录 一、List (一)List接口基本介绍 二、List接口的常用方法 三、List集合的三种遍历方式 四、小练习——使用冒泡排序遍历集合 一、List (一)List接口基本介绍 List接口是Collection接口的子接口 public interface List<E> extends Collection<E> List集…

Matlab实现海洋捕食者优化算法优化回声状态网络模型 (MPA-ESN)(附源码)

目录 1.内容介绍 2部分代码 3.实验结果 4.内容获取 1内容介绍 海洋捕食者优化算法&#xff08;Marine Predators Algorithm, MPA&#xff09;是一种基于海洋生物捕食行为的新型群体智能优化算法。MPA通过模拟海洋捕食者如鲨鱼、海豚等在寻找猎物时的追踪、包围和攻击行为&…

高质量SCI论文撰写及投稿丨论文选题、文献调研、实验设计、数据分析、论文结构及语言规范等----AI强大功能

科学研究的核心在于将复杂的思想和实验成果通过严谨的写作有效地传递给学术界和工业界。对于研究生、青年学者及科研人员&#xff0c;如何高效撰写和发表SCI论文&#xff0c;成为提升学术水平和科研成果的重要环节。系统掌握从选题到投稿的全过程&#xff0c;提高论文撰写效率与…

区块链积分系统:重塑支付安全与商业创新的未来

在当今社会&#xff0c;数字化浪潮席卷全球&#xff0c;支付安全与风险管理议题日益凸显。随着交易频次与规模的不断扩大&#xff0c;传统支付体系正面临前所未有的效率、合规性和安全挑战。 区块链技术&#xff0c;凭借其去中心化、高透明度以及数据不可篡改的特性&#xff0c…

React(一) 认识React、熟悉类组件、JSX书写规范、嵌入变量表达式、绑定属性

文章目录 一、初始React1. React的基本认识2. Hello案例2.1 三个依赖2.2 渲染页面2.3 hello案例完整代码 二、类组件1. 封装类组件2. 组件里的数据3. 组件里的函数 (重点)4. 案例练习(1) 展示电影列表 三、JSX语法1. 认识JSX2. JSX书写规范及注释3. JSX嵌入变量作为子元素4. JS…

Linux操作系统小项目——实现《进程池》

文章目录 前言&#xff1a;代码实现&#xff1a;原理讲解&#xff1a;细节处理&#xff1a; 前言&#xff1a; 在前面的学习中&#xff0c;我们简单的了解了下进程之间的通信方式&#xff0c;目前我们只能知道父子进程的通信是通过匿名管道的方式进行通信的&#xff0c;这是因…

【gRPC】4—gRPC与Netty

gRPC与Netty ⭐⭐⭐⭐⭐⭐ Github主页&#x1f449;https://github.com/A-BigTree 笔记链接&#x1f449;https://github.com/A-BigTree/Code_Learning ⭐⭐⭐⭐⭐⭐ 如果可以&#xff0c;麻烦各位看官顺手点个star~&#x1f60a; &#x1f4d6;RPC专栏&#xff1a;https://…

力扣 前缀和

找子数组的个数了解前缀和的基础。 前缀和大致理解为到达某个位置&#xff0c;前面几个数的总和&#xff0c;即s[i1]s[i]a[i1]&#xff0c;可以通过一次循环获得。然后几个前缀和作差&#xff0c;即可得到某个位置到某个位置的和&#xff0c;根据map的键值对进行更新次数。 题…

opencv实战项目(三十一):基于同态滤波的图像亮度提升

文章目录 前言一、同态滤波二、算法实现 前言 在数字图像处理领域&#xff0c;图像亮度的调整是一项基本且至关重要的技术。它不仅关系到图像的视觉效果&#xff0c;而且在许多实际应用中&#xff0c;如医疗影像分析、卫星遥感监测、视频监控系统等&#xff0c;都扮演着关键角…

基于STM32 ARM+FPGA+AD的电能质量分析仪方案设计(一)硬件设计

电能质量分析系统硬件设计 3.1 电能质量分析系统设计要求 本系统实现对电能质量的高精度测量&#xff0c;根据国家相关电能质量分析仪器规定 标准以及对市场电能质量分析仪的分析&#xff0c;指定以下设计目标。 &#xff08; 1 &#xff09;电能质量参数测量精度&#xf…

欧科云链研究院深掘链上数据:洞察未来Web3的隐秘价值

目前链上数据正处于迈向下一个爆发的重要时刻。 随着Web3行业发展&#xff0c;公链数量呈现爆发式的增长&#xff0c;链上积聚的财富效应&#xff0c;特别是由行业热点话题引领的链上交互行为爆发式增长带来了巨量的链上数据&#xff0c;这些数据构筑了一个行为透明但与物理世…

【部署篇】Redis-01介绍‌

一、Redis介绍‌ 1、什么是Redis&#xff1f; ‌Redis&#xff0c;英文全称是Remote Dictionary Server&#xff08;远程字典服务&#xff09;&#xff0c;Redis是一个开源的、使用‌ANSI C语言编写的‌Key-Value存储系统&#xff0c;支持网络、可基于内存亦可持久化。‌ 它提…