IT评测·应用市场-qidao123.com技术社区

标题: 【Android】广播BroadcastReceiver、接收体系广播(动态、静态注册方式)、 [打印本页]

作者: 李优秀    时间: 2024-6-15 00:42
标题: 【Android】广播BroadcastReceiver、接收体系广播(动态、静态注册方式)、
一、接收体系广播

1、动态注册监听网络

   1.需要一个过滤器
  2.需要一个广播接收器
  3.进行注册
  4.取消注册
  主要操作:使用registerReceiver接受两个参数,一个是广播接收器BroadcastReceiver,一个是意图IntentFiler。现在注册完成,广播接收器就可以实现接受指定意图的广播.
最后需要记得对于动态注册的广播接收器一定要取消注册,我们在onDestroy()中通过调用unregisterReceiver取消注册。传递的参数为:BroadcastReceiver
  1. public class MainActivity extends AppCompatActivity {
  2.     private IntentFilter intentFilter;
  3.     BroadcastReceiver NetwordChangeReceiver;
  4.     @Override
  5.     protected void onCreate(Bundle savedInstanceState) {
  6.         super.onCreate(savedInstanceState);
  7.         setContentView(R.layout.activity_main);
  8.         intentFilter = new IntentFilter();
  9.         intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
  10.         NetwordChangeReceiver = new NetwordChangeReceiver();
  11.         registerReceiver(NetwordChangeReceiver,intentFilter);
  12.     }
  13.     @Override
  14.     protected void onDestroy() {
  15.         super.onDestroy();
  16.         unregisterReceiver(NetwordChangeReceiver);
  17.     }
  18.    class NetwordChangeReceiver extends BroadcastReceiver{
  19.         @Override
  20.         public void onReceive(Context context, Intent intent) {
  21.             /** 制作一个网络管理器
  22.              *  它用于获取当前设备的网络连接状态信息。通过getSystemService方法,可以从系统服务中获取ConnectivityManager的实例。
  23.              */
  24.             ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
  25.             /**
  26.              * 使用网络工具类,从网络管理器中获取一个网络工具,这个工具有网络管理器的指定信息Context.CONNECTIVITY_SERVICE
  27.              */
  28.             NetworkCapabilities networkCapabilities = connectivityManager.getNetworkCapabilities(connectivityManager.getActiveNetwork());
  29.             if (networkCapabilities != null){
  30.                 Toast.makeText(context, "netword is good", Toast.LENGTH_SHORT).show();
  31.             }else {
  32.                 Toast.makeText(context, "netWork is Poor", Toast.LENGTH_SHORT).show();
  33.             }
  34.         }
  35.     }
  36. }
复制代码
可以在下面这个路径查看体系广播列表:
Android/Sdk/platforms/<任意的android api 版本>/data/broadcast_actions.txt
2、静态注册开机

注意静态广播需要在AndroidManifest.xml中注册才可以使用,不过使用android stdio的快捷方式可以实现自动注册。
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3.     xmlns:tools="http://schemas.android.com/tools">
  4.     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  5.     <application
  6.         android:allowBackup="true"
  7.         android:dataExtractionRules="@xml/data_extraction_rules"
  8.         android:fullBackupContent="@xml/backup_rules"
  9.         android:icon="@mipmap/ic_launcher"
  10.         android:label="@string/app_name"
  11.         android:roundIcon="@mipmap/ic_launcher_round"
  12.         android:supportsRtl="true"
  13.         android:theme="@style/Theme.BroadcastReceiver"
  14.         tools:targetApi="31">
  15.         <receiver
  16.             android:name=".BootCompleteReceiver"
  17.             android:enabled="true"
  18.             android:exported="true">
  19.         </receiver>
  20.         <activity
  21.             android:name=".MainActivity"
  22.             android:exported="true">
  23.             <intent-filter>
  24.                 <action android:name="android.intent.action.MAIN" />
  25.                 <category android:name="android.intent.category.LAUNCHER" />
  26.             </intent-filter>
  27.         </activity>
  28.     </application>
  29. </manifest>
复制代码
enabled、exported就是我们勾选的属性,不过此时的BootCompleteReceiver还是无法收到开机自启动广播,我们需要做如下操作:
添加,和应用权限
  1. <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  2. <intent-filter>
  3.     <action android:name="android.intent.action.BOOT_COMPLETED"/>
  4. </intent-filter>
复制代码
二、发送自定义广播(静态注册方法)

1、发送标准广播


1.1 构建一个广播接收器

  1. public class MyBroadcateReceiver extends BroadcastReceiver {
  2.     @Override
  3.     public void onReceive(Context context, Intent intent) {
  4.         Toast.makeText(context, "received in MyBroadcateRecevier", Toast.LENGTH_SHORT).show();
  5.     }
  6. }
