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

Android Framework AMS(13)广播组件分析-4(LocalBroadcastManager注册/注销/广播发送处理流程解读)

该系列文章总纲链接:专题总纲目录 Android Framework 总纲


本章关键点总结 & 说明:

说明:本章节主要解读广播组件的广播发送过程。关注思维导图中左上侧部分即可。

有了前面普通广播组件 注册/注销程/广播组件的发送广播流程分析的基础,基于此,接下来我们来分析LocalBroadcastManager也就是本地广播组件的 注册/注销程/广播组件的发送广播流程。

我们先对LocalBroadcastManager的引用有一个了解,再详细分析其注册/注销/广播发送关键流程。

1 LocalBroadcastManager应用解读

LocalBroadcastManager是Android框架中一个非常有用的工具类,它允许应用内的各个组件(如Activities、Services、Fragments等)之间通过广播机制进行通信,而无需使用全局的Intent系统。这种通信方式被称为本地广播或应用内广播。的主要特点和用途解读如下:

  • 作用域限制:LocalBroadcastManager限制了广播的作用域在应用内部,这意味着广播不会被发送到其他应用,增强了数据的安全性。
  • 简化通信:它提供了一种简化的通信方式,使得应用内部的组件可以轻松地发送和接收消息,而不需要处理复杂的Intent和Permission。
  • 解耦组件:LocalBroadcastManager帮助解耦应用内的组件,组件之间不需要直接引用或依赖,只需注册感兴趣的广播即可。
  • 线程安全:所有与LocalBroadcastManager交互的操作都是线程安全的,这意味着它可以在任何线程中使用,包括主线程和后台线程。
  • 异步和同步发送:应用可以使用LocalBroadcastManager发送异步广播(使用sendBroadcast)或同步广播(使用sendBroadcastSync)。
  • 广播生命周期管理:LocalBroadcastManager管理广播的生命周期,包括注册接收器、发送广播和注销接收器。
  • 性能优化:由于广播仅限于应用内部,LocalBroadcastManager可以减少系统资源的消耗,提高应用性能。
  • 使用场景:适用于需要在应用的不同组件之间传递小量数据的场景,如更新UI、同步数据。

以下是一个使用LocalBroadcastManager发送和接收本地广播的示例,包含发送广播和接收广播两部分。

1.1 发送广播部分

首先,我们需要一个方法来发送本地广播。这通常可以在某个事件发生时触发,比如用户完成了某个操作。SendBroadcastActivity.java内如实现如下:

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;public class SendBroadcastActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_send_broadcast);}public void sendLocalBroadcast(View view) {Intent intent = new Intent("com.example.myapp.LOCAL_BROADCAST");intent.putExtra("key_message", "Hello, this is a local broadcast!");// 使用LocalBroadcastManager发送本地广播LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);localBroadcastManager.sendBroadcast(intent);}
}

1.2 接收广播部分

接下来,我们需要一个组件来接收并处理这个本地广播。这里我们使用一个Service作为例子。ReceiveBroadcastService.java内容实现如下:

