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

Android底层摸索改BUG(一):Android系统状态栏显示不下Wifi图标

这是我入职的第一个BUG,头疼,隔壁实习生一周解决了,我多花了几天

其中最大的原因就是我思考复杂了,在公司系统上,此BUG标题为:

请确认Wifi优先级,状态栏Wifi被忽略

BUG意思就是:当前安卓系统状态栏图标有显示尺寸的测量,如果比如需要显示8个图标,已经在状态栏绘制不下,则显示一个点表示省略,而不希望wifi被省略

我思考了一下一直以为就是优先级问题,是不是Android底层状态栏有各个图标优先级,图标过多的时候优先级高的就不会被隐藏,而其实最后参考了公司以前相关BUG的修改,其实只是状态栏的图标大小修改即可,将图标改小,状态栏就可以多一个显示图标,Wifi就不会被隐藏。(点向后一个图标挪了一位)

在尺寸文件中进行修改:对这两个尺寸进行改小(可以调一下刷机看一下)

 <dimen name="status_bar_icon_size">14dip</dimen><dimen name="status_bar_system_icon_size">11.5dp</dimen>

值得一提的是上面的逻辑:超出的图标隐藏、绘制、测量相关的Java类是:StatusIconContainer.Java(虽然和BUG不在这改,记录一下)