复制代码
1.2 在AndroidManifest.xml中注册广播信息

  1. <receiver
  2.           android:name=".MyBroadcateReceiver"
  3.           android:enabled="true"
  4.           android:exported="true" >
  5.     <intent-filter>
  6.         <action android:name="com.example.broadcastreceiver.MY_BROADCAST"/>
  7.     </intent-filter>
  8. </receiver>
复制代码
1.3 定义一个按钮作为广播的触发器

  1. public class MainActivity extends AppCompatActivity {
  2.     private IntentFilter intentFilter;
  3.     BroadcastReceiver NetwordChangeReceiver;
  4.     @Override
  5.     protected void onCreate(Bundle savedInstanceState) {
  6.         super.onCreate(savedInstanceState);
  7.         setContentView(R.layout.activity_main);
  8.         Button button = findViewById(R.id.button);
  9.         button.setOnClickListener(new View.OnClickListener() {
  10.             @Override
  11.             public void onClick(View view) {
  12.                 Intent intent = new Intent("com.example.broadcastreceiver.MY_BROADCAST");
  13. //                intent.setPackage("com.example.broadcastreceiver");
  14.                 intent.setPackage(getPackageName());
  15.                 sendBroadcast(intent);
  16.             }
  17.         });
  18.     }
  19. }
复制代码
首先构建了一个Intent对象,并把要发送的广播的值传入。然后调用Intent的setPackage() 方法,并传入当前应用程序的包名。getPackageName()可以获取当前包名,用于获取当前应用程序的包名。最后调用sendBroadcast()方法将广播发送出去,如许所有监听com.example.broadcastreceiver.MY_BROADCAST这条广播的BroadcastReceiver就会收 到消息了。此时发出去的广播就是一条标准广播
注意这个setPackage的作用是指定这条广播发送给哪个程序,使得隐式广播转化为显式广播。因为Android8.0以后,静态注册的BroadcastReceiver是无法接受广播的。
在《第一行代码第二版》中,两个应用互相传递消息。在android 8.0之前是可以的,但是我们刚刚说android 8.0之后静态注册的BroadcastReceiver是无法接受广播的。因此无法实现两个应用互相传递消息,解决方法很简单。指定第二个应用的包名,在传递一次即可。
2、发送有序广播


2.1 建立一个新的广播接收器

  1. public class AontherBroadcastReceiver extends BroadcastReceiver {
  2.     @Override
  3.     public void onReceive(Context context, Intent intent) {
  4.         Toast.makeText(context, "receciver in AnotherBroadcastReceiver", Toast.LENGTH_SHORT).show();
  5.         Log.d("Broadcast","AnotherBroadcastReceiver");
  6.     }
  7. }
复制代码
在AndroidManifest.xml中注册广播信息
  1. <receiver
  2.           android:name=".MyBroadcateReceiver"
  3.           android:enabled="true"
  4.           android:exported="true">
  5.     <intent-filter android:priority="100">
  6.         <action android:name="com.example.broadcastreceiver.MY_BROADCAST" />
  7.     </intent-filter>
  8. </receiver>
复制代码
2.2 使用sendOrderedBroadcast发送有序广播

  1.         button.setOnClickListener(new View.OnClickListener() {
  2.             @Override
  3.             public void onClick(View view) {
  4.                 Intent intent = new Intent("com.example.broadcastreceiver.MY_BROADCAST");
  5.                 intent.setPackage(getPackageName());
  6.                 sendOrderedBroadcast(intent,null);
  7.             }
  8.         });
  9.     }
复制代码
2.3 设置优先级并且使用abortBroadcast截断广播

  1.         <receiver
  2.             android:name=".MyBroadcateReceiver"
  3.             android:enabled="true"
  4.             android:exported="true">
  5.             <intent-filter android:priority="100">
  6.                 <action android:name="com.example.broadcastreceiver.MY_BROADCAST" />
  7.             </intent-filter>
  8.         </receiver>
复制代码
android:priority="100"用于设置优先级为100
注意优先级大的先执行,但是笔者的手机优先级大的会后执行优先级小的广播,具体什么问题笔者也不可知,笔者手机为一加Ace2,基于android 13.0。笔者怀疑这种情况可能是手机权限导致,其他经过测试android 13.0的手机优先级正常,大的优先级高先执行。
  1. public class MyBroadcateReceiver extends BroadcastReceiver {
  2.     @Override
  3.     public void onReceive(Context context, Intent intent) {
  4.         Toast.makeText(context, "received in MyBroadcateRecevier", Toast.LENGTH_SHORT).show();
  5.         Log.d("Broadcast","MyBroadcateRecevier");
  6.         abortBroadcast();
  7.     }
  8. }
