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

智能座舱进阶-应用框架层-Handler分析

首先明确, handler是为了解决单进程内的线程之间的通信问题的。我也需要理解Android系统中进程和线程的概念, APP启动后,会有三四个线程启动起来,其中,有一条mainUITread的线程,专门用来处理UI事件,以及显示组件的生命周期,多个Activity的线程都是同一个。此外还要知晓,单进程内的多线程是共享内存、信号量、运行指令。如下图:
在这里插入图片描述

除了私有栈区,不能相互共享, 代码的方法指令、数据都可以在进程内任意线程执行。这里大家先记住这点, 在后面的问题3的解释中会用到。
enqueueMessage中的消息的存入,是可以设置时间先后的;
我们本篇幅文章只讨论三个问题:
1. Handler 的消息发送过程;
2. Message 被消耗的过程;
3. 为何需要Handler这个类的原因;

基础知识

跟handler相关的类:
Handler:发送消息的快递员(属于某个快递公司的职员)
Message:承担消息的包裹(可以放置很多东西的箱子)
MessageQueue:消息中心(这里会按照消息带的时间长短,一个排列好消息的单链表)
Looper: 真正在消费消息的永动机(这个是在主线程的,上面三个都在另一个线程里)

问题1#:Handler 的消息产生和发送过程

我们在Activity中的应用场景:
创建Handler的对象,里面也重写了真正去使用msg的回调方法:
//创建 Handler对象,并关联主线程消息队列

mHandler = new Handler(Looper.getMainLooper()) {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);···略···}}
};

发送消息:

Message msg = new Message();
msg.setData(bundle);
msg.what = 2;
mHandler.sendMessage(msg)

消息的产生, 可以在任何地方通过Message 去创建,它是一个比较简单的实体类, 包含1、what,when,target等。 这里面说一下:
2、what:就是携带的数据,Int类型;
3、when:这个一般不怎么用, 但是是可以使用,具体是输入时间长短后,当在msg发送到MessageQueue的队列里, 会根据when和当前时间来推送,需要去消费它的具体时间, 跟队列里的消息进行对比,然后排列插进去;
4、target: 这个一般我们没有赋值,是因为他在Messag的实例化对象的时候【obtain()方法】或者是在message的后续传递中底层会帮我们赋值, 这个在最后looper里消费的时候, 会使用,用它找到这个消息是用哪个handler来消费,调用他的handleMessage()方法。 这里也就说明了, 一个looper是支持绑定多个hander对象的,同时也不会混乱。

我们现在看一下handler的实例化过程:

public Handler(Callback callback, boolean async) {//......mLooper = Looper.myLooper();  //返回与当前线程关联的Looper对象,在后面Looper会讲到if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread " + Thread.currentThread()+ " that has not called Looper.prepare()");}mQueue = mLooper.mQueue;  //返回Looper对象的消息队列,在后面MessageQueue会讲到mCallback = callback;  //接口回调mAsynchronous = async; //是否异步}public interface Callback {public boolean handleMessage(Message msg); //这个函数大家都很熟悉了,暂不细说,总之都知道是用来回调消息的}

整个构造方法的过程中会确立以下几件事:

• 获取当前Handler实例所在线程的Looper对象:mLooper = Looper.myLooper(),这个looper获取的就是主线程那个loop
• 如果Looper不为空,则获取Looper的消息队列,赋值给Handler的成员变量mQueue:mQueue = mLooper.mQueue
• 可以设置Callback 来处理消息回调:mCallback = callback。

looper这里面为什么没有创建直接获取呢, 因为我们的Activity在每次创建的时候,
ActivityThread的1个静态的main();
而main()内则会调用Looper.prepareMainLooper()为主线程生成1个Looper对象,同时也会生成其对应的MessageQueue对象。为进程中的管理进行初始化。
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “ActivityThreadMain”);

    // Install selective syscall interceptionAndroidOs.install();// CloseGuard defaults to true and can be quite spammy.  We// disable it here, but selectively enable it later (via// StrictMode) on debug builds, but using DropBox, not logs.CloseGuard.setEnabled(false);Environment.initForCurrentUser();// Make sure TrustedCertificateStore looks in the right place for CA certificatesfinal File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());TrustedCertificateStore.setDefaultUserDirectory(configDir);// Call per-process mainline module initialization.initializeMainlineModules();Process.setArgV0("<pre-initialized>");Looper.prepareMainLooper();  // 在这里创建新的looper

