【Android】广播机制

【Android】广播机制

前言

广播机制是Android中一种非常重要的通信机制,用于在应用程序之间或应用程序的不同组件之间传递信息。广播可以是系统广播,也可以是自定义广播。广播机制主要包括标准广播和有序广播两种类型。

简介

在Android中,广播(Broadcast)是一种消息,任何应用程序都可以发送广播消息,任何应用程序也都可以接收广播消息。广播通常用于通知应用程序某些事件的发生,比如系统启动、电量低、网络状态改变等。

广播的主要组件包括:

  • Broadcast Receiver(广播接收器):用于接收广播消息并响应这些消息的组件。
  • Intent(意图):用于传递广播消息的数据结构。
  1. 标准广播:

    标准广播(Normal Broadcast)是完全异步的,所有接收器几乎同时接收广播,并且接收顺序是不确定的。标准广播的特点是速度快,因为它们不需要等待其他接收器处理完广播才能继续传递。

    image-20240723203035435

  2. 有序广播:

    有序广播(Ordered Broadcast)是同步的,一个接收器接收到广播并处理完后,广播才会继续传递给下一个接收器。接收器可以修改广播的数据或截断广播,使其不再传递给其他接收器。有序广播允许通过设置优先级来控制接收器的接收顺序,优先级高的接收器会先接收广播。

    image-20240723203247638

接收系统广播

监听网络变化

先新建BroadcastTest项目,修改MainActivity

public class MainActivity extends AppCompatActivity {private IntentFilter intentFilter; // 意图过滤器,用于监听特定广播事件private NetworkChangeReceiver networkChangeReceiver; // 广播接收器实例@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main); // 设置布局文件intentFilter = new IntentFilter();intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); // 添加网络连接变化的广播事件networkChangeReceiver = new NetworkChangeReceiver(); // 初始化广播接收器registerReceiver(networkChangeReceiver, intentFilter); // 注册广播接收器}@Overrideprotected void onDestroy() {super.onDestroy();unregisterReceiver(networkChangeReceiver); // 注销广播接收器}class NetworkChangeReceiver extends BroadcastReceiver { // 内部类,继承自BroadcastReceiver@Overridepublic void onReceive(Context context, Intent intent) {Toast.makeText(context, "network changes", Toast.LENGTH_SHORT).show(); // 网络变化时显示提示信息}}
}

动态注册的广播一定都要取消注册

取消注册原因:

防止内存泄漏

  • 如果广播接收器在不需要时未被注销,它会持有对 Context 的引用,可能会导致内存泄漏。特别是在 ActivityService 中,如果它们被销毁后广播接收器仍然存在,会导致这些组件无法被垃圾回收器回收,进而占用系统资源。

避免不必要的资源消耗

  • 如果不注销广播接收器,它仍然会继续接收广播,即使相关的 ActivityService 已经不再需要这些广播。这会导致不必要的系统资源消耗,因为每次接收到广播时都会触发 onReceive 方法的执行。

防止潜在的崩溃

  • 在一些情况下,如果广播接收器在 ActivityService 销毁后继续接收广播,可能会导致应用程序崩溃。例如,如果 onReceive 方法中试图访问已销毁的 Activity 的 UI 元素,会引发 NullPointerException 等异常。

良好的编程实践

  • 注销广播接收器是一种良好的编程习惯,有助于保持代码的整洁和可靠性。它确保每个资源都被合理管理和释放,避免因资源管理不当而导致的各种问题。

上面的代码只能提示网络是否变化,可以对上面的代码进行优化

public class MainActivity extends AppCompatActivity {private IntentFilter intentFilter; // 意图过滤器,用于监听特定广播事件private NetworkChangeReceiver networkChangeReceiver; // 广播接收器实例@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main); // 设置布局文件intentFilter = new IntentFilter();intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); // 添加网络连接变化的广播事件networkChangeReceiver = new NetworkChangeReceiver(); // 初始化广播接收器registerReceiver(networkChangeReceiver, intentFilter); // 注册广播接收器}@Overrideprotected void onDestroy() {super.onDestroy();unregisterReceiver(networkChangeReceiver); // 注销广播接收器}class NetworkChangeReceiver extends BroadcastReceiver { // 内部类,继承自BroadcastReceiver@Overridepublic void onReceive(Context context, Intent intent) {ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); // 获取连接管理器NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); // 获取当前活动的网络信息if (networkInfo != null && networkInfo.isAvailable()) { // 检查网络是否可用Toast.makeText(context, "network is available", Toast.LENGTH_SHORT).show(); // 网络可用时显示提示信息} else {Toast.makeText(context, "network is unavailable", Toast.LENGTH_SHORT).show(); // 网络不可用时显示提示信息}}}
}