复制代码
使用abortBroadcast()可以截断广播,使得优先级在MyBroadcateReceiver之后的BroadcateReceiver无法接受到广播,广播在这里就被截断了。
三、实践——强制下线功能

1、制作活动管理工具

  1. public class ActivityCollector {
  2.     public static List<Activity> activities = new ArrayList<>();
  3.     public static void addActivity(Activity activity){
  4.         activities.add(activity);
  5.     }
  6.     public static void delete(Activity activity){
  7.         activities.remove(activity);
  8.     }
  9.     public static void finishAll(){
  10.         for(Activity activity:activities){
  11.             if(!activity.isFinishing()){
  12.                 activity.finish();
  13.             }
  14.         }
  15.         activities.clear();
  16.     }
  17. }
复制代码
  1. public class BaseActivity extends AppCompatActivity {
  2.     @Override
  3.     protected void onCreate(@Nullable Bundle savedInstanceState) {
  4.         super.onCreate(savedInstanceState);
  5.         ActivityCollector.addActivity(this);
  6.     }
  7.     @Override
  8.     protected void onDestroy() {
  9.         super.onDestroy();
  10.         ActivityCollector.delete(this);
  11.     }
  12. }
复制代码
用于注销所有的活动,实现一键退出功能。
2、制作登岸界面

2.1 绘制登岸界面

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.     xmlns:app="http://schemas.android.com/apk/res-auto"
  4.     xmlns:tools="http://schemas.android.com/tools"
  5.     android:orientation="vertical"
  6.     android:layout_width="match_parent"
  7.     android:layout_height="match_parent"
  8.     tools:context=".MainActivity">
  9.     <LinearLayout
  10.         android:orientation="horizontal"
  11.         android:layout_width="match_parent"
  12.         android:layout_height="wrap_content">
  13.         <TextView
  14.             android:layout_width="0dp"
  15.             android:layout_height="wrap_content"
  16.             android:textSize="18sp"
  17.             android:layout_weight="1"
  18.             android:text="Account: "
  19.             android:gravity="center|end"/>
  20.         <EditText
  21.             android:id="@+id/account"
  22.             android:layout_width="0dp"
  23.             android:layout_height="wrap_content"
  24.             android:layout_weight="2"/>
  25.     </LinearLayout>
  26.     <LinearLayout
  27.         android:orientation="horizontal"
  28.         android:layout_width="match_parent"
  29.         android:layout_height="wrap_content">
  30.         <TextView
  31.             android:layout_width="0dp"
  32.             android:layout_height="wrap_content"
  33.             android:textSize="18sp"
  34.             android:layout_weight="1"
  35.             android:text="Password: "
  36.             android:gravity="center|end"/>
  37.         <EditText
  38.             android:id="@+id/password"
  39.             android:layout_width="0dp"
  40.             android:layout_height="wrap_content"
  41.             android:layout_weight="2"/>
  42.     </LinearLayout>
  43.     <Button
  44.         android:id="@+id/login"
  45.         android:layout_width="wrap_content"
  46.         android:layout_height="wrap_content"
  47.         android:layout_marginTop="20dp"
  48.         android:layout_gravity="center"
  49.         android:text="Login"/>
  50. </LinearLayout>
复制代码

2.2 编写登岸界面代码

  1. public class LoginActivity extends BaseActivity {
  2.     ActivityLoginBinding binding;
  3.     @Override
  4.     protected void onCreate(@Nullable Bundle savedInstanceState) {
  5.         super.onCreate(savedInstanceState);
  6.         binding = ActivityLoginBinding.inflate(getLayoutInflater());
  7.         setContentView(binding.getRoot());
  8.         binding.login.setOnClickListener(new View.OnClickListener() {
  9.             @Override
  10.             public void onClick(View view) {
  11.                 String account = binding.account.getText().toString();
  12.                 String password = binding.password.getText().toString();
  13.                 if (account.equals("admin") && password.equals("123456")) {
  14.                     Intent intent = new Intent(LoginActivity.this,MainActivity.class);
  15.                     startActivity(intent);
  16.                 }else {
  17.                     Toast.makeText(LoginActivity.this, "password is poor", Toast.LENGTH_SHORT).show();
  18.                 }
  19.             }
  20.         });
  21.     }
  22. }
复制代码
3、编写登岸后的界面,并且发送广播