/*** StatusIconContainer 是 StatusBarMobileView 内部的一个自定义视图容器,用于管理状态图标的显示。* 它负责在 StatusBarMobileView 中管理状态图标的布局和可见性。*/
public class StatusIconContainer extends AlphaOptimizedLinearLayout {//TAG    private static final String TAG = "StatusIconContainer";//是否打开DEBUG模式,会Log相关信息private static final boolean DEBUG = false;//是否打开DEBUG_OVERFLOW,会在状态栏绘制边框用来显示区域什么的private static final boolean DEBUG_OVERFLOW = false;// 最多可以显示 8 个状态图标,包括电池图标private static final int MAX_ICONS = 7;//    private static final int MAX_ICONS = 8;//点的个数        private static final int MAX_DOTS = 1;//Dot  点  Icon图标 相关属性private int mDotPadding;private int mIconSpacing;private int mStaticDotDiameter;private int mUnderflowWidth;private int mUnderflowStart = 0;// 是否可以在溢出空间中绘制private boolean mNeedsUnderflow;// 单个 StatusBarIconView 的点图标在此宽度内居中显示private int mIconDotFrameWidth;private boolean mShouldRestrictIcons = true;// 用于计算哪些状态要在布局期间可见private ArrayList<StatusIconState> mLayoutStates = new ArrayList<>();// 为了正确计数和测量private ArrayList<View> mMeasureViews = new ArrayList<>();// 任何被忽略的图标将不会被添加为子视图private ArrayList<String> mIgnoredSlots = new ArrayList<>();/*** 创建 StatusIconContainer 的构造函数。** @param context Android 上下文对象*/public StatusIconContainer(Context context) {this(context, null);}/*** 创建 StatusIconContainer 的构造函数。** @param context Android 上下文对象* @param attrs   属性集*/public StatusIconContainer(Context context, AttributeSet attrs) {super(context, attrs);initDimens();setWillNotDraw(!DEBUG_OVERFLOW);}@Overrideprotected void onFinishInflate() {super.onFinishInflate();}/*** 设置是否限制状态图标的显示。** @param should 是否应该限制状态图标的显示*/public void setShouldRestrictIcons(boolean should) {mShouldRestrictIcons = should;}/*** 检查是否正在限制状态图标的显示。** @return 如果正在限制状态图标的显示,则返回 true;否则返回 false。*/public boolean isRestrictingIcons() {return mShouldRestrictIcons;}/*** 初始化尺寸参数。*/private void initDimens() {// 这是与 StatusBarIconView 使用相同的值mIconDotFrameWidth = getResources().getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size);mDotPadding = getResources().getDimensionPixelSize(R.dimen.overflow_icon_dot_padding);mIconSpacing = getResources().getDimensionPixelSize(R.dimen.status_bar_system_icon_spacing);// 点图标int radius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius);// 计算点的直径 R.dimen.overflow_dot_radius 2dpmStaticDotDiameter = 2 * radius;// 不能超过宽度 mIconDotFrameWidth 图标宽度 最大图标个数-1(可能还有个点,所以-1) 每个宽高mUnderflowWidth = mIconDotFrameWidth + (MAX_DOTS - 1) * (mStaticDotDiameter + mDotPadding);android.util.Log.d(TAG, "initDimens: " + mUnderflowStart);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {float midY = getHeight() / 2.0f;// 首先对所有子视图进行布局,以便稍后移动它们for (int i = 0; i < getChildCount(); i++) {View child = getChildAt(i);int width = child.getMeasuredWidth();int height = child.getMeasuredHeight();int top = (int) (midY - height / 2.0f);child.layout(0, top, width, top + height);}resetViewStates();calculateIconTranslations();applyIconStates();}
//绘制@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (DEBUG_OVERFLOW) {//如果开启了DEBUG_OVERFLOW模式画框框Paint paint = new Paint();paint.setStyle(Style.STROKE);paint.setColor(Color.RED);// 显示边界框canvas.drawRect(getPaddingStart(), 0, getWidth() - getPaddingEnd(), getHeight(), paint);// 显示溢出框paint.setColor(Color.GREEN);canvas.drawRect(mUnderflowStart, 0, mUnderflowStart + mUnderflowWidth, getHeight(), paint);}}//测量@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {mMeasureViews.clear();int mode = MeasureSpec.getMode(widthMeasureSpec);final int width = MeasureSpec.getSize(widthMeasureSpec);final int count = getChildCount();// 收集所有希望进行布局的视图for (int i = 0; i < count; i++) {// 获取子视图StatusIconDisplayable icon = (StatusIconDisplayable) getChildAt(i);// 如果视图可见且没有被阻止,则加入可见视图列表if (icon.isIconVisible() && !icon.isIconBlocked()&& !mIgnoredSlots.contains(icon.getSlot())) {mMeasureViews.add((View) icon);}}// 可见视图数量int visibleCount = mMeasureViews.size();int maxVisible = visibleCount <= MAX_ICONS ? MAX_ICONS : MAX_ICONS - 1;int totalWidth = mPaddingLeft + mPaddingRight;boolean trackWidth = true;// 测量所有子视图,以便它们报告正确的宽度int childWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.UNSPECIFIED);mNeedsUnderflow = mShouldRestrictIcons && visibleCount > MAX_ICONS;for (int i = 0; i < visibleCount; i++) {View child = mMeasureViews.get(i);measureChild(child, childWidthSpec, heightMeasureSpec);int spacing = i == visibleCount - 1 ? 0 : mIconSpacing;if (mShouldRestrictIcons) {if (i < maxVisible && trackWidth) {totalWidth += getViewTotalMeasuredWidth(child) + spacing;} else if (trackWidth) {// 达到图标限制;为点图标添加空间totalWidth += mUnderflowWidth;trackWidth = false;}} else {totalWidth += getViewTotalMeasuredWidth(child) + spacing;}}if (mode == MeasureSpec.EXACTLY) {if (!mNeedsUnderflow && totalWidth > width) {mNeedsUnderflow = true;}setMeasuredDimension(width, MeasureSpec.getSize(heightMeasureSpec));} else {if (mode == MeasureSpec.AT_MOST && totalWidth > width) {mNeedsUnderflow = true;totalWidth = width;}setMeasuredDimension(totalWidth, MeasureSpec.getSize(heightMeasureSpec));}}@Overridepublic void onViewAdded(View child) {super.onViewAdded(child);StatusIconState vs = new StatusIconState();vs.justAdded = true;child.setTag(R.id.status_bar_view_state_tag, vs);}@Overridepublic void onViewRemoved(View child) {super.onViewRemoved(child);child.setTag(R.id.status_bar_view_state_tag, null);}/*** 添加要忽略的图标槽的名称。它将不会显示在布局中也不会被测量。** @param slotName 图标的名称,就像在 frameworks/base/core/res/res/values/config.xml 中定义的那样*/public void addIgnoredSlot(String slotName) {android.util.Log.d(TAG, "addIgnoredSlot: " + slotName);boolean added = addIgnoredSlotInternal(slotName);if (added) {requestLayout();}}/*** 添加要忽略的图标槽的名称的列表。** @param slots 要忽略的图标的名称列表*/public void addIgnoredSlots(List<String> slots) {for (String slot : slots) {android.util.Log.d(TAG, "addIgnoredSlots: " + slot);}boolean willAddAny = false;for (String slot : slots) {willAddAny |= addIgnoredSlotInternal(slot);}if (willAddAny) {requestLayout();}}/*** 内部添加要忽略的图标槽名称。** @param slotName 图标的名称,就像在 frameworks/base/core/res/res/values/config.xml 中定义的那样* @return 如果成功添加,则返回 true,否则返回 false*/private boolean addIgnoredSlotInternal(String slotName) {android.util.Log.d(TAG, "addIgnoredSlotInternal: " + slotName);if (mIgnoredSlots.contains(slotName)) {return false;}mIgnoredSlots.add(slotName);return true;}/*** 从忽略的图标槽中移除一个名称。** @param slotName 要移除的图标槽的名称*/public void removeIgnoredSlot(String slotName) {android.util.Log.d(TAG, "removeIgnoredSlot: " + slotName);boolean removed = mIgnoredSlots.remove(slotName);if (removed) {requestLayout();}}/*** 从忽略的图标槽中移除名称的列表。** @param slots 要移除的图标槽的名称列表*/public void removeIgnoredSlots(List<String> slots) {for (String slot: slots) {android.util.Log.d(TAG, "removeIgnoredSlot: " + slot);}boolean removedAny = false;for (String slot : slots) {removedAny |= mIgnoredSlots.remove(slot);}if (removedAny) {requestLayout();}}/*** 设置要忽略的图标槽的列表,清除当前的列表。** @param slots 要忽略的图标槽的名称列表*/public void setIgnoredSlots(List<String> slots) {mIgnoredSlots.clear();addIgnoredSlots(slots);}/*** 返回与特定槽名称相对应的视图。* 仅用于操作它如何呈现。** @param slot 槽名称,与 com.android.internal.R.config_statusBarIcons 中定义的名称相对应* @return 如果此容器拥有相应的视图,则返回该视图,否则返回 null*/public View getViewForSlot(String slot) {for (int i = 0; i < getChildCount(); i++) {View child = getChildAt(i);if (child instanceof StatusIconDisplayable&& ((StatusIconDisplayable) child).getSlot().equals(slot)) {return child;}}return null;}/*** 布局从右到左发生。*/private void calculateIconTranslations() {mLayoutStates.clear();float width = getWidth();float translationX = width - getPaddingEnd();float contentStart = getPaddingStart();int childCount = getChildCount();// Underflow === 不显示内容直到此索引if (DEBUG) Log.d(TAG, "calculateIconTranslations: start=" + translationX+ " width=" + width + " underflow=" + mNeedsUnderflow);// 收集所有希望可见的状态for (int i = childCount - 1; i >= 0; i--) {View child = getChildAt(i);StatusIconDisplayable iconView = (StatusIconDisplayable) child;StatusIconState childState = getViewStateFromChild(child);if (!iconView.isIconVisible() || iconView.isIconBlocked()|| mIgnoredSlots.contains(iconView.getSlot())) {childState.visibleState = STATE_HIDDEN;if (DEBUG) Log.d(TAG, "skipping child (" + iconView.getSlot() + ") not visible");continue;}// 移动 translationX 到布局的位置,以添加视图而不截断子视图translationX -= getViewTotalWidth(child);childState.visibleState = STATE_ICON;childState.xTranslation = translationX;mLayoutStates.add(0, childState);// 为下一个视图移动 translationX 以腾出间隔translationX -= mIconSpacing;}// 显示 1 至 MAX_ICONS 个图标,或 (MAX_ICONS - 1) 个图标 + 溢出int totalVisible = mLayoutStates.size();int maxVisible = totalVisible <= MAX_ICONS ? MAX_ICONS : MAX_ICONS - 1;mUnderflowStart = 0;int visible = 0;int firstUnderflowIndex = -1;for (int i = totalVisible - 1; i >= 0; i--) {StatusIconState state = mLayoutStates.get(i);// 如果在测量时发现需要溢出,则允许在此之前腾出空间if (mNeedsUnderflow && (state.xTranslation < (contentStart + mUnderflowWidth)) ||(mShouldRestrictIcons && visible >= maxVisible)) {firstUnderflowIndex = i;break;}mUnderflowStart = (int) Math.max(contentStart, state.xTranslation - mUnderflowWidth - mIconSpacing);visible++;}//开始判断是否超出  超出则画点if (firstUnderflowIndex != -1) {int totalDots = 0;int dotWidth = mStaticDotDiameter + mDotPadding;int dotOffset = mUnderflowStart + mUnderflowWidth - mIconDotFrameWidth;for (int i = firstUnderflowIndex; i >= 0; i--) {StatusIconState state = mLayoutStates.get(i);if (totalDots < MAX_DOTS) {state.xTranslation = dotOffset;state.visibleState = STATE_DOT;dotOffset -= dotWidth;totalDots++;} else {state.visibleState = STATE_HIDDEN;}}}// 从 NotificationIconContainer 中拿来的,不是最优解,但保持布局逻辑简洁if (isLayoutRtl()) {for (int i = 0; i < childCount; i++) {View child = getChildAt(i);StatusIconState state = getViewStateFromChild(child);state.xTranslation = width - state.xTranslation - child.getWidth();}}}private void applyIconStates() {for (int i = 0; i < getChildCount(); i++) {View child = getChildAt(i);StatusIconState vs = getViewStateFromChild(child);if (vs != null) {vs.applyToView(child);}}}private void resetViewStates() {for (int i = 0; i < getChildCount(); i++) {View child = getChildAt(i);StatusIconState vs = getViewStateFromChild(child);if (vs == null) {continue;}vs.initFrom(child);vs.alpha = 1.0f;vs.hidden = false;}}private static @Nullable StatusIconState getViewStateFromChild(View child) {return (StatusIconState) child.getTag(R.id.status_bar_view_state_tag);}private static int getViewTotalMeasuredWidth(View child) {return child.getMeasuredWidth() + child.getPaddingStart() + child.getPaddingEnd();}private static int getViewTotalWidth(View child) {return child.getWidth() + child.getPaddingStart() + child.getPaddingEnd();}public static class StatusIconState extends ViewState {/// StatusBarIconView.STATE_*public int visibleState = STATE_ICON;public boolean justAdded = true;// 从视图末尾的距离是最相关的,用于动画float distanceToViewEnd = -1;@Overridepublic void applyToView(View view) {float parentWidth = 0;if (view.getParent() instanceof View) {parentWidth = ((View) view.getParent()).getWidth();}float currentDistanceToEnd = parentWidth - xTranslation;if (!(view instanceof StatusIconDisplayable)) {return;}StatusIconDisplayable icon = (StatusIconDisplayable) view;AnimationProperties animationProperties = null;boolean animateVisibility = true;// 用于计算哪些状态在布局过程中是可见的,找出哪些属性的状态转换(如果有的话)我们需要动画// 确定要动画的状态转换的属性(如果有)if (justAdded|| icon.getVisibleState() == STATE_HIDDEN && visibleState == STATE_ICON) {// 图标正在出现,通过将其放在它将出现的位置并动画 alpha 来淡入它super.applyToView(view);view.setAlpha(0.f);icon.setVisibleState(STATE_HIDDEN);animationProperties = ADD_ICON_PROPERTIES;} else if (icon.getVisibleState() != visibleState) {if (icon.getVisibleState() == STATE_ICON && visibleState == STATE_HIDDEN) {// 消失,不要执行任何复杂的操作animateVisibility = false;} else {// 所有其他转换(到/从点等)animationProperties = ANIMATE_ALL_PROPERTIES;}} else if (visibleState != STATE_HIDDEN && distanceToViewEnd != currentDistanceToEnd) {// 可见性不在发生变化,只需动画位置animationProperties = X_ANIMATION_PROPERTIES;}icon.setVisibleState(visibleState, animateVisibility);if (animationProperties != null) {view.animate().cancel();icon.addTransformationToViewGroup(view, animationProperties, null);}icon.applyInShelfTransformation(view, this, animationProperties, animationProperties);}}
}

