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

【用法总结】无障碍AccessibilityService

一、背景

    本文仅用于做学习总结,转换成自己的理解,方便需要时快速查阅,深入研究可以去官网了解更多:官网链接点这里
    之前对接AI语音功能时,发现有些按钮(或文本)在我没有主动注册唤醒词场景下,还是响应了点击,使用profiler跟踪调用堆栈才发现是使用了无障碍服务实现的。因为开发的是系统应用,也没必要主动去打开无障碍服务开关,于是觉得无障碍服务有很大的可发挥空间,于是借助无障碍服务,实现了一个显示当前展示的Window/Activity/Dialog的悬浮窗,用于演示无障碍服务的用法及其强大之处。

二、用法

2.1 新建一个继承AccessibilityService的无障碍服务类,并按需重写回调方法
class AccessibilityTest : AccessibilityService() {override fun onAccessibilityEvent(event: AccessibilityEvent?) {Log.d(TAG, "onAccessibilityEvent: event = $event")}override fun onServiceConnected() {super.onServiceConnected()Log.d(TAG, "onServiceConnected: ")}override fun onUnbind(intent: Intent?): Boolean {Log.d(TAG, "onUnbind: intent = $intent")return super.onUnbind(intent)}override fun onInterrupt() {Log.d(TAG, "onInterrupt: ")}
}
  • onServiceConnected():
        当无障碍服务打开后,有注册的交互事件发生时,如果还没有连接服务,这会先执行连接,并回调这个方法。
        问题:AccessibilityServie继承Service也就是普通的服务,没有绑定前台的notification等可见的界面,会不会在后台过一会儿就断开了,是否会导致某些时候无法捕获到交互的事件??
  • onAccessibilityEvent(event: AccessibilityEvent?):
        当有注册的交互事件,比如:点击、长按、焦点变化等触发时,会回调这个函数
    • event.getEventType(): 获取事件类型,点击:TYPE_VIEW_CLICKED,长按:TYPE_VIEW_LONG_CLICKED,窗口状态变化:TYPE_WINDOW_STATE_CHANGED,详细的可以查阅AccessibilityService类的EventType注解中有枚举出所有的事件类型。
    • event.getPackName(): 获取交互来自的包名
    • event.getClassName(): 如果是Activity/Dialog则是其类的全路径名,如果是View的话则展示当前的View全路径名。
  • onUnbind(intent: Intent?):
        断开服务时回调,用于处理一些资源释放的逻辑。
  • onInterrupt():
2.2 AndroidManifest.xml文件中注册无障碍服务

    这个步骤和普通的Service注册有些不同,需要配置permission、intent-filter和无障碍服务的xml配置文件,基本都是固定的格式,只是按需改一些配置项。

<serviceandroid:name=".accessibility.AccessibilityTest"android:exported="true"android:label="@string/accessibility_tip"android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"android:process=":BackgroundService"><intent-filter><action android:name="android.accessibilityservice.AccessibilityService" /></intent-filter><meta-dataandroid:name="android.accessibilityservice"android:resource="@xml/accessibility_config" />
</service>
  • service节点配置的label标签会在无障碍服务中展示,比如上面的label内容是“accessibility_tip”,那么在无障碍服务中展示就会如下所示“:
    在这里插入图片描述
    在这里插入图片描述
        在/res/xml目录下,新建一个accessibility_config.xml文件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"android:accessibilityEventTypes="typeAllMask"android:accessibilityFeedbackType="feedbackGeneric"android:canRetrieveWindowContent="true"android:description="@string/accessibilty_desc" />

⚠️:如果这里指定了包名(android:packageNames的值,多个包名用英文逗号分隔。)则只会收到对应包名应用的事件。

  • android:description属性设置的就是上面的无障碍中accessibility_tip服务最下面的文案介绍。
  • android:accessibilityEventTypes:指定接收的事件类型
  • android:accessibilityFeedbackType:指定接收的反馈类型