3.1绘制界面

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.     xmlns:app="http://schemas.android.com/apk/res-auto"
  4.     xmlns:tools="http://schemas.android.com/tools"
  5.     android:orientation="vertical"
  6.     android:layout_width="match_parent"
  7.     android:layout_height="match_parent"
  8.     tools:context=".MainActivity">
  9.     <Button
  10.         android:id="@+id/force_offline"
  11.         android:layout_width="wrap_content"
  12.         android:layout_height="wrap_content"
  13.         android:layout_marginTop="40dp"
  14.         android:layout_gravity="center"
  15.         android:text="Send force offline Broadcast"/>
  16. </LinearLayout>
复制代码

3.2 登岸后发送广播

  1. public class MainActivity extends BaseActivity{
  2.     @Override
  3.     protected void onCreate(Bundle savedInstanceState) {
  4.         super.onCreate(savedInstanceState);
  5.         setContentView(R.layout.activity_main);
  6.         Button button = findViewById(R.id.force_offline);
  7.         button.setOnClickListener(new View.OnClickListener() {
  8.             @Override
  9.             public void onClick(View view) {
  10.                 Intent intent = new Intent("com.example.forcedoffine.FORCE_OFFLINE");
  11.                 sendBroadcast(intent);
  12.             }
  13.         });
  14.     }
  15. }
复制代码
4、接收广播

在BaseActivity中制作广播接收器
  1. package com.example.forcedoffline;
  2. import android.app.Activity;
  3. import android.app.AlertDialog;
  4. import android.content.BroadcastReceiver;
  5. import android.content.Context;
  6. import android.content.DialogInterface;
  7. import android.content.Intent;
  8. import android.content.IntentFilter;
  9. import android.os.Bundle;
  10. import android.os.PersistableBundle;
  11. import android.util.Log;
  12. import androidx.annotation.Nullable;
  13. import androidx.appcompat.app.AppCompatActivity;
  14. /**
  15. * 项目名: ForcedOffline
  16. * 文件名: BaseActivity
  17. * 创建者: lukecc0
  18. * 创建时间:2023/7/25 上午11:33
  19. * 描述: TODO
  20. */
  21. public class BaseActivity extends AppCompatActivity {
  22.     private ForceOfflineReceiver forceOfflineReceiver;
  23.     @Override
  24.     protected void onCreate(@Nullable Bundle savedInstanceState) {
  25.         super.onCreate(savedInstanceState);
  26.         ActivityCollector.addActivity(this);
  27.     }
  28.     @Override
  29.     protected void onDestroy() {
  30.         super.onDestroy();
  31.         ActivityCollector.delete(this);
  32.     }
  33.     @Override
  34.     protected void onResume() {
  35.         super.onResume();
  36.         IntentFilter intentFilter = new IntentFilter();
  37.         intentFilter.addAction("com.example.forcedoffine.FORCE_OFFLINE");
  38.         forceOfflineReceiver = new ForceOfflineReceiver();
  39.         registerReceiver(forceOfflineReceiver,intentFilter);
  40.     }
  41.     @Override
  42.     protected void onPause() {
  43.         super.onPause();
  44.         if(forceOfflineReceiver!=null){
  45.             unregisterReceiver(forceOfflineReceiver);
  46.             forceOfflineReceiver = null;
  47.         }
  48.     }
  49.     class ForceOfflineReceiver extends BroadcastReceiver{
  50.         @Override
  51.         public void onReceive(Context context, Intent intent) {
  52.             AlertDialog.Builder builder = new AlertDialog.Builder(context);
  53.             builder.setTitle("Warinng");
  54.             builder.setMessage("please try to login again");
  55.             builder.setCancelable(false);
  56.             builder.setPositiveButton("ok", new DialogInterface.OnClickListener() {
  57.                 @Override
  58.                 public void onClick(DialogInterface dialogInterface, int i) {
  59.                     ActivityCollector.finishAll();
  60.                     Intent intent1 = new Intent(context, LoginActivity.class);
  61.                     context.startActivity(intent1);
  62.                 }
  63.             });
  64.             builder.show();
  65.         }
  66.     }
  67. }
复制代码
代码表明:
4.1 为什么要让forceOfflineReceiver = null

如许写的目的是为了确保在调用 unregisterReceiver() 注销广播接收器之后,再将 forceOfflineReceiver 设置为 null,以制止在已经注销的广播接收器上继续操作而可能导致异常或其他问题。因为这里不是在onDestroy中注销广播。
4.2 为什么在onResume和onPause中注册和注销

在 Android 应用的生命周期中,onResume() 和 onPause() 方法对应着 Activity 的可见性。当 Activity 处于可见状态时,会调用 onResume() 方法;当 Activity 处于不可见状态时,会调用 onPause() 方法。
假如我们将广播接收器的注册放在 onCreate() 中,那么广播接收器会在 Activity 创建时注册,但可能会出现以下问题:

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/) Powered by Discuz! X3.4