ActivityThread thread = new ActivityThread();
thread.attach(false);

    if (sMainThreadHandler == null) {sMainThreadHandler = thread.getHandler();// 获取Handler}if (false) {Looper.myLooper().setMessageLogging(newLogPrinter(Log.DEBUG, "ActivityThread"));}// End of event ActivityThreadMain.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);Looper.loop();// 开始调用loop()方法

好了,言归正传, handler创建完成调用

mHandler.sendMessage(msg)方法进行发送:

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue; //获得当前的消息队列
if (queue == null) { //若是在创建Handler时没有指定Looper,就不会有对应的消息队列queue ,自然就会为null
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w(“Looper”, e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {msg.target = this;   //这个target就是前面我们说到过的if (mAsynchronous) {msg.setAsynchronous(true);}return queue.enqueueMessage(msg, uptimeMillis);
}

消息通过这个方法 queue.enqueueMessage(msg, uptimeMillis)进入到了queue队列里了。

boolean enqueueMessage(Message msg, long when) {if (msg.target == null) {  //判断msg的所属Handlerthrow new IllegalArgumentException("Message must have a target.");}//......synchronized (this) {  //因为是队列,有先后之分,所以用了同步机制//......msg.when = when;Message p = mMessages;  //对列中排在最后的那个Message //......if (p == null || when == 0 || when < p.when) {    //若队列为空,或者等待时间为0,或者比前面那位的等待时间要短,就插队msg.next = p;  //此处的next就是前面我们在Message提到的,指向队列的下一个结点mMessages = msg;//......} else { //......Message prev;for (;;) {     //此处for循环是为了取出一个空的或者when比当前Message长的一个消息,然后进行插入prev = p;p = p.next;if (p == null || when < p.when) {break;}//......}msg.next = p;       // 置换插入prev.next = msg;  // 置换插入}//......}return true;}

这个就消息新建产生,然后发送到了queue的消息队列里,对待looper去取然后分发消费了。

问题2#:Message的消费过程

这个我们要看一下looper.loop()方法:

public static void loop() {final Looper me = myLooper();if (me == null) {throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");}final MessageQueue queue = me.mQueue;Binder.clearCallingIdentity();final long ident = Binder.clearCallingIdentity();for (;;) {// 无限循环Message msg = queue.next(); // might blockif (msg == null) {// No message indicates that the message queue is quitting.return;}......final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();final long end;try {// 处理消息msg.target.dispatchMessage(msg);......}

前面有代码片里说到 ActivityThread.mian-> Looper.prepareMainLooper()->mLooper.loop():
我们只要看Loop()方法就可以了:

public static void loop() {final Looper me = myLooper();if (me == null) {throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");}final MessageQueue queue = me.mQueue;Binder.clearCallingIdentity();final long ident = Binder.clearCallingIdentity();for (;;) {// 无限循环Message msg = queue.next(); // might blockif (msg == null) {// No message indicates that the message queue is quitting.return;}......final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();final long end;try {// 处理消息msg.target.dispatchMessage(msg);......

这里面就看到,两件事情,根据target来判断是哪个handler,同时调用它的dispatchMessage来分发消息:

 public void dispatchMessage(Message msg) {if (msg.callback != null) {handleCallback(msg);} else {if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}handleMessage(msg);}}

最终调用了 我们附带了的callback的handleMessage()方法。

这里面还有一个疑惑, looper是怎么能够一直处理消息的。 大家看loop()方法中, 有一个for(;;)死循环,这个其实就是永远在轮询队列中的消息,for循环是可以被阻塞的, 在这里就是这个函数Message msg = queue.next(); 就是如果队列没有消息了,它就会阻塞, 类似thread.sleep(1000)的方法。 当有新消息, queue.next()就会正常,继续执行消息。

问题3#: 为什么需要handler

需要handler,是因为在Android的设计里,不允许除了UI主线程外的其他线程对UI进行操作,最终都会走到View.requestLayout()里面判断当前线程是否是主线。
所以我们就需要想办法,需要子线程执行的某个阶段,有需求更新UI,那我们就必须通知在主线程里面去执行刷新UI的代码,这个在很多地方都有这种设计, 设计一个轮转片的循环,线程内的通信,通过消息来通知。 比如JS这种单线程设计语言, 就有Emit的设计。
1.创建了一个Looper对象保存在ThreadLocal中。这个Looper同时持有一个MessageQueue对象。
2.创建Handler获取到Looper对象和MessageQueue对象。在调用sendMessage方法的时候在不同的线程(子线程)中把消息插入MessageQueue队列。

3.在主线程中(UI线程),调用Looper的loop()方法无限循环查询MessageQueue队列是否有消息保存了。有消息就取出来调用dispatchMessage()方法处理。这个方法最终调用了我们自己重写了消息处理方法handleMessage(msg);这样就完成消息从子线程到主线程的无声切换。

最后补充:我们经常使用Handler没有创建Looper调用Looper.pepare()和Looper.loop()是因为在ActivityThread中已经创建了主线程的Looper对象,保存在了ThreadLocal中,我们在创建Hander的时候就会从ThreadLocal中取出来这个Looper。

相关文章:

智能座舱进阶-应用框架层-Handler分析

首先明确&#xff0c; handler是为了解决单进程内的线程之间的通信问题的。我也需要理解Android系统中进程和线程的概念&#xff0c; APP启动后&#xff0c;会有三四个线程启动起来&#xff0c;其中&#xff0c;有一条mainUITread的线程&#xff0c;专门用来处理UI事件&#xf…...

颜色空间之RGB和HSV互转

参考文档&#xff1a; https://blog.csdn.net/shandianfengfan/article/details/120600453 定点化实现&#xff1a; #define FRAC_BIT 10 // 小数精度 #define MIN3(x,y,z)int min3(int a, int b, int c) {int ret_val a < b ? (a < c ? a : c) : (b < c ? b :…...

程序员之路:编程语言面向过程的特征

以下是面向过程编程语言所具有的一些典型特征&#xff1a; 一、以过程&#xff08;函数、子程序&#xff09;为核心组织代码 强调函数的作用&#xff1a; 在面向过程编程中&#xff0c;函数&#xff08;或子程序等不同语言中的类似概念&#xff09;是代码组织的关键单元。程序…...

matlab的一些时间函数【转】

看到就记下来&#xff0c;感觉挺好玩的。 原文&#xff1a;MATLAB-一些时间函数 - 简书 (jianshu.com) 注明出处了&#xff0c;原文是公开的&#xff0c;应该不算侵权。若有侵权请告知删除谢谢。...

OpenGL —— 2.6.1、绘制一个正方体并贴图渲染颜色(附源码,glfw+glad)

源码效果 C++源码 纹理图片 需下载stb_image.h这个解码图片的库,该库只有一个头文件。 具体代码: vertexShader.glsl #version...

【ETCD】【源码阅读】深入解析 EtcdServer.applyEntries方法

applyEntries方法的主要作用是接收待应用的 Raft 日志条目&#xff0c;并按顺序将其应用到系统中&#xff1b;确保条目的索引连续&#xff0c;避免丢失或重复应用条目。 一、函数完整代码 func (s *EtcdServer) applyEntries(ep *etcdProgress, apply *apply) {if len(apply.…...

【数据分析】数据分析流程优化:从数据采集到可视化的全面指南

目录 引言一、数据采集&#xff1a;高质量数据的起点1.1 数据采集的目标1.2 数据采集的常用方法1.3 数据采集的注意事项 二、数据清洗&#xff1a;确保数据质量2.1 数据清洗的重要性2.2 常见的数据清洗步骤 三、数据分析&#xff1a;从数据中挖掘有价值的洞察3.1 数据分析的目的…...

【华为OD-E卷-字符串重新排序 字符串重新排列 100分(python、java、c++、js、c)】

【华为OD-E卷-字符串重新排序 字符串重新排列 100分&#xff08;python、java、c、js、c&#xff09;】 题目 给定一个字符串s&#xff0c;s包括以空格分隔的若干个单词&#xff0c;请对s进行如下处理后输出&#xff1a; 1、单词内部调整&#xff1a;对每个单词字母重新按字典…...

Mybatis二级缓存

一、二级缓存的概念 MyBatis 的二级缓存是基于命名空间&#xff08;namespace&#xff09;的缓存&#xff0c;它可以被多个 SqlSession 共享。当开启二级缓存后&#xff0c;在一个 SqlSession 中执行的查询结果会被缓存起来&#xff0c;其他 SqlSession 在查询相同的语句&…...

C语言中的宏定义:无参宏与带参宏的详细解析

C语言中的宏定义&#xff1a;无参宏与带参宏的详细解析 在C语言中&#xff0c;宏定义是一种非常强大的预处理功能&#xff0c;通过#define指令可以定义一些常量或者代码片段&#xff0c;用来减少代码重复&#xff0c;提高可读性。本文将详细讲解无参宏与带参宏的使用方法&…...

unity 最小后监听键盘输入

当Untiy最小化后&#xff0c;游戏窗口不会立刻失去焦点&#xff0c;此时依然可以使用Input来获取按键&#xff0c;但是点击其他窗口后&#xff0c;就会失去焦点&#xff0c;此时系统会把按键输入分配到其他窗口里&#xff0c;此时要用windowsAPI获取按键输入&#xff0c;应对两…...

python使用Flask框架创建一个简单的动态日历

0. 运行效果 运行代码&#xff0c;然后在浏览器中访问 http://127.0.0.1:5000/&#xff0c;将看到一个动态日历&#xff0c;能够通过点击按钮切换月份。 1. 安装 Flask 首先&#xff0c;确保你已经安装了Flask。如果没有&#xff0c;可以使用以下命令安装&#xff1a; pip i…...

力扣438-找到字符串中所有字母异位词

力扣438-找到字符串中所有字母异位词 力扣438-找到字符串中所有字母异位词原题地址&#xff1a;https://leetcode.cn/problems/find-all-anagrams-in-a-string/description/ 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的 异位词的子串&#x…...

七、网络安全-企业数据脱敏

文章目录 前言一、数据脱敏方法二、企业脱敏方案1. 数据库脱敏方案2. 历史数据脱敏3. 具体实现 三、日志脱敏方案四、输出脱敏 前言 数据脱敏‌ 随着用户对个人隐私数据的重视和法律法规的完善&#xff0c;数据安全显得愈发重要。一方面可以加强权限管理&#xff0c;减少能够接…...

电子应用设计方案-62:智能鞋柜系统方案设计

智能鞋柜系统方案设计 一、引言 随着人们生活水平的提高&#xff0c;对家居用品的智能化需求也日益增加。智能鞋柜作为一种创新的家居产品&#xff0c;能够有效地解决鞋子的收纳、消毒、除臭和保养等问题&#xff0c;为用户提供更加便捷和健康的生活体验。 二、系统概述 1. 系…...

C++ 引用的基本用法

通过使用引用&#xff0c;可以创建该对象的另一个名字&#xff0c;而不会引入额外的内存开销。引用在函数参数传递、返回值以及避免拷贝大型对象时特别有用。 引用的基本用法 创建引用&#xff1a; 引用必须在创建时被初始化&#xff0c;且一旦被绑定到一个对象后&#xff0…...

全面解析 Golang Gin 框架

1. 引言 在现代 Web 开发中&#xff0c;随着需求日益增加&#xff0c;开发者需要选择合适的工具来高效地构建应用程序。对于 Go 语言&#xff08;Golang&#xff09;开发者来说&#xff0c;Gin 是一个备受青睐的 Web 框架。它轻量、性能高、易于使用&#xff0c;并且具备丰富的…...

element plus的table组件,点击table的数据是,会出现一个黑色边框

在使用 Element Plus 的 Table 组件时&#xff0c;如果你点击表格数据后出现了一个黑色边框&#xff0c;这通常是因为浏览器默认的焦点样式&#xff08;outline&#xff09;被触发了。如图&#xff1a; 你可以通过自定义 CSS 来隐藏这个黑色边框&#xff0c;代码如下&#xff1…...

三种国产大语言模型Python免费调用

基础三大模型&#xff0c;需要先去官方注册获得key&#xff1b;后续可以使用下列代码调用 1.腾讯 安装&#xff1a; pip install -i https://mirrors.tencent.com/pypi/simple/ --upgrade tencentcloud-sdk-python 实例&#xff1a; import jsonimport typesfrom tencentcl…...

Ansible playbook 详解与实战操作

一、概述 playbook 与 ad-hoc 相比,是一种完全不同的运用 ansible 的方式&#xff0c;类似与 saltstack 的 state 状态文件。ad-hoc 无法持久使用&#xff0c;playbook 可以持久使用。 playbook 是由一个或多个 play 组成的列表&#xff0c;play 的主要功能在于将事先归并为一…...

linux普通用户使用sudo不需要输密码

1.root用户如果没有密码&#xff0c;先给root用户设置密码 sudo passwd root #设置密码 2.修改visudo配置 su #切换到root用户下 sudo visudo #修改visudo配置文件 用户名 ALL(ALL) NOPASSWD: ALL #下图所示处新增一行配置 用户名需要输入自己当前主机的用户名...

linux-----数据库

Linux下数据库概述 数据库类型&#xff1a; 关系型数据库&#xff08;RDBMS&#xff09;&#xff1a;如MySQL、PostgreSQL、Oracle等。这些数据库以表格的形式存储数据&#xff0c;表格之间通过关系&#xff08;如主键 - 外键关系&#xff09;相互关联。关系型数据库支持复杂的…...

【Linux进程】进程间的通信

目录 1. 进程间通信 1.1 进程间通信的目的 2. 管道 2.1 什么是管道 2.2. 匿名管道 匿名管道的特性 管道的4种情况 联系shell中的管道 2.3. 命名管道 代码级建立命名管道 2.4. 小结 总结 1. 进程间通信 进程间通信&#xff08;Inter-Process Communication&#xff0c;IPC&…...

面试题整理4----lvs,nginx,haproxy区别和使用场景

LVS、Nginx、HAProxy&#xff1a;区别与使用场景 1. LVS&#xff08;Linux Virtual Server&#xff09;1.1 介绍1.2 特点1.3 使用场景 2. Nginx2.1 介绍2.2 特点2.3 使用场景 3. HAProxy3.1 介绍3.2 特点3.3 使用场景 4. 总结对比 在构建高可用、高性能的网络服务时&#xff0c…...

开放词汇目标检测(Open-Vocabulary Object Detection, OVOD)综述

定义 开放词汇目标检测&#xff08;Open-Vocabulary Object Detection, OVOD&#xff09;是一种目标检测任务&#xff0c;旨在检测和识别那些未在训练集中明确标注的物体类别。传统的目标检测模型通常只能识别有限数量的预定义类别&#xff0c;而OVOD模型则具有识别“开放词汇…...

Python读写JSON文件

import jsondef writeJSONFile(self):with open(g_updateFilePath, "w" encodingutf-8) as fiel:json.dump(dictData, fiel, indent4, ensure_asciiFalse)fiel.close()def readJsonToDict(file):with open(file, r, encodingutf-8) as f: # 确保文件以 UTF-8 编码打…...

使用Python开发高级游戏:创建一个3D射击游戏

在这篇文章中,我们将深入介绍如何使用Python开发一个简单的3D射击游戏。我们将使用Pygame库来创建2D游戏界面,并结合PyOpenGL来进行3D渲染。这个项目的目标是帮助你理解如何将2D和3D图形结合起来,创建更复杂的游戏机制,包括玩家控制、敌人AI、碰撞检测和声音效果。 一、开…...

springboot 配置Kafka 关闭自启动连接

这里写自定义目录标题 springboot 配置Kafka 关闭自启动连接方法一&#xff1a;使用 ConditionalOnProperty方法二&#xff1a;手动管理Kafka监听器容器方法三&#xff1a;使用 autoStartupfalse结语 springboot 配置Kafka 关闭自启动连接 在Spring Boot应用程序中&#xff0c…...

Jenkins中添加节点实战

Jenkins是一个开源的自动化服务器,用于持续集成和持续交付(CI/CD)。为了提高构建和测试的效率,我们可以在Jenkins中添加节点(也称为代理或从属节点)。本文将详细介绍如何在Jenkins中添加节点,包括安装Java 11、Git、设置凭证、多种配置Jenkins Agent的方法以及验证。 &#…...

DL作业11 LSTM

习题6-4 推导LSTM网络中参数的梯度&#xff0c; 并分析其避免梯度消失的效果 LSTM&#xff08;长短期记忆网络&#xff09;是一种特殊的循环神经网络&#xff08;RNN&#xff09;&#xff0c;旨在解决普通 RNN 在处理长序列时遇到的梯度消失和梯度爆炸问题。它通过设计多个门…...

用 Python 实现井字棋游戏

一、引言 井字棋&#xff08;Tic-Tac-Toe&#xff09;是一款经典的两人棋类游戏。在这个游戏中&#xff0c;玩家轮流在 3x3 的棋盘上放置自己的标记&#xff0c;通常是 “X” 和 “O”&#xff0c;第一个在棋盘上连成一线&#xff08;横、竖或斜&#xff09;的玩家即为获胜者。…...

构建MacOS应用小白教程(打包 签名 公证 上架)

打包 在package.json中&#xff0c;dependencies会被打进 Electron 应用的包里&#xff0c;而devDependencies则不会&#xff0c;所以必要的依赖需要放到dependencies中。files中定义自己需要被打进 Electron 包里的文件。以下是一个完整的 mac electron-builder的配置文件。 …...

如何高效使用 Facebook Business Manager (商务管理平台)

在数字营销的浪潮中&#xff0c;Facebook Business Manager&#xff08;商务管理平台&#xff09;已成为众多企业管理社交广告活动、品牌资产和团队协作的核心工具。无论你是刚刚进入社交广告领域的小型企业主&#xff0c;还是经验丰富的大型品牌经理&#xff0c;掌握 Facebook…...

每天学习一个思维模型 - 损失规避

定义 损失规避&#xff08;Loss aversion&#xff09;&#xff0c;又称损失厌恶&#xff0c;指人们面对同样数量的利益和损失时&#xff0c;认为损失更加令他们难以忍受。损失带来的负效用为收益正效用的2至2.5倍。损失厌恶反映了人们的风险偏好并不是一致的&#xff0c;当涉及…...

Python知识分享第三十一天-Numpy和Pnadas入门

NumPy Numpy介绍 Numpy是Python中科学计算的基础包,它是一个Python库提供多维数组对象 各种派生对象(如掩码数组和矩阵),以及用于对数组进行快速的各种例程,包括数学 ,逻辑, 形状操作,排序,选择,I/O,离散傅里叶变换,基本线性代数,基本统计运算,随机模拟等等(Numpy的核心是nda…...

mlr3超参数Hyperparameter 自动寻找auto

底层还是根据你本来在R跑单独那一个机器学习的函数&#xff0c;例如randomForest::randomForest()&#xff0c;里面可以填入什么&#xff0c;然后跟你的实际数据取值范围去设个范围。然后用auto_tuner()函数对学习器的超参数自动调参 随机森林randomforest learner_rf <- …...

双臂机器人

目录 一、双臂机器人简介 二、双臂机器人系统的组成 三、双臂机器人面临的主要挑战 3.1 协调与协同控制问题 3.2 力控制与柔顺性问题 3.3 路径规划与轨迹优化问题 3.4 感知与环境交互 3.5 人机协作问题 3.6 能源与效率问题 3.7 稳定性与可靠性问题 四、双臂机器人…...

MATLAB中cvx工具箱的使用

CVX 是 MATLAB 中一个用于解决凸优化问题的建模工具箱。它使得定义、求解和分析凸优化问题变得简单。CVX 允许用户用类似数学表达的方式编写凸优化问题&#xff0c;而不需要过多关注底层的优化算法。CVX 的核心功能是将一个简单的数学问题转化为 MATLAB 可以理解并求解的标准形…...

EGO Swarm翻译

目录 摘要 Ⅰ 介绍 Ⅱ 相关工作 A . 单四旋翼局部规划 B . 拓扑规划 C. 分布式无人机集群 Ⅲ 基于梯度的局部规划隐式拓扑轨迹生成 A.无需ESDF梯度的局部路径规划 B.隐式拓扑轨迹生成 Ⅳ 无人机集群导航 A 机间避碰 B. 定位漂移补偿 C. 从深度图像中去除agent Ⅴ …...

Webpack简单介绍及安装

一、介绍 Webpack 是一个现代 JavaScript 应用程序的静态模块打包器&#xff08;module bundler&#xff09;。它将应用程序中的所有依赖项&#xff08;JavaScript、图片、CSS 等&#xff09;打包成一个或多个 bundle。这样做的主要目的是减少加载时间和提高应用程序的加载性能…...

如何在Anaconda的虚拟环境中下载Python包

一、首先查看conda下的虚拟环境 使用conda info -e查看当前conda下的虚拟环境&#xff1a; conda info -e 二、激活要添加Python包的虚拟环境 其中base是基础环境&#xff0c;这里我们选择conda_env这个虚拟环境 conda activate conda_env 三、使用conda命令安装需要的Pyth…...

React 事件机制和原生 DOM 事件流有什么区别

发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【宝藏入口】。 React 的事件机制与原生 DOM 事件流在设计和实现上有一些显著的区别。了解这些区别有助于我们更好地理解 React 是如何管理事件的…...

React 底部加载组件(基于antd)

底部加载组件的意义在于提供一种流畅的用户体验&#xff0c;以便在用户滚动到页面底部时自动加载更多内容。这样可以让用户无需离开当前页面&#xff0c;就能够无缝地浏览更多的内容.通过底部加载组件&#xff0c;可以分批加载页面内容&#xff0c;减少一次性加载大量数据对页面…...

Redis应用—7.大Value处理方案

1.⽅案设计 步骤一&#xff1a;首先需要配置一个crontab定时调度shell脚本&#xff0c;然后该脚本每天凌晨会通过rdbtools⼯具解析Redis的RDB⽂件&#xff0c;接着对解析出的内容进行过滤&#xff0c;把RDB⽂件中的⼤key导出到CSV⽂件。 步骤二&#xff1a;使⽤SQL导⼊CSV⽂件到…...

洛谷P2742 圈奶牛 (凸包 Andrew算法)

[USACO5.1] 圈奶牛Fencing the Cows /【模板】二维凸包 题目背景 upd: 新增一组 hack 数据。 题目描述 农夫约翰想要建造一个围栏用来围住他的奶牛&#xff0c;可是他资金匮乏。他建造的围栏必须包括他的奶牛喜欢吃草的所有地点。对于给出的这些地点的坐标&#xff0c;计算…...

Spring(一)---IOC(控制权反转)

目录 引入 1.什么叫IOC(Inversion of Control)控制权反转&#xff1f; 2.什么叫AOP(Aspect-Oriented Programming)面向切面编程(涉及Java代理)&#xff1f; 3.简单谈一下Java怎么实现ICO? Spring框架的介绍 1. Spring框架的概述 2. Spring框架的优点 Spring IOC容器介绍…...

MySQL数据库——门诊管理系统数据库数据表

门诊系统数据库his 使用图形化工具或SQL语句在简明门诊管理系统数据库his中创建数据表&#xff0c;数据表结构见表2-3-9&#xff5e;表2-3-15所示。 表2-3-9 department&#xff08;科室信息表&#xff09; 字段名称 数据类型 长度 是否为空 说明 dep_ID int 否 科室…...

linux环境使用yum方式安装nginx

linux环境使用yum方式安装nginx 一、nginx官网 二、nginx安装 点击首页的 Docs 或者 install 都可以&#xff0c;最终都是进入到Installing nginx页面 因为安装的服务器环境是linux centos 所以选择 Installation on Linux下面 packages 跳转链接 点击packages后 最终会跳转…...

2024高级前端面试题大全

&#x1f3a8; 1、v-bind指令绑定所有属性 <comp :title"title" :color"color" /><comp v-bind"props" />&#x1f3a8; 父组件监听字组件渲染周期&#xff1a;hook:updated文章地址&#x1f3a8; Vue3 defineAsyncComponent动态导…...

[机器学习]XGBoost(3)——确定树的结构

XGBoost的目标函数详见[机器学习]XGBoost&#xff08;2&#xff09;——目标函数&#xff08;公式详解&#xff09; 确定树的结构 之前在关于目标函数的计算中&#xff0c;均假设树的结构是确定的&#xff0c;但实际上&#xff0c;当划分条件不同时&#xff0c;叶子节点包含的…...