就可以显式网络是否连接了

静态注册实现开机启动

先在com/example/boardcasttest包下点击New→Other→Broadcast Receiver,修改名字为BootCompleteReceiver并且勾选Exported(是否允许这个广播接收器接收本程序以外的广播),Enabled(表示是否启用这个广播接收器)创建完成

修改BootCompleteReceiver中的代码:

class NetworkChangeReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {Toast.makeText(context, "Boot Complete", Toast.LENGTH_SHORT).show();}
}

此外还需要在AndroidManifest文件中注册,但是由于我们使用的是快捷方式创建,所以这一步已经被自动完成了:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.BoardcastTest"tools:targetApi="31"><receiverandroid:name=".BootCompleteReceiver"android:enabled="true"android:exported="true"></receiver><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

新建了一个标签<receiver>

但是目前还是接收不到开机广播,需要对AndroidManifest进行修改:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>//<applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.BoardcastTest"tools:targetApi="31"><receiverandroid:name=".BootCompleteReceiver"android:enabled="true"android:exported="true"><intent-filter><action android:name="android.intent.action.BOOT_COMPLETED"/>//</intent-filter></receiver><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

重新运行后就可以接收开机广播了

自定义广播

发送标准广播

首先需要定义一个广播接收器接收广播,新建MyBroadcastReceiver

public class MyBroadcastReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show();}
}

修改AndroidManifest中的代码:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/><applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.BoardcastTest"tools:targetApi="31"><receiverandroid:name=".BootCompleteReceiver"android:enabled="true"android:exported="true"><intent-filter><action android:name="com.example.broadcasttest.MY_BROADCAST"/>//</intent-filter></receiver><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