相关文章:

Android底层摸索改BUG(一):Android系统状态栏显示不下Wifi图标

这是我入职的第一个BUG&#xff0c;头疼&#xff0c;隔壁实习生一周解决了&#xff0c;我多花了几天 其中最大的原因就是我思考复杂了&#xff0c;在公司系统上&#xff0c;此BUG标题为&#xff1a; 请确认Wifi优先级&#xff0c;状态栏Wifi被忽略 BUG意思就是&#xff1a;当…...

第十三章---枚举类型与泛型

一&#xff0c;枚举类型 1.使用枚举类型设置常量 设置常量时&#xff0c;我们通常将常量放置在接口中&#xff0c;这样在程序中就可以直接使用。该常量稚因为在接口中定义常量时&#xff0c;该常量的修饰符为 final 与 static。 public interface Constants ( public static …...

shell语法大全(超级详细!!!!),非常适合入门

本文旨在对y总的Linux基础课shell语法做学习记录&#xff0c;指令较多&#xff0c;方便日后查找。 参考视频&#xff1a;Linux基础课 参考教程&#xff1a;Linux教程 1 概论 Linux中常见的shell脚本有很多种&#xff0c;常见的有&#xff1a; Bourne Shell(/usr/bin/sh或/bi…...

【Python机器学习】零基础掌握ExtraTreesRegressor集成学习

