李优秀 发表于 2024-6-15 00:42:56

【Android】广播BroadcastReceiver、接收体系广播(动态、静态注册方式)、

一、接收体系广播

1、动态注册监听网络

   1.需要一个过滤器
2.需要一个广播接收器
3.进行注册
4.取消注册
主要操作:使用registerReceiver接受两个参数,一个是广播接收器BroadcastReceiver,一个是意图IntentFiler。现在注册完成,广播接收器就可以实现接受指定意图的广播.
最后需要记得对于动态注册的广播接收器一定要取消注册,我们在onDestroy()中通过调用unregisterReceiver取消注册。传递的参数为:BroadcastReceiver
public class MainActivity extends AppCompatActivity {
    private IntentFilter intentFilter;
    BroadcastReceiver NetwordChangeReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      intentFilter = new IntentFilter();

      intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");

      NetwordChangeReceiver = new NetwordChangeReceiver();

      registerReceiver(NetwordChangeReceiver,intentFilter);

    }

    @Override
    protected void onDestroy() {
      super.onDestroy();
      unregisterReceiver(NetwordChangeReceiver);
    }

   class NetwordChangeReceiver extends BroadcastReceiver{

      @Override
      public void onReceive(Context context, Intent intent) {

            /** 制作一个网络管理器
             *它用于获取当前设备的网络连接状态信息。通过getSystemService方法,可以从系统服务中获取ConnectivityManager的实例。
             */
            ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            /**
             * 使用网络工具类,从网络管理器中获取一个网络工具,这个工具有网络管理器的指定信息Context.CONNECTIVITY_SERVICE
             */
            NetworkCapabilities networkCapabilities = connectivityManager.getNetworkCapabilities(connectivityManager.getActiveNetwork());

            if (networkCapabilities != null){
                Toast.makeText(context, "netword is good", Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(context, "netWork is Poor", Toast.LENGTH_SHORT).show();
            }
      }
    }
}
可以在下面这个路径查看体系广播列表:
Android/Sdk/platforms/<任意的android api 版本>/data/broadcast_actions.txt
2、静态注册开机

注意静态广播需要在AndroidManifest.xml中注册才可以使用,不过使用android stdio的快捷方式可以实现自动注册。
<?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.BroadcastReceiver"
      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>
enabled、exported就是我们勾选的属性,不过此时的BootCompleteReceiver还是无法收到开机自启动广播,我们需要做如下操作:
添加,和应用权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

<intent-filter>
    <action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
二、发送自定义广播(静态注册方法)

1、发送标准广播

https://img-blog.csdnimg.cn/1cfbdbf8a711423e8a6eef7344b4d2cc.png
1.1 构建一个广播接收器

public class MyBroadcateReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
      Toast.makeText(context, "received in MyBroadcateRecevier", Toast.LENGTH_SHORT).show();
    }
}
1.2 在AndroidManifest.xml中注册广播信息

<receiver
          android:name=".MyBroadcateReceiver"
          android:enabled="true"
          android:exported="true" >
    <intent-filter>
      <action android:name="com.example.broadcastreceiver.MY_BROADCAST"/>
    </intent-filter>
</receiver>
1.3 定义一个按钮作为广播的触发器

public class MainActivity extends AppCompatActivity {
    private IntentFilter intentFilter;
    BroadcastReceiver NetwordChangeReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      Button button = findViewById(R.id.button);