2.3 在AccessibilityTest的onServiceConnected方法中动态设置serviceInfo
  • AccessibilityTest->onServiceConnected(): 通过在Service连接到无障碍服务的回调,调用setServiceInfo方法,可以在在运行时调整无障碍服务的配置:
override fun onServiceConnected() {super.onServiceConnected()Log.d(TAG, "onServiceConnected: ")val accessibilityServiceInfo = AccessibilityServiceInfo()accessibilityServiceInfo.eventTypes = (AccessibilityEvent.TYPE_WINDOWS_CHANGEDor AccessibilityEvent.TYPE_WINDOW_STATE_CHANGEDor AccessibilityEvent.TYPE_VIEW_CLICKEDor AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGEDor AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED)accessibilityServiceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_ALL_MASKaccessibilityServiceInfo.notificationTimeout = 0accessibilityServiceInfo.flags = AccessibilityServiceInfo.DEFAULT// 如果这里指定了包名则只会收到对应包名应用的事件accessibilityServiceInfo.packageNames = arrayOf("com.yanggui.animatortest")serviceInfo = accessibilityServiceInfo
}

    完成以上的步骤,然后编译运行安装到手机上,然后从无障碍服务中开启,就能够在AccessibilityTest的onAccessibilityEvent中收到各种交互事件了。

无障碍服务跑起来后,会打印如下log:

// 从无障碍服务中打开accessibility_tip服务回调onServiceConnected方法:
14:25:34.170  D  onServiceConnected:
// 打开当前应用会执行onAccessibilityEvent方法,回调一系列的事件信息,封装在// AccessibilityEvent中
14:26:44.792  D  onAccessibilityEvent: event = EventType: TYPE_VIEW_CLICKED; EventTime: 7897173; PackageName: com.google.android.apps.nexuslauncher; MovementGranularity: 0; Action: 0; ContentChangeTypes: []; WindowChangeTypes: [] [ ClassName: android.widget.TextView; Text: [AnimatorTest]; ContentDescription: AnimatorTest; ItemCount: -1; CurrentItemIndex: -1; Enabled: true; Password: false; Checked: false; FullScreen: false; Scrollable: false; BeforeText: null; FromIndex: -1; ToIndex: -1; ScrollX: 0; ScrollY: 0; MaxScrollX: 0; MaxScrollY: 0; ScrollDeltaX: -1; ScrollDeltaY: -1; AddedCount: -1; RemovedCount: -1; ParcelableData: null ]; recordCount: 0
14:26:44.847  D  onAccessibilityEvent: event = EventType: TYPE_WINDOW_CONTENT_CHANGED; EventTime: 7897231; PackageName: com.google.android.apps.nexuslauncher; MovementGranularity: 0; Action: 0; ContentChangeTypes: [CONTENT_CHANGE_TYPE_SUBTREE]; WindowChangeTypes: [] [ ClassName: android.widget.FrameLayout; Text: []; ContentDescription: null; ItemCount: -1; CurrentItemIndex: -1; Enabled: true; Password: false; Checked: false; FullScreen: false; Scrollable: false; BeforeText: null; FromIndex: -1; ToIndex: -1; ScrollX: 0; ScrollY: 0; MaxScrollX: 0; MaxScrollY: 0; ScrollDeltaX: -1; ScrollDeltaY: -1; AddedCount: -1; RemovedCount: -1; ParcelableData: null ]; recordCount: 0
14:26:44.891  D  onAccessibilityEvent: event = EventType: TYPE_WINDOW_STATE_CHANGED; EventTime: 7897277; PackageName: com.yanggui.animatortest; MovementGranularity: 0; Action: 0; ContentChangeTypes: []; WindowChangeTypes: [] [ ClassName: com.yanggui.animatortest.leanback.RowsSupportFragmentActivity; Text: [AnimatorTest]; ContentDescription: null; ItemCount: -1; CurrentItemIndex: -1; Enabled: true; Password: false; Checked: false; FullScreen: true; Scrollable: false; BeforeText: null; FromIndex: -1; ToIndex: -1; ScrollX: 0; ScrollY: 0; MaxScrollX: 0; MaxScrollY: 0; ScrollDeltaX: -1; ScrollDeltaY: -1; AddedCount: -1; RemovedCount: -1; ParcelableData: null ]; recordCount: 0
14:26:44.952  D  onAccessibilityEvent: event = EventType: TYPE_WINDOW_STATE_CHANGED; EventTime: 7897337; PackageName: com.yanggui.animatortest; MovementGranularity: 0; Action: 0; ContentChangeTypes: []; WindowChangeTypes: [] [ ClassName: com.yanggui.animatortest.leanback.RowsSupportFragmentActivity; Text: [AnimatorTest]; ContentDescription: null; ItemCount: -1; CurrentItemIndex: -1; Enabled: true; Password: false; Checked: false; FullScreen: true; Scrollable: false; BeforeText: null; FromIndex: -1; ToIndex: -1; ScrollX: 0; ScrollY: 0; MaxScrollX: 0; MaxScrollY: 0; ScrollDeltaX: -1; ScrollDeltaY: -1; AddedCount: -1; RemovedCount: -1; ParcelableData: null ]; recordCount: 0
// 从无障碍服务中关闭accessibility_tip服务回调onUnbind方法:
14:24:38.264  D  onUnbind: intent = Intent { cmp=com.yanggui.animatortest/.accessibility.AccessibilityTest }
2.4 附:反馈类型(feedbackType)和事件类型(eventType)的枚举值
  • 反馈类型(feedbackType):定义在AccessibilityServiceInfo中