面临的问题:如何更准确地预测糖尿病患者的病情? 在医疗领域,准确预测疾病的发展状况是至关重要的。尤其是对于糖尿病这样的慢性病,一个精准的预测模型能帮助医生制定更有效的治疗方案。但问题是,如何构建一个高准确度的预测模型呢? 假设现有一组糖尿病患者的医疗数据,…...

网络协议--TCP的交互数据流

19.1 引言 前一章我们介绍了TCP连接的建立与释放&#xff0c;现在来介绍使用TCP进行数据传输的有关问题。 一些有关TCP通信量的研究如[Caceres et al. 1991]发现&#xff0c;如果按照分组数量计算&#xff0c;约有一半的TCP报文段包含成块数据&#xff08;如FTP、电子邮件和U…...

IOC课程整理-13 Spring校验

1. Spring 校验使用场景 2. Validator 接口设计 3. Errors 接口设计 4. Errors 文案来源 5. 自定义 Validator 6. Validator 的救赎 7. 面试题精选 Spring 校验接口是哪个 org.springframework.validation.Validator Spring 有哪些校验核心组件&#xff1f;...

SSM咖啡点餐管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 SSM 咖啡点餐管理系统是一套完善的信息系统&#xff0c;结合SSM框架完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主 要采用B/S模式开…...

