当前位置: 首页 > 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)…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析&#xff0c;分为​​已启动​​和​​未启动​​两种场景&#xff1a; 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​&#xff1a;当其他组件&#xff08;如Activity、Service&#xff09;通过ContentR…...

windows系统MySQL安装文档

概览&#xff1a;本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容&#xff0c;为学习者提供全面的操作指导。关键要点包括&#xff1a; 解压 &#xff1a;下载完成后解压压缩包&#xff0c;得到MySQL 8.…...

若依登录用户名和密码加密

/*** 获取公钥&#xff1a;前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...