【Android】广播机制

news2024/11/16 4:23:10

【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; // 广播接收器实例

    @Override
    protected 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); // 注册广播接收器
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver); // 注销广播接收器
    }

    class NetworkChangeReceiver extends BroadcastReceiver { // 内部类,继承自BroadcastReceiver

        @Override
        public 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; // 广播接收器实例

    @Override
    protected 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); // 注册广播接收器
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver); // 注销广播接收器
    }

    class NetworkChangeReceiver extends BroadcastReceiver { // 内部类,继承自BroadcastReceiver

        @Override
        public 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 {
    @Override
	public 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" />
    
    <application
        android: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">
        <receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            
        </receiver>

        <activity
            android: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"/>//
    <application
        android: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">
        <receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>//
            </intent-filter>
        </receiver>

        <activity
            android: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 {
    @Override
    public 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"/>
    <application
        android: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">
        <receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>//
            </intent-filter>
        </receiver>

        <activity
            android: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">

    
    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send BoardCast"/>

</LinearLayout>

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

修改MainActivity中的代码:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public 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 {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public 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 {
    @Override
    public 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"/>
    <application
        android: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">
        <receiver
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>

        <receiver
            android:name=".AnotherBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter android:priority="100">
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>

        <activity
            android: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; // 本地广播管理器实例

    @Override
    protected 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() {
            @Override
            public 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);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 注销本地广播接收器
        localBroadcastManager.unregisterReceiver(localReceiver);
    }

    // 定义本地广播接收器类,继承自BroadcastReceiver
    class LocalReceiver extends BroadcastReceiver {
        @Override
        public 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 {
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
        super.onCreate(savedInstanceState, persistentState);
        ActivityCollector.addActivity(this);
    }

    @Override
    protected 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">

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp">
        <TextView
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:text="Account:"
            android:textSize="18sp"/>

        <EditText
            android:id="@+id/account"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_gravity="center_vertical"/>
    </LinearLayout>
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp">
        <TextView
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:text="Password:"
            android:textSize="18sp"/>

        <EditText
            android:id="@+id/password"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_gravity="center_vertical"/>
    </LinearLayout>

    <Button
        android: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;

    @Override
    protected 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() {
            @Override
            public 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">

    <Button
        android: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 {

    @Override
    protected 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() {
            @Override
            public 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; // 广播接收器实例

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
        super.onCreate(savedInstanceState, persistentState);
        ActivityCollector.addActivity(this); // 将活动添加到活动管理器中
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityCollector.removeActivity(this); // 将活动从活动管理器中移除
    }

    @Override
    protected void onResume() {
        super.onResume();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.broadcastbestpractice.FORCE_OFFLINE"); // 添加广播事件
        receiver = new ForceOfflineReceiver(); // 初始化广播接收器
        registerReceiver(receiver, intentFilter); // 注册广播接收器
    }

    @Override
    protected void onPause() {
        super.onPause();
        if(receiver != null) {
            unregisterReceiver(receiver); // 注销广播接收器
            receiver = null; // 将接收器置为空
        }
    }

    class ForceOfflineReceiver extends BroadcastReceiver { // 定义内部类,继承自BroadcastReceiver
        @Override
        public 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() { // 设置对话框确认按钮
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    ActivityCollector.finishAll(); // 关闭所有活动
                    Intent i = new Intent(context, LogActivity.class); // 创建意图,启动LogActivity
                    context.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">

    <application
        android: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.coloradmin.cn/o/1946732.html

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

相关文章

【学一点儿前端】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…

超低功耗ARM Cortex-M33 TZ MCU STM32WBA54、STM32WBA55:通过提升无线性能实现更出色的用户体验

摘要 STM32WBA54、STM32WBA55产品系列同时支持多种无线标准&#xff0c;包括Bluetooth低功耗 5.4&#xff08;已认证&#xff09;、Zigbee、Thread以及可用作Thread边界路由器的Matter。 该产品系列具有出色的灵活性和更强的安全性&#xff0c;可帮助开发人员应对不断变化的无…

二、QGroundControl开发环境搭建

文章目录 环境列表QGC源码下载编译 环境列表 QGC GithubPX4-AutopilotQt 5.15Ubuntu20.04 QGC源码下载编译 官网下载指令 如下 // Clone the repo (or your fork) including submodules: git clone --recursive -j8 https://github.com/mavlink/qgroundcontrol.git // Upda…

【vluhub】elasticsearch漏洞

Elasticsearch介绍 是Apache旗下的一个开源的、分布式、RESTful的搜索和分析引擎&#xff0c;适用于java语言项目 默认端口9200 kali中搭建ElasticHD, 即可未授权绕过ES可视化界面 直通车 https://github.com/360EntSecGroup-Skylar/ElasticHD/releases/download/1.4/elas…

防火墙——网络环境支持

目录 网络环境支持 防火墙的组网 web连接上防火墙 web管理口 让防火墙接到网络环境中 ​编辑 管理员用户管理 缺省管理员 接口 配置一个普通接口 创建安全区域 路由模式 透明模式 混合模式 防火墙的安全策略 防火墙转发流程 与传统包过滤的区别 创建安全策略 …

新手小白的pytorch学习第十一弹-----Computer Vision创建基础模型使用FashionMNIST

目录 PyTorch Computer Vision0 PyTorch 中 Computer vision 的库1 获得一个数据集1.1 查看数据的输入和输出形状1.2 可视化数据 2 准备 DataLoader3 Model 0: 创建一个 baseline model3.1 设置损失函数、优化器和评估指标3.2 创建一个函数来给我们的实验计时3.3 在批量数据集上…

09-软件易用性

易用性是用户体验的一个重要方面&#xff0c;网站建设者一般会沉溺于自己的思维习惯&#xff0c;而造成用户使用的不畅。易用性不仅是专业UI/UE人员需要研究&#xff0c;对于网站建设其他岗位的人也应该了解一定的方法去检验和提升网站的易用性。通常对易用性有如下定义: 易理解…

书生浦语多模态简述——学习笔记

多模态学习概念 多模态它是研究异构且相互连接数据的科学。它涵盖了从原始的器官信号到抽象概念的多种模态。 比如说我们语音和语言是我们理解人类交流的关键模态&#xff0c;而情感和图像就为我们提供了对环境和对象的感知&#xff0c;通过分析这些模态&#xff0c;我们就可…

视频生成【文章汇总】SVD, Sora, Latte, VideoCrafter12, DiT...

视频生成【文章汇总】SVD, Sora, Latte, VideoCrafter12, DiT... 数据集指标 【arXiv 2024】MiraData: A Large-Scale Video Dataset with Long Durations and Structured Captions【CVPR 2024】VBench : Comprehensive Benchmark Suite for Video Generative Models【arxiv 20…

SpringBoot自动配置(面试重点)

自动配置是指&#xff1a; 自动配置是指在应用程序启动时&#xff0c;SpringBoot根据classpath路径下的jar包自动配置应用程序所需的一系列bean和组件&#xff0c;从而减少开发者的配置工作&#xff0c;提高开发效率。 一&#xff1a;Condition Condition是spring4.0之后添加…

HTML5 + CSS3

HTML 基础 准备开发环境 1.vscode 使用 新建文件夹 ---> 左键拖入 vscode 中 2.安装插件 扩展 → 搜索插件 → 安装打开网页插件&#xff1a;open in browser汉化菜单插件&#xff1a;Chinese 3.缩放代码字号 放大,缩小&#xff1a;Ctrl 加号&#xff0c;减号 4.设…

【BUG】已解决:You are using pip version 10.0.1, however version 21.3.1 is available.

You are using pip version 10.0.1, however version 21.3.1 is available. 目录 You are using pip version 10.0.1, however version 21.3.1 is available. 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#…

硅纪元视角 | 语音克隆突破:微软VALL-E 2,Deepfake新纪元!

在数字化浪潮的推动下&#xff0c;人工智能&#xff08;AI&#xff09;正成为塑造未来的关键力量。硅纪元视角栏目紧跟AI科技的最新发展&#xff0c;捕捉行业动态&#xff1b;提供深入的新闻解读&#xff0c;助您洞悉技术背后的逻辑&#xff1b;汇聚行业专家的见解&#xff0c;…

SSL/TLS和SSL VPN

1、SSL/TLS SSL安全套接字层&#xff1a;是一种加密协议&#xff0c;用于在网络通信中建立安全连接。它在应用层和传输层&#xff08;TCP/IP&#xff09;之间提供数据加密、服务器身份验证以及信息完整性验证 SSL只保护TCP流量&#xff0c;不保护UDP协议 TLS&#xff1a;传输层…

自定义webIpad证件相机(webRTC)

该技术方案可用于各浏览器自定义相机开发 相机UI&#xff08;index.html&#xff09; <!DOCTYPE html> <html lang"zh" prew"-1"><head><meta charset"UTF-8"><meta name"viewport"content"user-sc…

江苏 | 南京恒建视角下混凝土企业的根基和未来

第一视角带您走进本期标杆企业&#xff1a;南京恒建混凝土有限公司 “有根基才有未来。” ——走进南京恒建混凝土有限公司的办公楼&#xff0c;首先映入眼帘的就是这句话。所谓万丈高楼平地起&#xff0c;一砖一瓦皆根基。简单几个字&#xff0c;既能看到脚踏实地的坚守&…

机器学习笔记-01-初识基础(问题-解答自查版)

前言 以下问题以Q&A形式记录&#xff0c;基本上都是笔者在初学一轮后&#xff0c;掌握不牢或者频繁忘记的点 Q&A的形式有助于学习过程中时刻关注自己的输入与输出关系&#xff0c;也适合做查漏补缺和复盘。 本文对读者可以用作自查&#xff0c;答案在后面&#xff0…

DNS续集

1、DNS多域名解析 [rootdns ~]# vim /etc/named.rfc1912.zones 复制5行放在最后面 zone "z.a" IN { type master; file "z.a.zone"; allow-update { none; }; }; zone "4.168.192.in-addr.arpa" IN { type ma…

<数据集>玉米地杂草识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;9900张 标注数量(xml文件个数)&#xff1a;9900 标注数量(txt文件个数)&#xff1a;9900 标注类别数&#xff1a;2 标注类别名称&#xff1a;[Maize, Weed] 序号类别名称图片数框数1Maize8439125142Weed959231048…

rk3588s 定制版 USB adb , USB2.0与USB3.0 区别,adb 由typeC 转换到USB3.0(第二部分)

硬件资源&#xff1a; rk3588s 核心板定制的地板 软件资源&#xff1a; 网盘上的 android12 源码 1 硬件上 客户只想使用 type c 接口中的 usb2.0 OTG 。在硬件上&#xff0c;甚至连 CC芯片都没有连接。 关于一些前置的知识。 1 USB2.0 与 USB3.0 的区别。 usb3.0 兼容2.0 …