Capacitor 打包 h5 到 Android 应用,uniapp https http net::ERR_CLEARTEXT_NOT_PERMITTED

Capacitor 打包 h5 到 Android 应用&#xff0c;uniapp https http net::ERR_CLEARTEXT_NOT_PERMITTED capacitor 官网&#xff1a; https://capacitorjs.com/docs/ 项目上需要做一个 app&#xff0c;而这个 app 是用 uniapp 做的&#xff0c;里面用到了一个依赖 dom 的库&…...

华为数通方向HCIP-DataCom H12-831题库(多选题:101-120)

第101题 LSR对收到的标签进行保留,且保留方式有多种,那么以下关于LDP标签保留一自由方式的说法 A、保留邻居发送来的所有标签 B、需要更多的内存和标签空间 C、只保留来自下一跳邻居的标签,丢弃所有非下一跳铃邻居发来的标签 D、节省内存和标签空间 E、当IP路由收敛、下一跳…...

misc学习(4)Traffic(流量分析)-

感悟&#xff1a;回想起自己学的计算机网络和网络协议分析&#xff0c;有所感悟&#xff1a;计算机网络好比将一群人区分开来&#xff08;局域网&#xff09;&#xff0c;为了能够使得不同部分的人能够沟通&#xff08;wireshark中的数据包&#xff09;&#xff0c;就设置了网络…...