import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;public class ReceiveBroadcastService extends Service {@Overridepublic void onCreate() {super.onCreate();// 创建IntentFilter并添加要接收的广播ActionIntentFilter filter = new IntentFilter("com.example.myapp.LOCAL_BROADCAST");// 使用LocalBroadcastManager注册接收器LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);localBroadcastManager.registerReceiver(broadcastReceiver, filter);}@Overridepublic void onDestroy() {super.onDestroy();// 注销接收器LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);localBroadcastManager.unregisterReceiver(broadcastReceiver);}@Overridepublic IBinder onBind(Intent intent) {// 不提供绑定服务,返回nullreturn null;}private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if ("com.example.myapp.LOCAL_BROADCAST".equals(action)) {String message = intent.getStringExtra("key_message");// 处理接收到的广播,比如显示日志、更新UI等}}};
}

1.3 对应的AndroidManifest.xml配置文件部分

对应的AndroidManifest.xml配置文件参考如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.myapp"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><!-- 发送广播的Activity --><activity android:name=".SendBroadcastActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><!-- 接收广播的Service --><service android:name=".ReceiveBroadcastService" /></application>
</manifest>

2 LocalBroadcastManager解读

基于上面的案例demo,我们主要分析几个关键代码及对应流程:

  • localBroadcastManager = LocalBroadcastManager.getInstance(this); 获取LocalBroadcastManager的单例对象流程
  • localBroadcastManager.registerReceiver(broadcastReceiver, filter);注册流程
  • localBroadcastManager.unregisterReceiver(broadcastReceiver);注销流程
  • localBroadcastManager.sendBroadcast(intent);广播发送流程

2.1 获取LocalBroadcastManager的单例对象流程解读

LocalBroadcastManager的单例模式设计和构造器实现代码如下:

//LocalBroadcastManager// 单例模式public static LocalBroadcastManager getInstance(Context context) {synchronized (mLock) {if (mInstance == null) {mInstance = new LocalBroadcastManager(context.getApplicationContext());}return mInstance;}}// 构造函数private LocalBroadcastManager(Context context) {mAppContext = context;mHandler = new Handler(context.getMainLooper()) {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_EXEC_PENDING_BROADCASTS:// 调用executePendingBroadcasts方法来执行挂起的广播executePendingBroadcasts(); break;default:super.handleMessage(msg);}}};}

这里在构造期中初始化了一个Handler用于消息处理。

2.2 LocalBroadcastManager注册接收器流程解读

注册receiver流程为registerReceiver方法,代码实现如下:

//LocalBroadcastManagerpublic void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {synchronized (mReceivers) {// 创建一个新的ReceiverRecord对象,它包含了IntentFilter和BroadcastReceiver的引用ReceiverRecord entry = new ReceiverRecord(filter, receiver);// 获取与该BroadcastReceiver关联的IntentFilter列表ArrayList<IntentFilter> filters = mReceivers.get(receiver);if (filters == null) {// 如果列表不存在,则创建一个新的列表并将其与BroadcastReceiver关联filters = new ArrayList<IntentFilter>(1);mReceivers.put(receiver, filters);}// 将新的IntentFilter添加到列表中filters.add(filter);// 遍历IntentFilter中的所有动作for (int i = 0; i < filter.countActions(); i++) {String action = filter.getAction(i);// 获取与该动作关联的ReceiverRecord列表ArrayList<ReceiverRecord> entries = mActions.get(action);if (entries == null) {// 如果列表不存在,则创建一个新的列表并将其与动作关联entries = new ArrayList<ReceiverRecord>(1);mActions.put(action, entries);}// 将ReceiverRecord添加到与动作关联的列表中entries.add(entry);}}}

registerReceiver方法通过维护两个映射(mReceivers和mActions)来管理BroadcastReceiver的注册信息。这种方法允许LocalBroadcastManager高效地处理本地广播的注册和分发,确保只有匹配特定IntentFilter的广播被发送到对应的BroadcastReceiver。

2.3 LocalBroadcastManager注销接收器流程解读

注销receiver流程为unregisterReceiver方法,代码实现如下:

//LocalBroadcastManagerpublic void unregisterReceiver(BroadcastReceiver receiver) {synchronized (mReceivers) {// 从mReceivers映射中移除与BroadcastReceiver关联的IntentFilter列表ArrayList<IntentFilter> filters = mReceivers.remove(receiver);if (filters == null) {// 如果没有找到对应的IntentFilter列表,直接返回return;}for (int i = 0; i < filters.size(); i++) {// 遍历每个IntentFilterIntentFilter filter = filters.get(i);for (int j = 0; j < filter.countActions(); j++) {// 遍历IntentFilter中的每个动作String action = filter.getAction(j);ArrayList<ReceiverRecord> receivers = mActions.get(action);if (receivers != null) {// 在与动作关联的ReceiverRecord列表中查找对应的BroadcastReceiverfor (int k = 0; k < receivers.size(); k++) {if (receivers.get(k).receiver == receiver) {// 如果找到,从列表中移除对应的ReceiverRecordreceivers.remove(k);k--; // 调整索引,因为列表大小变了}}// 如果某个动作的所有ReceiverRecord都被移除了,那么也移除这个动作if (receivers.size() <= 0) {mActions.remove(action);}}}}}}

unregisterReceiver方法通过遍历mReceivers映射和mActions映射来注销BroadcastReceiver。它确保了所有与BroadcastReceiver关联的IntentFilter和动作都被正确地移除,保持了LocalBroadcastManager内部状态的一致性。这个过程对于维护LocalBroadcastManager的注册表非常重要,确保了广播能够准确地发送给正确的接收器。

2.4 LocalBroadcastManager发送广播流程解读

2.4.1 sendBroadcast方法解读

发送广播流程为sendBroadcast方法,代码实现如下:

//LocalBroadcastManager//关键流程:step1public boolean sendBroadcast(Intent intent) {synchronized (mReceivers) {// 获取Intent中的动作final String action = intent.getAction();// 根据ContentResolver解析Intent的数据类型final String type = intent.resolveTypeIfNeeded(mAppContext.getContentResolver());// 获取Intent中的数据Urifinal Uri data = intent.getData();// 获取Intent中的schemefinal String scheme = intent.getScheme();// 获取Intent中的categoriesfinal Set<String> categories = intent.getCategories();// 根据动作从mActions映射中获取对应的ReceiverRecord列表ArrayList<ReceiverRecord> entries = mActions.get(intent.getAction());if (entries != null) {// 如果有记录,准备发送广播ArrayList<ReceiverRecord> receivers = null;for (int i = 0; i < entries.size(); i++) {ReceiverRecord receiver = entries.get(i);// 如果ReceiverRecord正在广播中,则跳过if (receiver.broadcasting) {continue;}// 匹配IntentFilter和Intentint match = receiver.filter.match(action, type, scheme, data, categories, "LocalBroadcastManager");// 如果匹配成功if (match >= 0) {if (receivers == null) {receivers = new ArrayList<ReceiverRecord>();}receivers.add(receiver);receiver.broadcasting = true; // 标记为正在广播}}// 如果有匹配的接收器if (receivers != null) {for (int i = 0; i < receivers.size(); i++) {receivers.get(i).broadcasting = false; // 重置广播状态}// 将广播记录添加到待处理列表mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));// 如果Handler没有正在处理的消息,则发送一个消息以执行待处理的广播if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);}return true; // 返回true表示广播已发送}}}return false; // 返回false表示没有匹配的接收器}//消息处理流程private LocalBroadcastManager(Context context) {mAppContext = context;mHandler = new Handler(context.getMainLooper()) {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_EXEC_PENDING_BROADCASTS:// 调用executePendingBroadcasts方法来执行挂起的广播executePendingBroadcasts(); break;default:super.handleMessage(msg);}}};}//关键流程:step3private void executePendingBroadcasts() {while (true) {BroadcastRecord[] brs = null;synchronized (mReceivers) {// 获取挂起广播的数量final int N = mPendingBroadcasts.size();// 如果没有挂起的广播,退出方法if (N <= 0) {return;}// 创建一个数组来存储挂起的广播记录brs = new BroadcastRecord[N];// 将挂起的广播记录复制到数组中mPendingBroadcasts.toArray(brs);// 清空挂起的广播列表mPendingBroadcasts.clear();}// 遍历所有挂起的广播记录for (int i = 0; i < brs.length; i++) {BroadcastRecord br = brs[i];// 遍历广播记录中的所有接收器for (int j = 0; j < br.receivers.size(); j++) {// 获取ReceiverRecordReceiverRecord receiverRecord = br.receivers.get(j);// 调用BroadcastReceiver的onReceive方法receiverRecord.receiver.onReceive(mAppContext, br.intent);}}}}

sendBroadcast方法通过匹配Intent和IntentFilter来找到所有感兴趣的BroadcastReceiver,并将它们添加到待处理列表中。然后,它使用Handler来异步执行这些广播,确保广播的发送不会阻塞当前线程。这种方法允许LocalBroadcastManager在应用内部高效地分发本地广播。

sendBroadcast最后是通过handler消息机制调用executePendingBroadcasts方法来完成处理的,方法负责执行所有挂起的本地广播。它通过遍历挂起的广播列表,为每个广播调用相应的BroadcastReceiver的onReceive方法。这个方法确保了所有本地广播都能被正确处理,即使在主线程繁忙时也能异步执行。

2.4.2 sendBroadcastSync方法解读

同步发送广播流程为sendBroadcastSync方法,代码实现如下:

//LocalBroadcastManagerpublic void sendBroadcastSync(Intent intent) {// 首先,尝试异步发送广播if (sendBroadcast(intent)) {// 如果sendBroadcast方法返回true,表示广播已经成功放入待处理队列// 然后,调用executePendingBroadcasts方法来同步执行所有挂起的广播executePendingBroadcasts();}}

sendBroadcastSync方法提供了一个同步发送本地广播的机制。与sendBroadcast方法不同,sendBroadcastSync会立即执行挂起的广播,而不是将它们放入消息队列等待主线程处理。这确保了广播的接收器能够立即接收到广播,这对于需要快速响应的场景非常有用。

这种方法的同步特性意味着它可能会阻塞当前线程,直到所有挂起的广播都被处理完毕。因此,在使用sendBroadcastSync时需要谨慎,以避免在主线程中引起不必要的延迟。通常,sendBroadcastSync用于测试或后台线程中,以确保广播能够立即被处理。

2.4.3 sendBroadcastSyncsendBroadcast的区别

两者的区别主要有以下几点:

  • 同步执行sendBroadcastSync方法在发送广播后,会立即调用executePendingBroadcasts方法来同步执行所有挂起的广播。这意味着BroadcastReceiveronReceive方法会在当前方法调用栈中被执行,而不是被放入消息队列等待。sendBroadcast方法则需要消息等待。
  • 立即响应:使用sendBroadcastSync可以确保广播的接收器立即接收到广播,这对于需要快速响应的事件处理非常重要。
  • 阻塞性sendBroadcastSync可能会导致当前线程阻塞,直到所有挂起的广播都被处理完毕,因为它是同步执行的。而sendBroadcast是异步的。
  • 适用场景sendBroadcastSync适用于那些需要立即处理广播的场景,而sendBroadcast则适用于那些可以异步处理广播的场景。

总之,sendBroadcastSync方法提供了一种机制,允许应用在发送本地广播后立即同步处理这些广播,而不是等待主线程的消息队列中的其他消息。这与sendBroadcast方法形成对比,后者是异步的,它将广播放入消息队列中,等待主线程在适当的时候处理。选择使用哪种方法取决于应用的具体需求,是否需要立即处理广播或者可以容忍一定的延迟。

相关文章:

Android Framework AMS(13)广播组件分析-4(LocalBroadcastManager注册/注销/广播发送处理流程解读)

该系列文章总纲链接&#xff1a;专题总纲目录 Android Framework 总纲 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节主要解读广播组件的广播发送过程。关注思维导图中左上侧部分即可。 有了前面普通广播组件 注册/注销程/广播组件的发送广播流程分析的基础&…...

模糊理论与模糊集概述

1. 模糊集 1️⃣ μ A : U → [ 0 , 1 ] \mu_A:U\to{[0,1]} μA​:U→[0,1]&#xff0c;将任意 u ∈ U u\in{}U u∈U映射到 [ 0 , 1 ] [0,1] [0,1]上的某个函数 模糊集&#xff1a; A { μ A ( u ) , u ∈ U } A\{\mu_A(u),u\in{}U\} A{μA​(u),u∈U}称为 U U U上的一个模糊集…...

基于STM32的实时时钟(RTC)教学

引言 实时时钟&#xff08;RTC&#xff09;是微控制器中的一种重要功能&#xff0c;能够持续跟踪当前时间和日期。在许多应用中&#xff0c;RTC用于记录时间戳、定时操作等。本文将指导您如何使用STM32开发板实现RTC功能&#xff0c;通过示例代码实现当前时间的读取和显示。 环…...

Caffeine Cache解析(三):BoundedBuffer 与 MpscGrowableArrayQueue 源码浅析

接续 Caffeine Cache解析(一)&#xff1a;接口设计与TinyLFU 接续 Caffeine Cache解析(二)&#xff1a;drainStatus多线程状态流转 BoundedBuffer 与 MpscGrowableArrayQueue multiple-producer / single-consumer 这里multiple和single指的是并发数量 BoundedBuffer: Caf…...

全双工通信协议WebSocket——使用WebSocket实现智能学习助手/聊天室功能

一.什么是WebSocket&#xff1f; WebSocket是基于TCP的一种新的网络协议。它实现了浏览器与服务器的全双工通信——浏览器和服务器只需要完成一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c;并进行双向数据传输 HTTP 协议是一种无状态的、无连接的、单向的应用…...

Rust-Trait 特征编程

昨夜江边春水生&#xff0c;艨艟巨舰一毛轻。 向来枉费推移力&#xff0c;此日中流自在行。 ——《活水亭观书有感二首其二》宋朱熹 【哲理】往日舟大水浅&#xff0c;众人使劲推船&#xff0c;也是白费力气&#xff0c;而此时春水猛涨&#xff0c;巨舰却自由自在地飘行在水流中…...

彻底理解哈希表(HashTable)结构

目录 介绍优缺点概念哈希函数快速的计算键类型键转索引霍纳法则 均匀的分布 哈希冲突链地址法开放地址法线性探测二次探测再哈希法 扩容/缩容实现哈希创建哈希表质数判断哈希函数插入&修改获取数据删除数据扩容/缩容函数全部代码 哈希表&#xff08;Hash Table&#xff09;…...

微信小程序的汽车维修预约管理系统

文章目录 项目介绍具体实现截图技术介绍mvc设计模式小程序框架以及目录结构介绍错误处理和异常处理java类核心代码部分展示详细视频演示源码获取 项目介绍 系统功能简述 前台用于实现用户在页面上的各种操作&#xff0c;同时在个人中心显示各种操作所产生的记录&#xff1a;后…...

LeetCode:3255. 长度为 K 的子数组的能量值 II(模拟 Java)

目录 3255. 长度为 K 的子数组的能量值 II 题目描述&#xff1a; 实现代码与解析&#xff1a; 模拟 原理思路&#xff1a; 3255. 长度为 K 的子数组的能量值 II 题目描述&#xff1a; 给你一个长度为 n 的整数数组 nums 和一个正整数 k 。 一个数组的 能量值 定义为&am…...

深入了解逻辑回归:机器学习中的经典算法

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

软件测试基础十三(python 函数)

函数 1. 函数的意义 代码复用 提高效率&#xff1a;Python中的函数允许将一段可重复使用的代码封装起来。例如&#xff0c;在一个数据分析项目中&#xff0c;可能需要多次计算一组数据的平均值。可以将计算平均值的代码定义为一个函数&#xff1a; def calculate_average(nu…...

计算机网络——HTTP篇

基础篇 IOS七层网络模型 TCP/IP四层模型&#xff1f; 应⽤层&#xff1a;位于传输层之上&#xff0c;主要提供两个终端设备上的应⽤程序之间的通信&#xff0c;它定义了信息交换的格式&#xff0c;消息会交给下⼀层传输层来传输。 传输层的主要任务就是负责向两台设备进程之间…...

信息化运维方案,实施方案,开发方案,信息中心安全运维资料(软件资料word)

1 编制目的 2 系统运行维护 2.1 系统运维内容 2.2 日常运行维护方案 2.2.1 日常巡检 2.2.2 状态监控 2.2.3 系统优化 2.2.4 软件系统问题处理及升级 2.2.5 系统数据库管理维护 2.2.6 灾难恢复 2.3 应急运行维护方案 2.3.1 启动应急流程 2.3.2 成立应急小组 2.3.3 应急处理过程 …...

自动化工具 Gulp

自动化工具 gulp 摘要 概念&#xff1a;gulp用于自动化开发流程。 理解&#xff1a;我们只需要编写任务&#xff0c;然后gulp帮我们执行 核心概念&#xff1a; 任务&#xff1a;通过定义不同的任务来组织你的构建流程。 管道&#xff1a;通过管道方式将文件从一个插件传递…...

css实现div被图片撑开

固定好盒子的宽度&#xff0c;高度随传过来的图片大小决定 <div class"tab-con"> <img:src"concertInfo.detail"alt""> </div>.tab-con {margin-bottom: 20px;width: 700px;img {width: 700px;height: auto;object-fit: cont…...

Power Pivot、Power BI 和 SQL Server Analysis Services 的公式语言:DAX(数据分析表达式)

DAX&#xff08;Data Analysis Expressions&#xff09;是一种用于 Power Pivot、Power BI 和 SQL Server Analysis Services 的公式语言&#xff0c;旨在帮助用户进行数据建模和复杂计算。DAX 的设计初衷是使数据分析变得简单而高效&#xff0c;特别是在处理数据模型中的表关系…...

大模型应用编排工具Dify二开之工具和模型页面改造

1.前言 简要介绍下 dify&#xff1a; ​ 一款可以对接市面上主流大模型的任务编排工具&#xff0c;可以通过拖拽形式进行编排形成解决某些业务场景的大模型应用。 背景信息&#xff1a; ​ 环境&#xff1a;dify-0.8.3、docker-21 ​ 最近笔者在做 dify的私有化部署和二次…...

Pytorch用BERT对CoLA、新闻组文本数据集自然语言处理NLP:主题分类建模微调可视化分析...

原文链接&#xff1a;https://tecdat.cn/?p38181 自然语言处理&#xff08;NLP&#xff09;领域在近年来发展迅猛&#xff0c;尤其是预训练模型的出现带来了重大变革。其中&#xff0c;BERT 模型凭借其卓越性能备受瞩目。然而&#xff0c;对于许多研究者而言&#xff0c;如何高…...

LightGBM-GPU不能装在WSL,能装在windows上

这是一篇经验总结文章&#xff0c;注重思路&#xff0c;忽略细节。 1.起因 用多个机器学习方法训练模型&#xff0c;比较性能&#xff0c;发现Light GBM方法获得的性能明显更高&#xff0c;但问题是在CPU上训练的速度特别特别慢&#xff0c;需要用GPU训练。 2.开始装LightGB…...

工业相机常用功能之白平衡及C++代码分享

目录 1、白平衡的概念解析 2、相机白平衡参数及操作 2.1 相机白平衡参数 2.2 自动白平衡操作 2.3 手动白平衡操作流程 3、C++ 代码从XML读取参数及设置相机参数 3.1 读取XML 3.2 C++代码,从XML读取参数 3.3 给相机设置参数 1、白平衡的概念解析 白平衡(White Balance)…...

IfcOpenShell技术架构深度解析:开源IFC引擎的模块化设计与高性能实现

IfcOpenShell技术架构深度解析&#xff1a;开源IFC引擎的模块化设计与高性能实现 【免费下载链接】IfcOpenShell Open source IFC library and geometry engine 项目地址: https://gitcode.com/gh_mirrors/if/IfcOpenShell IfcOpenShell作为开源建筑信息模型&#xff08…...

告别虚拟机卡顿:在Ubuntu 18.04上为ARM板交叉编译Qt5.12.9的完整配置流程

突破虚拟机性能瓶颈&#xff1a;Ubuntu 18.04下高效交叉编译Qt5.12.9的工程实践 当你在40GB磁盘空间的Ubuntu虚拟机上尝试编译Qt5.12.9时&#xff0c;解压后的2.8GB源码目录和漫长的编译等待时间可能已经让你抓狂。这不是个例——嵌入式开发工程师经常面临这样的困境&#xff1…...

最火的知识付费系统小程序+PC+H5三端数据互通支持采集资源开源版

内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍 系统含带 裂变模式 可以助力好友来获取资源共享 分站功能 独立后台 会员功能 卡密功能 二级分销功能等 自行研究看 后期有更新新版会在持续发布 目前版本是3.5 是我花三天时间修复的 好多…...

用PyTorch复现BCNet息肉分割模型:从论文到代码的保姆级实践指南

用PyTorch复现BCNet息肉分割模型&#xff1a;从论文到代码的保姆级实践指南 医学影像分析领域&#xff0c;息肉分割一直是内窥镜诊断的关键技术。传统方法依赖医生手动标注&#xff0c;效率低下且易受主观因素影响。近年来&#xff0c;深度学习在医学图像分割领域展现出强大潜…...

IS6201A多相PWM控制器:从架构解析到PCB布局的电源设计实战

1. 项目概述&#xff1a;为什么我们需要关注IS6201A&#xff1f;在电源设计领域&#xff0c;尤其是面对高性能计算、数据中心服务器、高端显卡以及工业自动化设备时&#xff0c;工程师们常常面临一个核心挑战&#xff1a;如何为那些“电老虎”级别的核心芯片&#xff08;比如CP…...

用Python重写‘估值一亿的AI核心代码’:聊聊正则表达式与字符串处理的优雅解法

Python重构估值一亿的AI核心代码&#xff1a;正则表达式与字符串处理的优雅实践 当我们需要处理复杂的文本规则时&#xff0c;不同编程语言会展现出截然不同的解决思路。本文将以PTA L1-064题目为例&#xff0c;展示如何用Python的正则表达式和字符串处理方法&#xff0c;优雅地…...

Ecco架构:突破LLM推理内存墙的熵编码优化方案

1. Ecco架构&#xff1a;突破LLM推理的内存墙在A100 GPU上运行LLaMA-70B模型时&#xff0c;仅权重参数就占用140GB显存&#xff0c;而HBM带宽仅有2TB/s——这就是典型的"内存墙"问题。传统解决方案如量化会损失精度&#xff0c;而单纯增加硬件成本又面临边际效益递减…...

告别龟速下载!Windows下用VSCode离线包5分钟搞定ESP-IDF环境(附镜像加速)

5分钟极速部署&#xff1a;Windows下VSCode与ESP-IDF开发环境实战指南 当第一次接触ESP32开发时&#xff0c;许多开发者都会遇到一个共同的难题——官方工具链的下载速度慢如蜗牛。这不仅浪费宝贵时间&#xff0c;还可能让初学者在配置阶段就失去耐心。本文将分享一套经过实战…...

C#上位机开发工业机器人:从零搭建第一个机器人控制程序

作为一名在工控行业摸爬滚打了十年的老工程师,我见过太多自动化工程师卡在"机器人上位机开发"这一关。很多人C#基础不错,也懂机器人原理,但就是不知道怎么把两者结合起来,写出一个能在生产环境运行的控制程序。 今天这篇文章,我会带着你从零开始,搭建一个完整…...

PHP SimpleXML:深入解析与高效使用

PHP SimpleXML:深入解析与高效使用 引言 PHP 是一种广泛使用的服务器端脚本语言,它以其灵活性和强大的功能而闻名。在处理 XML 数据时,PHP 提供了多种方法,其中 SimpleXML 是一个简单且强大的库,它允许开发者轻松地解析和操作 XML 数据。本文将深入探讨 PHP SimpleXML 的…...