      button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent("com.example.broadcastreceiver.MY_BROADCAST");
//                intent.setPackage("com.example.broadcastreceiver");
                intent.setPackage(getPackageName());
                sendBroadcast(intent);
            }
      });

    }
}
首先构建了一个Intent对象,并把要发送的广播的值传入。然后调用Intent的setPackage() 方法,并传入当前应用程序的包名。getPackageName()可以获取当前包名,用于获取当前应用程序的包名。最后调用sendBroadcast()方法将广播发送出去,如许所有监听com.example.broadcastreceiver.MY_BROADCAST这条广播的BroadcastReceiver就会收 到消息了。此时发出去的广播就是一条标准广播
注意这个setPackage的作用是指定这条广播发送给哪个程序,使得隐式广播转化为显式广播。因为Android8.0以后,静态注册的BroadcastReceiver是无法接受广播的。
在《第一行代码第二版》中,两个应用互相传递消息。在android 8.0之前是可以的,但是我们刚刚说android 8.0之后静态注册的BroadcastReceiver是无法接受广播的。因此无法实现两个应用互相传递消息,解决方法很简单。指定第二个应用的包名,在传递一次即可。
2、发送有序广播

https://img-blog.csdnimg.cn/6b45724c73bd4d8d97f8b081bb28a6cf.png
2.1 建立一个新的广播接收器

public class AontherBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
      Toast.makeText(context, "receciver in AnotherBroadcastReceiver", Toast.LENGTH_SHORT).show();
      Log.d("Broadcast","AnotherBroadcastReceiver");

    }
}
在AndroidManifest.xml中注册广播信息
<receiver
          android:name=".MyBroadcateReceiver"
          android:enabled="true"
          android:exported="true">
    <intent-filter android:priority="100">
      <action android:name="com.example.broadcastreceiver.MY_BROADCAST" />
    </intent-filter>
</receiver>
2.2 使用sendOrderedBroadcast发送有序广播

      button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent("com.example.broadcastreceiver.MY_BROADCAST");

                intent.setPackage(getPackageName());

                sendOrderedBroadcast(intent,null);
            }
      });
    }
2.3 设置优先级并且使用abortBroadcast截断广播

      <receiver
            android:name=".MyBroadcateReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter android:priority="100">
                <action android:name="com.example.broadcastreceiver.MY_BROADCAST" />
            </intent-filter>
      </receiver>
android:priority="100"用于设置优先级为100
注意优先级大的先执行,但是笔者的手机优先级大的会后执行优先级小的广播,具体什么问题笔者也不可知,笔者手机为一加Ace2,基于android 13.0。笔者怀疑这种情况可能是手机权限导致,其他经过测试android 13.0的手机优先级正常,大的优先级高先执行。
public class MyBroadcateReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
      Toast.makeText(context, "received in MyBroadcateRecevier", Toast.LENGTH_SHORT).show();
      Log.d("Broadcast","MyBroadcateRecevier");
      abortBroadcast();
    }
}
使用abortBroadcast()可以截断广播,使得优先级在MyBroadcateReceiver之后的BroadcateReceiver无法接受到广播,广播在这里就被截断了。
三、实践——强制下线功能

1、制作活动管理工具

public class ActivityCollector {
    public static List<Activity> activities = new ArrayList<>();

    public static void addActivity(Activity activity){
      activities.add(activity);
    }

    public static void delete(Activity activity){
      activities.remove(activity);
    }

    public static void finishAll(){
      for(Activity activity:activities){
            if(!activity.isFinishing()){
                activity.finish();
            }
      }
      activities.clear();
    }
}
public class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      ActivityCollector.addActivity(this);


    }

    @Override
    protected void onDestroy() {
      super.onDestroy();
      ActivityCollector.delete(this);
    }
}
用于注销所有的活动,实现一键退出功能。
2、制作登岸界面

2.1 绘制登岸界面

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
      android:orientation="horizontal"
      android:layout_width="match_parent"
      android:layout_height="wrap_content">
      <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textSize="18sp"
            android:layout_weight="1"
            android:text="Account: "
            android:gravity="center|end"/>

      <EditText
            android:id="@+id/account"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="2"/>

    </LinearLayout>

    <LinearLayout
      android:orientation="horizontal"
      android:layout_width="match_parent"
      android:layout_height="wrap_content">
      <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textSize="18sp"
            android:layout_weight="1"
            android:text="Password: "
            android:gravity="center|end"/>

      <EditText
            android:id="@+id/password"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="2"/>

    </LinearLayout>

    <Button
      android:id="@+id/login"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginTop="20dp"
      android:layout_gravity="center"
      android:text="Login"/>