Less的基本语法

less的每一个语句后必须使用";"结束&#xff0c;否则可能无法正确的转换成css 1、导入 即在当前less文件中引用其它less文件&#xff0c;被引入的less文件中的内容可以在此less文件中使用。在引用less文件时可以省略扩展名 import "global"; // global.…...

spring boot项目优雅停机

1、关闭流程 停止接收请求和内部线程。判断是否有线程正在执行。等待正在执行的线程执行完毕。停止容器。 2、关闭过程有新的请求 在kill Spring Boot项目时&#xff0c;如果有访问请求过来&#xff0c;请求会被拒绝并返回错误提示。 在kill Spring Boot项目时&#xff0c;Sp…...

链式存储方式下字符串的replace(S,T1,T2)运算

链式存储方式下字符串的replace运算 ⭐️题目⭐️思路⭐️代码✨定义结点✨打印字符串函数✨计算字符串函数✨初始化字符串函数✨代码解读✨字符串替换函数✨字符串替换函数解读✨ 主函数✨完整代码 实现在链式存储下字符串的replace(S,T1,T2)&#xff0c;来自课本习题的一道题…...

unity脚本_Mathf和Math c#

首先创建一个脚本 当我们要做一个值趋近于一个值变化时 可以用Mathf.Lerp(start,end,time);方法实现 比如物体跟随...

轻量级仿 Spring Boot=嵌入式 Tomcat+Spring MVC

啥&#xff1f;Spring Boot 不用&#xff1f;——对。就只是使用 Spring MVC Embedded Tomcat&#xff0c;而不用 Boot。为啥&#xff1f;——因为 Boot 太重了&#xff1a;&#xff09; 那是反智吗&#xff1f;Spring Boot 好好的就只是因为太重就不用&#xff1f;——稍安勿…...

笔记Kubernetes核心技术-之Controller

2、Controller 2.1、概述 在集群上管理和运行容器的对象&#xff0c;控制器(也称为&#xff1a;工作负载)&#xff0c;Controller实际存在的&#xff0c;Pod是抽象的&#xff1b; 2.2、Pod和Controller关系 Pod是通过Controller实现应用运维&#xff0c;比如&#xff1a;弹…...

Azure云工作站上做Machine Learning模型开发 - 全流程演示

目录 本文内容先决条件从“笔记本”开始设置用于原型制作的新环境&#xff08;可选&#xff09;创建笔记本开发训练脚本迭代检查结果 关注TechLead&#xff0c;分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验&#xff0c;同济本复旦硕&#xff0…...

前端 : 用html ,css,js写一个你画我猜的游戏

1.HTML&#xff1a; <body><div id "content"><div id "box1">计时器</div><div id"box"><div id "top"><div id "box-top-left">第几题:</div><div id "box…...

Illustrator 2024(AI v28.0)

Illustrator 2024是一款功能强大的矢量图形编辑软件&#xff0c;由Adobe公司开发。它是设计师、艺术家和创意专业人士的首选工具&#xff0c;用于创建和编辑各种矢量图形、插图、图标、标志和艺术作品。 以下是Adobe Illustrator的主要功能和特点&#xff1a; 矢量图形编辑&…...

【Git企业开发】第二节.Git 的分支管理

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;Git企业级开发 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01;&#xff0…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...