@IntDef(flag = true, prefix = { "FEEDBACK_" }, value = {FEEDBACK_AUDIBLE,FEEDBACK_GENERIC,FEEDBACK_HAPTIC,FEEDBACK_SPOKEN,FEEDBACK_VISUAL,FEEDBACK_BRAILLE
})
@Retention(RetentionPolicy.SOURCE)
public @interface FeedbackType {}
  • 事件类型(eventType):定义在AccessibilityEvent中
@IntDef(flag = true,prefix = {"TYPE_"},value = {TYPE_VIEW_CLICKED, // 点击事件TYPE_VIEW_LONG_CLICKED, // 长按事件TYPE_VIEW_SELECTED, // view选中TYPE_VIEW_FOCUSED, // view上焦,使用遥控操作的需要关注该事件TYPE_VIEW_TEXT_CHANGED, // 表示更改 android.widget.EditText的文本的事件。TYPE_WINDOW_STATE_CHANGED,TYPE_NOTIFICATION_STATE_CHANGED,TYPE_VIEW_HOVER_ENTER,TYPE_VIEW_HOVER_EXIT,TYPE_TOUCH_EXPLORATION_GESTURE_START,TYPE_TOUCH_EXPLORATION_GESTURE_END,TYPE_WINDOW_CONTENT_CHANGED,TYPE_VIEW_SCROLLED,TYPE_VIEW_TEXT_SELECTION_CHANGED,TYPE_ANNOUNCEMENT,TYPE_VIEW_ACCESSIBILITY_FOCUSED,TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED,TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY,TYPE_GESTURE_DETECTION_START,TYPE_GESTURE_DETECTION_END,TYPE_TOUCH_INTERACTION_START,TYPE_TOUCH_INTERACTION_END,TYPE_WINDOWS_CHANGED,TYPE_VIEW_CONTEXT_CLICKED,TYPE_ASSIST_READING_CONTEXT,TYPE_SPEECH_STATE_CHANGE})@Retention(RetentionPolicy.SOURCE)public @interface EventType {}

三、实现展示当前Activity/Dialog/Window信息的悬浮窗

    如上介绍的,无障碍服务是能够获取到各种交互事件,从onAccessibilityEvent回调中可轻松拿到交互控件的packageName和className,所以基于无障碍服务能力的支持,也就很容易实现悬浮展示当前Activity的功能了。

3.1 全局悬浮窗的实现
  • 这个业务点的关键知识点是能全局悬浮,且不依赖Activity类型context,也就是不需要windowToken参数的window类型。
private const val TAG = "TopActivityEvent"
class TopActivityEventWindow {companion object {@SuppressLint("StaticFieldLeak")private var rootView: View? = null@SuppressLint("StaticFieldLeak")private var tvContent: TextView? = null@SuppressLint("StaticFieldLeak")private var window: TopActivityEventWindow? = null@SuppressLint("StaticFieldLeak")fun showEvent(ctx: Context, pkgName: String?, activityClassName: String?) {if (window == null) {initEventWindow(ctx)}if (!pkgName.isNullOrBlank() && !activityClassName.isNullOrBlank()) {tvContent?.text = "$pkgName\n$activityClassName"} else {Log.e(TAG, "showEvent: pkgName = $pkgName, activityClassName = $activityClassName")}}private fun initEventWindow(ctx: Context) {rootView =LayoutInflater.from(ctx).inflate(R.layout.layout_top_activity_window, null, false)val windowManager = ctx.getSystemService(Context.WINDOW_SERVICE) as? WindowManagerwindowManager?.apply {val lp = WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT)lp.type = if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {WindowManager.LayoutParams.TYPE_TOAST} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {// android31及以上 需要使用TYPE_APPLICATION_OVERLAY才能展示,使用ALERT_WINDOW会报没有权限WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY} else {WindowManager.LayoutParams.TYPE_SYSTEM_ALERT}lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_NOT_TOUCHABLElp.gravity = Gravity.TOP or Gravity.LEFTlp.format = PixelFormat.TRANSLUCENTaddView(rootView, lp)}tvContent = rootView?.findViewById(R.id.top_activity_window_text)window = TopActivityEventWindow()}fun dismiss(ctx: Context) {if (window != null) {val windowManager = ctx.getSystemService(Context.WINDOW_SERVICE) as? WindowManagerwindowManager?.removeView(rootView)tvContent = nullrootView = nullwindow = null}}}
}
3.1 在无障碍服务的onAccessibilityEvent中调用悬浮窗的展示逻辑
override fun onAccessibilityEvent(event: AccessibilityEvent?) {Log.d(TAG, "onAccessibilityEvent: event = $event")if (event?.eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {TopActivityEventWindow.showEvent(this.applicationContext, "${event.packageName}", "${event.className}")}}
3.2 实现的实际效果
  • 捕获pixel3a-api33模拟器的Launcher展示效果:
    在这里插入图片描述
  • 自己的demo app的主页获取效果:
    在这里插入图片描述
  • Dialog的捕获效果:
    在这里插入图片描述
  • PopupWindow获取不到待解决!!

四、总结

    以上是自定义Android的无障碍服务的基本用法。在清单文件中注册CustomAccessibilityService(在meta-datade android.accessibilityservice为key,填写配置文件xml的路径,关键是intent-filter节点中要写,service节点要写permission),然后重写onAccessiblityEvent()方法拿到交互事件、packageName、className,最后只要在系统设置-无障碍打开,就能很轻松实现一个自己的无障碍服务。这块定义注册Service的套路是固定的,核心是理解不同属性的作用,比如配置接收哪些事件类型和反馈类型,指定包名的方式等,其他的步骤不用纠结,直接在需要时照猫画虎就好了,不必花太多时间研究基础用法了。
    但是无障碍服务支持的能力还远不止于此,还能实现很多丰富的功能,比如:触发指定控件的点击,从而配合语音识别实现点击、跳转等业务逻辑,需要我们进一步阅读官方文档进行学习实践总结。

相关文章:

【用法总结】无障碍AccessibilityService

一、背景 本文仅用于做学习总结&#xff0c;转换成自己的理解&#xff0c;方便需要时快速查阅&#xff0c;深入研究可以去官网了解更多&#xff1a;官网链接点这里 之前对接AI语音功能时&#xff0c;发现有些按钮&#xff08;或文本&#xff09;在我没有主动注册唤醒词场景…...

AI绘画风格化实战

在社交软件和短视频平台上&#xff0c;我们时常能看到各种特色鲜明的视觉效果&#xff0c;比如卡通化的图片和中国风的视频剪辑。这些有趣的风格化效果其实都是图像风格化技术的应用成果。 风格化效果举例 MidLibrary 这个网站提供了不同的图像风格&#xff0c;每一种都带有鲜…...

008定点小数、奇偶校验码

...

一、二进制方式 安装部署K8S

目录 一、操作系统初始化 1、关闭防火墙 2、关闭 SELinu 3、 关闭 swap 4、添加hosts 5、同步系统时间 二、集群搭建 —— 使用外部Etcd集群 1、自签证书 2、自签 Etcd SSL 证书 ① 创建 CA 配置文件&#xff1a;ca-config.json ② 创建 CA 证书签名请求文件&#xff…...

【simple-admin】FMS模块如何快速接入阿里云oss 腾讯云cos 服务 实现快速上传文件功能落地

让我们一起支持群主维护simple-admin 社群吧!!! 不能加入星球的朋友记得来点个Star!! https://github.com/suyuan32/simple-admin-core 一、前提准备 1、goctls版本 goctls官方git:https://github.com/suyuan32/goctls 确保 goctls是最新版本 v1.6.19 goctls -v goct…...

数据结构.线性表(2)

一、模板 例子&#xff1a; a: b: 二、基本操作的实现 &#xff08;1&#xff09;初始化 &#xff08;2&#xff09;销毁和清空 &#xff08;3&#xff09;求长度和判断是否为空 &#xff08;4&#xff09;取值 &#xff08;5&#xff09;查找 &#xff08;6&#xff09;插入 &…...

【计算机网络】TCP原理 | 可靠性机制分析(三)

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【网络编程】【Java系列】 本专栏旨在分享学习网络编程、计算机网络的一点学习心得&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目…...

【昕宝爸爸小模块】线程的几种状态,状态之间怎样流转

➡️博客首页 https://blog.csdn.net/Java_Yangxiaoyuan 欢迎优秀的你&#x1f44d;点赞、&#x1f5c2;️收藏、加❤️关注哦。 本文章CSDN首发&#xff0c;欢迎转载&#xff0c;要注明出处哦&#xff01; 先感谢优秀的你能认真的看完本文&…...

ChatGPT网站小蜜蜂AI更新了

ChatGPT网站小蜜蜂AI更新了 前阶段郭震兄弟刚开发小蜜蜂AI网站的的时候&#xff0c;写了一篇关于ChatGPT的网站小蜜蜂AI的博文[https://blog.csdn.net/weixin_41905135/article/details/135297581?spm1001.2014.3001.5501]。今天听说小蜜蜂网站又增加了新的功能——在线生成思…...

瑞_Java开发手册_(二)异常日志

文章目录 异常日志的意义(一) 错误码(二) 异常处理(三) 日志规约附&#xff1a;错误码列表 &#x1f64a;前言&#xff1a;本文章为瑞_系列专栏之《Java开发手册》的异常日志篇&#xff0c;本篇章主要介绍异常日志的错误码、异常处理、日志规约。由于博主是从阿里的《Java开发手…...

Elasticsearch:Search tutorial - 使用 Python 进行搜索 (四)

在本节中&#xff0c;你将了解另一种机器学习搜索方法&#xff0c;该方法利用 Elastic Learned Sparse EncodeR 模型或 ELSER&#xff0c;这是一种由 Elastic 训练来执行语义搜索的自然语言处理模型。这是继之前的文章 “Elasticsearch&#xff1a;Search tutorial - 使用 Pyth…...

Python之Matplotlib绘图调节清晰度

Python之Matplotlib绘图调节清晰度 文章目录 Python之Matplotlib绘图调节清晰度引言解决方案dpi是什么&#xff1f;效果展示总结 引言 使用python中的matplotlib.pyplot绘图的时候&#xff0c;如果将图片显示出来&#xff0c;或者另存为图片&#xff0c;常常会出现清晰度不够的…...

pygame.error: video system not initialized

错误处理方式&#xff1a; pygame.init() 增加此行...

java面试题2024

前言 准备换工作了&#xff0c;给自己定个目标&#xff0c;每天至少整理出一道面试题。题型会比较随机&#xff0c;感觉这样更容易随机到面试官要问的东西。整理时我会把我认为正确的回答写出来&#xff0c;比较复杂的也尽量把原理贴出来&#xff0c;争取做到无论为了应付面试&…...

配置git服务器

第一步&#xff1a; jdk环境配置 &#xff08;1&#xff09;搜索【高级系统设置】&#xff0c;选择【高级】选项卡&#xff0c;点【环境变量】 &#xff08;2&#xff09;在【系统变量】里面&#xff0c;点击【新建】 &#xff08;3&#xff09;添加JAVA_HOME环境变量JAVA_HO…...

vue3环境下,三方组件中使用echarts,无法显示问题

问题描述&#xff1a; vue3中&#xff0c;使用了三方组件primevue的侧边栏Sidebar&#xff0c;在其中注册echarts dom节点&#xff0c;无法显示&#xff0c;提示dom不存在 问题分析&#xff1a; 使用原生div&#xff0c;通过document.getElementById()&#xff0c;将echarts…...

FAST OS DOCKER 可视化Docker管理工具

介绍 FAST OS DOCKER 界面直观、简洁&#xff0c;非常适合新手使用&#xff0c;方便大家轻松上手 docker部署运行各类有趣的容器应用&#xff0c;同时 FAST OS DOCKER 为防止服务器负载过高&#xff0c;进行了底层性能优化&#xff1b;其以服务器安全为基础&#xff0c;对其进…...

MOJO基础语法

文章目录 打印变量及方法声明结构体python集成 打印 print("Hello Mojo!")变量及方法声明 变量&#xff1a; 使用’ var ‘创建一个可变的值&#xff0c;或者用’ let 创建一个不可变的值。 方法&#xff1a; 方法可以使用python中的def 方法声明&#xff0c;也引…...

java基础之IO流之字符流

字符流 传输char和String类型的数据 输入流 抽象父类&#xff1a;Reader 节点流&#xff1a;FileReader 常用方法 int read()&#xff1a;读取一个字符&#xff0c;读取到达末尾&#xff0c;返回-1 package com.by.test2; ​ import java.io.FileNotFoundException; import…...

chromium通信系统-ipcz系统(十一)-mojo binding

关于mojo binding的官方文档为mojo docs。 由于比较复杂&#xff0c;这里只做简单源码分析。 我们知道要实现rpc&#xff0c;必须实现客户端和服务端。 mojo 实现了一套领域语言&#xff0c;通过领域语言描述接口和数据&#xff0c; 再通过特有编译器编译成c代码。 这个过程会…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写&#xff0c;中文译为后进先出。这是一种数据结构的工作原则&#xff0c;类似于一摞盘子或一叠书本&#xff1a; 最后放进去的元素最先出来 -想象往筒状容器里放盘子&#xff1a; &#xff08;1&#xff09;你放进的最后一个盘子&#xff08…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

基于TurtleBot3在Gazebo地图实现机器人远程控制

1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

Python 训练营打卡 Day 47

注意力热力图可视化 在day 46代码的基础上&#xff0c;对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...

redis和redission的区别

Redis 和 Redisson 是两个密切相关但又本质不同的技术&#xff0c;它们扮演着完全不同的角色&#xff1a; Redis: 内存数据库/数据结构存储 本质&#xff1a; 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能&#xff1a; 提供丰…...