</LinearLayout>
https://img-blog.csdnimg.cn/img_convert/0498e2057c361bd90fe10e7a6eb21fa8.png
2.2 编写登岸界面代码

public class LoginActivity extends BaseActivity {

    ActivityLoginBinding binding;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);

      binding = ActivityLoginBinding.inflate(getLayoutInflater());

      setContentView(binding.getRoot());

      binding.login.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String account = binding.account.getText().toString();
                String password = binding.password.getText().toString();

                if (account.equals("admin") && password.equals("123456")) {
                  Intent intent = new Intent(LoginActivity.this,MainActivity.class);
                  startActivity(intent);
                }else {
                  Toast.makeText(LoginActivity.this, "password is poor", Toast.LENGTH_SHORT).show();
                }
            }
      });
    }
}
3、编写登岸后的界面,并且发送广播

3.1绘制界面

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
      android:id="@+id/force_offline"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_marginTop="40dp"
      android:layout_gravity="center"
      android:text="Send force offline Broadcast"/>

</LinearLayout>
https://img-blog.csdnimg.cn/img_convert/09c06798aa11e908f4d73fc8122b0026.png
3.2 登岸后发送广播

public class MainActivity extends BaseActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      Button button = findViewById(R.id.force_offline);

      button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                Intent intent = new Intent("com.example.forcedoffine.FORCE_OFFLINE");
                sendBroadcast(intent);
            }
      });

    }
}
4、接收广播

在BaseActivity中制作广播接收器
package com.example.forcedoffline;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

/**
* 项目名: ForcedOffline
* 文件名: BaseActivity
* 创建者: lukecc0
* 创建时间:2023/7/25 上午11:33
* 描述: TODO
*/

public class BaseActivity extends AppCompatActivity {

    private ForceOfflineReceiver forceOfflineReceiver;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      ActivityCollector.addActivity(this);


    }

    @Override
    protected void onDestroy() {
      super.onDestroy();
      ActivityCollector.delete(this);
    }


    @Override
    protected void onResume() {
      super.onResume();
      IntentFilter intentFilter = new IntentFilter();
      intentFilter.addAction("com.example.forcedoffine.FORCE_OFFLINE");
      forceOfflineReceiver = new ForceOfflineReceiver();
      registerReceiver(forceOfflineReceiver,intentFilter);
    }

    @Override
    protected void onPause() {
      super.onPause();
      if(forceOfflineReceiver!=null){
            unregisterReceiver(forceOfflineReceiver);
            forceOfflineReceiver = null;
      }
    }

    class ForceOfflineReceiver extends BroadcastReceiver{
      @Override
      public void onReceive(Context context, Intent intent) {
            AlertDialog.Builder builder = new AlertDialog.Builder(context);
            builder.setTitle("Warinng");
            builder.setMessage("please try to login again");

            builder.setCancelable(false);
            builder.setPositiveButton("ok", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                  ActivityCollector.finishAll();
                  Intent intent1 = new Intent(context, LoginActivity.class);
                  context.startActivity(intent1);
                }
            });

            builder.show();
      }
    }
}

代码表明:
4.1 为什么要让forceOfflineReceiver = null

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

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

[*]假如广播接收器注册在 onCreate() 中,但在 onPause() 或 onStop() 中没有注销,那么纵然 Activity 不可见,广播接收器仍然保持注册状态,继续接收广播,这可能会导致资源浪费和不必要的逻辑执行。
[*]假如广播接收器的注销在 onDestroy() 中,那么在 Activity 被销毁时才会注销广播接收器。如许可能会导致在 Activity 不可见的时候仍然接收广播,直到 Activity 被销毁。这可能导致不必要的逻辑执行和资源浪费。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 【Android】广播BroadcastReceiver、接收体系广播(动态、静态注册方式)、