我们让MyBroadcastReceiver接收值为`的广播

修改activity_main中的代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/button"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Send BoardCast"/></LinearLayout>

定义了一个按钮用于作为发送广播的触发点

修改MainActivity中的代码:

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button button = (Button) findViewById(R.id.button);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");intent.setPackage(getPackageName());sendBroadcast(intent);}});}
}

首先创建intent对象,将要发送的广播的值传入,然后调用sendBroadcast()进行发送,我们之前设置的接收器就可以接收到广播了

还要注意的是setPackage的作用是指定这条广播发送给哪个程序,使得隐式广播转化为显式广播。因为Android8.0以后,静态注册的BroadcastReceiver是无法接受广播的

发送有序广播

修改MainActivity中的代码:

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button button = (Button) findViewById(R.id.button);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");sendOrderedBroadcast(intent, null);}});}
}

我们将sendBroadcast()方法改成了sendOrderedBroadcast()

新建一个类AnotherBroadcastReceiver继承BroadcastReceiver:

public class AnotherBroadcastReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {Toast.makeText(context, "receciver in AnotherBroadcastReceiver", Toast.LENGTH_SHORT).show();abortBroadcast();//表示截断广播}
}

修改AndroidManifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/><applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.BoardcastTest"tools:targetApi="31"><receiverandroid:name=".MyBroadcastReceiver"android:enabled="true"android:exported="true"><intent-filter><action android:name="com.example.broadcasttest.MY_BROADCAST"/></intent-filter></receiver><receiverandroid:name=".AnotherBroadcastReceiver"android:enabled="true"android:exported="true"><intent-filter android:priority="100"><action android:name="com.example.broadcasttest.MY_BROADCAST"/></intent-filter></receiver><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

可以通过修改

<intent-filter android:priority="100">

来确定接收广播的优先级,数字大的先接收

使用本地广播

public class MainActivity extends AppCompatActivity {private IntentFilter intentFilter; // 意图过滤器,用于监听特定广播事件private LocalReceiver localReceiver; // 本地广播接收器实例private LocalBroadcastManager localBroadcastManager; // 本地广播管理器实例@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main); // 设置布局文件localBroadcastManager = LocalBroadcastManager.getInstance(this); // 获取本地广播管理器实例// 获取按钮并设置点击监听器Button button = (Button) findViewById(R.id.button);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 创建一个意图,并通过本地广播发送Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");localBroadcastManager.sendBroadcast(intent);}});// 初始化意图过滤器,并添加广播事件intentFilter = new IntentFilter();intentFilter.addAction("com.example.broadcasttest.MY_BROADCAST");// 初始化本地广播接收器localReceiver = new LocalReceiver();// 注册本地广播接收器localBroadcastManager.registerReceiver(localReceiver, intentFilter);}@Overrideprotected void onDestroy() {super.onDestroy();// 注销本地广播接收器localBroadcastManager.unregisterReceiver(localReceiver);}// 定义本地广播接收器类,继承自BroadcastReceiverclass LocalReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {// 接收到本地广播时显示提示信息Toast.makeText(context, "received local broadcast", Toast.LENGTH_SHORT).show();}}
}

广播的最佳实践——强制下线功能

先创建一个ActivityCollector类管理所有活动

public class ActivityCollector {public static List<Activity>  activities = new ArrayList<>();public static void addActivity(Activity activity) {activities.add(activity);}public static void removeActivity(Activity activity) {activities.remove(activity);}public static void finishAll() {for (Activity activity : activities) {if (!activity.isFinishing()) {activity.finish();}}activities.clear();}
}

然后创建BaseActivity类作为所有活动的父类

public class BaseActivity extends AppCompatActivity {@Overridepublic void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {super.onCreate(savedInstanceState, persistentState);ActivityCollector.addActivity(this);}@Overrideprotected void onDestroy() {super.onDestroy();ActivityCollector.removeActivity(this);}
}

创建LoginActivity,并自动生成activity_login布局文件,修改如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:orientation="horizontal"android:layout_width="match_parent"android:layout_height="60dp"><TextViewandroid:layout_width="90dp"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:text="Account:"android:textSize="18sp"/><EditTextandroid:id="@+id/account"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:layout_gravity="center_vertical"/></LinearLayout><LinearLayoutandroid:orientation="horizontal"android:layout_width="match_parent"android:layout_height="60dp"><TextViewandroid:layout_width="90dp"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:text="Password:"android:textSize="18sp"/><EditTextandroid:id="@+id/password"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:layout_gravity="center_vertical"/></LinearLayout><Buttonandroid:id="@+id/login"android:layout_width="match_parent"android:layout_height="60dp"android:text="Login"/></LinearLayout>

这个布局就不多做解释了

下来修改LoginActivity中的代码:

public class LogActivity extends BaseActivity {private EditText accountEdit;private EditText passwordEdit;private Button login;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_log);accountEdit = (EditText) findViewById(R.id.account);passwordEdit = (EditText) findViewById(R.id.password);login = (Button) findViewById(R.id.login);login.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String account = accountEdit.getText().toString();String password = passwordEdit.getText().toString();if (account.equals("123") && password.equals("123")) {Intent intent = new Intent(LogActivity.this, MainActivity.class);startActivity(intent);finish();} else {Toast.makeText(LogActivity.this, "account or password is invalid", Toast.LENGTH_SHORT).show();}}});}
}

模拟了一个点单的登录功能,账号为123且密码为123则登陆成功,跳转到MainActivity

下来修改activity_main中的代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/main"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/force_offline"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Send force offline broadcast"/></LinearLayout>

只用实现一个按钮用来触发强制下线功能

修改MainActivity中的代码:

public class MainActivity extends BaseActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button forceOffline = (Button) findViewById(R.id.force_offline);forceOffline.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent("com.example.broadcastbestpractice.FORCE_OFFLINE");intent.setPackage(getPackageName());sendBroadcast(intent);}});}
}

其中come.example.broadcastbestpractice.FORCE_OFFLINE是用来通知程序强制下线的

下来需要创建广播接收器来接收广播,但是如果创建一个静态注册的广播接收器是没有办法在onReceive()里弹出对话框那样的UI控件,是不现实的

我们只需要在BaseActivity中动态注册一个广播接收器就可以了,因为所有活动继承自BaseActivity

修改BaseActivity中的代码:

public class BaseActivity extends AppCompatActivity {private ForceOfflineReceiver receiver; // 广播接收器实例@Overridepublic void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {super.onCreate(savedInstanceState, persistentState);ActivityCollector.addActivity(this); // 将活动添加到活动管理器中}@Overrideprotected void onDestroy() {super.onDestroy();ActivityCollector.removeActivity(this); // 将活动从活动管理器中移除}@Overrideprotected void onResume() {super.onResume();IntentFilter intentFilter = new IntentFilter();intentFilter.addAction("com.example.broadcastbestpractice.FORCE_OFFLINE"); // 添加广播事件receiver = new ForceOfflineReceiver(); // 初始化广播接收器registerReceiver(receiver, intentFilter); // 注册广播接收器}@Overrideprotected void onPause() {super.onPause();if(receiver != null) {unregisterReceiver(receiver); // 注销广播接收器receiver = null; // 将接收器置为空}}class ForceOfflineReceiver extends BroadcastReceiver { // 定义内部类,继承自BroadcastReceiver@Overridepublic void onReceive(final Context context, Intent intent) {AlertDialog.Builder builder = new AlertDialog.Builder(context);builder.setTitle("Warning"); // 设置对话框标题builder.setMessage("You are forced to be offline!"); // 设置对话框消息builder.setCancelable(false); // 设置对话框不可取消builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { // 设置对话框确认按钮@Overridepublic void onClick(DialogInterface dialog, int which) {ActivityCollector.finishAll(); // 关闭所有活动Intent i = new Intent(context, LogActivity.class); // 创建意图,启动LogActivitycontext.startActivity(i); // 启动LogActivity}});builder.show(); // 显示对话框}}
}

下来对AndroidManifest文件进行修改:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.BroadcastBestPractice"tools:targetApi="31"><activity android:name=".MainActivity" ></activity><activity android:name=".LogActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

完成了所有代码,当我们登录后点击按钮,就可以实现强制退出了。

下面是实现的效果:

image-20240724212643794

image-20240724212732409

image-20240724212748833


已经到底啦!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/49830.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Istio_01_Istio初识

文章目录 IstioService Mesh Istio Istio: 以服务网格形态用于服务治理的开放平台和基础设施 本质: 以非侵入式治理服务之间的访问和调用服务治理: 流量管理、可观测性、安全性可同时管理多类基础设施(多种网络方案) 如: Istio和Kubernetes架构的结合 Istio通过Kubernetes的域…

Ubuntu 重置root密码

Ubuntu 重置root密码 当系统管理员或者授权用户忘记了root密码时&#xff0c;重置密码能够提供紧急访问系统的方法。这种情况下&#xff0c;重置密码可以避免因为密码丢失而导致的系统无法访问的问题&#xff0c;确保及时的操作和维护。在进行系统安全审计或者需要紧急恢复访问…

【学一点儿前端】getaddrinfo ENOTFOUND registry.nlark.com“.

问题 今天jenkins打包一个项目&#xff0c;发现报错了 error An unexpected error occurred: "https://registry.nlark.com/xxxxxxxxxx.tgz: getaddrinfo ENOTFOUND registry.nlark.com". 先写解决方案 把yarn.lock文件里面的registry.nlark.com替换为registry.npmmi…

<数据集>抽烟识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;4860张 标注数量(xml文件个数)&#xff1a;4860 标注数量(txt文件个数)&#xff1a;4860 标注类别数&#xff1a;1 标注类别名称&#xff1a;[smoking] 使用标注工具&#xff1a;labelImg 标注规则&#xff1a;对…

【时间动作定位】End-to-end Temporal Action Detection with Transformer 论文阅读

End-to-end Temporal Action Detection with Transformer 论文阅读 AbstractI. INTRODUCTIONII. RELATED WORKIII. TADTRA. ArchitectureB. Training and Inference IV. EXPERIMENTSV. CONCLUSION 文章信息&#xff1a; 发表于&#xff1a; IEEE Transactions on Image Proce…

四、GD32 MCU 常见外设介绍 (7) 7.I2C 模块介绍

7.1.I2C 基础知识 I2C(Inter-Integrated Circuit)总线是一种由Philips公司开发的两线式串行总线&#xff0c;用于内部IC控制的具有多端控制能力的双线双向串行数据总线系统&#xff0c;能够用于替代标准的并行总线&#xff0c;连接各种集成 电路和功能模块。I2C器件能够减少电…

整合StarRocks主键表全部知识点

总结StarRocks主键表的全部内容的集合&#xff08;V3.2版本&#xff09; 一、基本功能 主键非空约束&#xff0c;任何一个字段都不可以为空支持导入数据时删除数据操作(CDC)支持部分更新支持独立的排序键&#xff08;只有主键表支持独立排序键&#xff0c;而且可以不为key键&…

极限科技闪耀 2024 可信数据库发展大会,多款自研产品引领搜索技术新纪元

北京&#xff0c;7 月 16、17 日 —— 在由中国信息通信研究院&#xff08;中国信通院&#xff09;与中国通信标准化协会联合主办&#xff0c;InfoQ 协办的“2024 可信数据库发展大会”&#xff08;TDBC 2024&#xff09;上&#xff0c;极限科技凭借其前沿的搜索技术创新与卓越…

【相机与图像】1. 相机模型的介绍:内参、外参、畸变参数

想着整理下相机模型&#xff08;内容上参考 slam十四讲&#xff09;、相机的内外参标定。方便自己的使用和回顾。 不过&#xff0c;内外参标定啥时候记录随缘 -_- 概述 【构建相机模型】 相机将三位世界中的坐标点&#xff08;单位为米&#xff09;映射到二维图像平面&#xff…

py Qt5学习记录

1.Qt5的安装 可参考一些博客如&#xff1a;Python 小白从零开始 PyQt5 项目实战&#xff08;2&#xff09;菜单和工具栏_pyqt 二级菜单-CSDN博客 2.Qt5的界面显示 3.新建一个工具栏并打开本地文件方法 &#xff08;1&#xff09;在Qt5界面右下角有个“动作编辑器”&#xff…

每日一题~961div2A+B+C(阅读题,思维,数学log)

A 题意&#xff1a;给你 n*n 的表格和k 个筹码。每个格子上至多放一个 问至少占据多少对角线。 显然&#xff0c;要先 格数的多的格子去放。 n n-1 n-2 …1 只有n 的是一个&#xff08;主对角线&#xff09;&#xff0c;其他的是两个。 #include <bits/stdc.h> using na…

基于微信小程序图书馆座位预约管理系统设计与实现

1.1选题动因 当前的网络技术&#xff0c;软件技术等都具备成熟的理论基础&#xff0c;市场上也出现各种技术开发的软件&#xff0c;这些软件都被用于各个领域&#xff0c;包括生活和工作的领域。随着电脑和笔记本的广泛运用&#xff0c;以及各种计算机硬件的完善和升级&#x…

JS 事件循环(Event Loop)机制

事件循环机制的作用 事件循环机制是 JS 的一种执行机制&#xff0c;一种可以实现异步编程的机制。 因为 JS 是单线程的&#xff0c;单线程意味着所有任务需要排队执行。但是有一些 API&#xff08;比如&#xff1a;定时器和 Ajax 等&#xff09;是需要等待一定的时间才能得到…

【Python】一文向您详细介绍 K-means 算法

【Python】一文向您详细介绍 K-means 算法 下滑即可查看博客内容 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地&#xff01;&#x1f387; &#x1f393; 博主简介&#xff1a;985高校的普通本硕&#xff…

Visual Studio 2022新建 cmake 工程测试 tensorRT 自带样例 sampleOnnxMNIST

1. 新建 cmake 工程 vs2022_cmake_sampleOnnxMNIST_test( 如何新建 cmake 工程&#xff0c;请参考博客&#xff1a;Visual Studio 2022新建 cmake 工程测试 opencv helloworld ) 2. 删除默认生成的 vs2022_cmake_sampleOnnxMNIST_test.h 头文件 3. 修改默认生成的 vs2022_cma…

BSV区块链在人工智能时代的数字化转型中的角色

​​发表时间&#xff1a;2024年6月13日 企业数字化转型已有约30年的历史&#xff0c;而人工智能&#xff08;以下简称AI&#xff09;将这种转型提升到了一个全新的高度。这并不难理解&#xff0c;因为AI终于使企业能够发挥其潜力&#xff0c;实现更宏大的目标。然而&#xff0…

MySQL中实现动态表单中JSON元素精准匹配的方法

目录 前言 一、动态表单技术 1、包含的主要信息 2、元素属性设置 3、表单内容 二、表单数据存储和查询 1、数据存储 2、数据的查询 3、在5.7版本中进行JSON检索 4、8.0后的优化查询 三、总结 前言 在很多有工作流设置的地方、比如需要在不同的流程中&#xff0c;需要…

服务器数据恢复—V7000存储硬盘故障脱机的数据恢复案例

服务器存储数据恢复环境&#xff1a; 某品牌P740小型机AIXSybaseV7000磁盘阵列柜&#xff0c;磁盘阵列柜中有12块SAS机械硬盘&#xff08;其中包括一块热备盘&#xff09;。 服务器存储故障&#xff1a; 磁盘阵列柜中有一块磁盘出现故障&#xff0c;运维人员用新硬盘替换掉故障…

网络安全等级保护解决方案的主打产品

网络安全等级保护解决方案的主打产品&#xff1a; HiSec Insight安全态势感知系统、 FireHunter6000沙箱、 SecoManager安全控制器、 HiSecEngine USG系列防火墙和HiSecEngine AntiDDoS防御系统。 华为HiSec Insight安全态势感知系统是基于商用大数据平台FusionInsight的A…

【LeetCode】201. 数字范围按位与

1. 题目 2. 分析 这题挺难想的&#xff0c;我到现在还没想明白&#xff0c;为啥只用左区间和右区间就能找到目标值了&#xff0c;而不用挨个做与操作&#xff1f; 3. 代码 class Solution:def rangeBitwiseAnd(self, left: int, right: int) -> int:left_bin bin(left).…