Android BroadcastReceiver

一 简介

1.1 定义

 BroadcastReceiver即 广播,是一个全局的监听器,属于Android四大组件之一

1.2 作用

监听 / 接收 应用 App 发出的广播消息,并 做出响应

1.3 应用场景

  • Android不同组件间的通信(含 :应用内 / 不同应用之间)
  • 多线程通信
  • 与 Android 系统在特定情况下的通信

二 实现原理

2.1 使用模型

Android中的广播使用了设计模式中的观察者模式:基于消息的发布 / 订阅事件模型

2.2 模型讲解

  • 模型中有3个角色:

    1. 消息订阅者(广播接收者)
    2. 消息发布者(广播发布者)
    3. 消息中心(AMS,即Activity Manager Service
  • 示意图 & 原理如下

示意图

三 广播接收

3.1 静态注册

<receiver 
    android:enabled=["true" | "false"]
//此broadcastReceiver能否接收其他App的发出的广播
//默认值是由receiver中有无intent-filter决定的:如果有intent-filter,默认值为true,否则为false
    android:exported=["true" | "false"]
    android:icon="drawable resource"
    android:label="string resource"
//继承BroadcastReceiver子类的类名
    android:name=".mBroadcastReceiver"
//具有相应权限的广播发送者发送的广播才能被此BroadcastReceiver所接收;
    android:permission="string"
//BroadcastReceiver运行所处的进程
//默认为app的进程,可以指定独立的进程
//注:Android四大基本组件都可以通过此属性指定自己的独立进程
    android:process="string" >

//用于指定此广播接收器将接收的广播类型
//本示例中给出的是用于接收网络状态改变时发出的广播
 <intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    </intent-filter>
</receiver>

从8.0开始,系统对静态注册的广播会有所限制,无法使用清单为大多数隐式广播声明接收方。

倘若要继续使用,设定 package 和 class 即可,如下图:

 

3.2 动态注册

    private void register() {
        receiver = new MyActiveReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(MyActiveReceiver.ACTION);
        registerReceiver(receiver, filter);
    }

    private void unRegister() {
        unregisterReceiver(receiver);
    }

 

3.3 两种方式区别

示意图

四 广播类型

4.1 普通广播

    private void sendStaticBroadcast() {
        Intent intent = new Intent();
        intent.setPackage(getPackageName());
        intent.setAction(MyActiveReceiver.ACTION);
        sendBroadcast(intent);
    }

4.2 系统广播

  • Android中内置了多个系统广播:只要涉及到手机的基本操作(如开机、网络状态变化、拍照等等),都会发出相应的广播
  • 每个广播都有特定的Intent - Filter(包括具体的action),Android系统广播action如下:
系统操作 action
监听网络变化android.net.conn.CONNECTIVITY_CHANGE
关闭或打开飞行模式Intent.ACTION_AIRPLANE_MODE_CHANGED
充电时或电量发生变化Intent.ACTION_BATTERY_CHANGED
电池电量低Intent.ACTION_BATTERY_LOW
电池电量充足(即从电量低变化到饱满时会发出广播Intent.ACTION_BATTERY_OKAY
系统启动完成后(仅广播一次)Intent.ACTION_BOOT_COMPLETED
按下照相时的拍照按键(硬件按键)时Intent.ACTION_CAMERA_BUTTON
屏幕锁屏Intent.ACTION_CLOSE_SYSTEM_DIALOGS
设备当前设置被改变时(界面语言、设备方向等)Intent.ACTION_CONFIGURATION_CHANGED
插入耳机时Intent.ACTION_HEADSET_PLUG
未正确移除SD卡但已取出来时(正确移除方法:设置–SD卡和设备内存–卸载SD卡)Intent.ACTION_MEDIA_BAD_REMOVAL
插入外部储存装置(如SD卡)Intent.ACTION_MEDIA_CHECKING
成功安装APKIntent.ACTION_PACKAGE_ADDED
成功删除APKIntent.ACTION_PACKAGE_REMOVED
重启设备Intent.ACTION_REBOOT
屏幕被关闭Intent.ACTION_SCREEN_OFF
屏幕被打开Intent.ACTION_SCREEN_ON
关闭系统时Intent.ACTION_SHUTDOWN
重启设备Intent.ACTION_REBOOT

 

注:当使用系统广播时,只需要在注册广播接收者时定义相关的action即可,并不需要手动发送广播,当系统有相关操作时会自动进行系统广播

示例:

    private void register() {
        receiver = new MySystemReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_SCREEN_ON);//亮屏广播
        registerReceiver(receiver, filter);
    }

    private void unRegister() {
        unregisterReceiver(receiver);
    }
public class MySystemReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (TextUtils.equals(Intent.ACTION_SCREEN_ON, action)) {
            Toast.makeText(context, "收到亮屏广播", Toast.LENGTH_LONG).show();
        }
    }
}

 

4.3 有序广播

发送出去的广播被广播接收者按照先后顺序接收。

  • 顺序规则(同时面向静态和动态注册的广播接受者)

          1   按照Priority属性值从大-小排序;
          2   Priority属性相同者,动态注册的广播优先;

  • 特点

         1  接收广播按顺序接收
         2  先接收的广播接收者可以对广播进行截断,即后接收的广播接收者不再接收到此广播;
         3  先接收的广播接收者可以对广播进行修改,那么后接收的广播接收者将接收到被修改后的广播
 

示例:

/**
 * 有序广播
 */
public class MyOrder1Receiver extends BroadcastReceiver {
    public static final String ACTION = "com.bsoft.ck.action.orderdemo";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (TextUtils.equals(ACTION,action)){
            Log.i("chenkaid","收到有序广播 1");

            //传值
            Bundle twobundle = new Bundle();
            twobundle.putString("extra","来自Order1");
            setResultExtras(twobundle);
        }
    }
}
/**
 * 有序广播
 */
public class MyOrder2Receiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (TextUtils.equals(MyOrder1Receiver.ACTION, action)) {
            Bundle bundle = getResultExtras(true);
            String extra = null;
            if (bundle != null) {
                extra = bundle.getString("extra");
            }
            Log.i("chenkaid", "收到有序广播 2 " + extra);

            //拦截
            abortBroadcast();
        }
    }
}
/**
 * 有序广播
 */
public class MyOrder3Receiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (TextUtils.equals(MyOrder1Receiver.ACTION,action)){
            Log.i("chenkaid","收到有序广播 3");
        }
    }
}
    private void sendStaticBroadcast() {
        Intent intent = new Intent();
        intent.setPackage(getPackageName());
        intent.setAction(MyOrder1Receiver.ACTION);
        sendOrderedBroadcast(intent, null);
    }

    private void register() {
        myOrder1Receiver = new MyOrder1Receiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(MyOrder1Receiver.ACTION);
        filter.setPriority(1);
        registerReceiver(myOrder1Receiver, filter);

        myOrder2Receiver = new MyOrder2Receiver();
        IntentFilter filter2 = new IntentFilter();
        filter2.addAction(MyOrder1Receiver.ACTION);
        filter2.setPriority(2);
        registerReceiver(myOrder2Receiver, filter);

        myOrder3Receiver = new MyOrder3Receiver();
        IntentFilter filter3 = new IntentFilter();
        filter3.addAction(MyOrder1Receiver.ACTION);
        filter3.setPriority(3);
        registerReceiver(myOrder3Receiver, filter);
    }

    private void unRegister() {
        unregisterReceiver(myOrder1Receiver);
        unregisterReceiver(myOrder2Receiver);
        unregisterReceiver(myOrder3Receiver);
    }
}

 

4.4 应用内广播

  • 背景

       Android中的广播可以跨App直接通信(exported对于有intent-filter情况下默认值为true)

  • 可能出现的问题:

       1  其他App针对性发出与当前App intent-filter相匹配的广播,由此导致当前App不断接收广播并处理;
       2  其他App注册与当前App一致的intent-filter用于接收广播,获取广播具体信息;
           即会出现安全性 & 效率性的问题。

  • 解决方案

        使用App应用内广播(Local Broadcast)

有两种方式:

方式一:将全局广播设置成局部广播

  1. 注册广播时将exported属性设置为false,使得非本App内部发出的此广播不被接收;
  2. 在广播发送和接收时,增设相应权限permission,用于权限验证;
  3. 发送广播时指定该广播接收器所在的包名(通过**intent.setPackage(packageName)**指定报名),此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中。

方式二:使用封装好的LocalBroadcastManager类

对于LocalBroadcastManager方式发送的应用内广播,只能通过LocalBroadcastManager动态注册,不能静态注册

 

示例:

manager = LocalBroadcastManager.getInstance(this);
    private void register() {
        myLocalReceiver = new MyLocalReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(MyLocalReceiver.ACTION);
        manager.registerReceiver(myLocalReceiver, filter);

    }

    private void unregister() {
        manager.unregisterReceiver(myLocalReceiver);
    }

    private void sendStaticBroadcast() {
        Intent intent = new Intent();
        intent.setAction(MyLocalReceiver.ACTION);
        manager.sendBroadcast(intent);
    }

 

五 广播权限

创建自己的使用权限,即在清单文件中添加一个 < permission > 标签来声明自定义权限。

    <permission
        android:name="com.example.permission.receiver"
        android:protectionLevel="signature" />

自定义权限时必须同时指定 protectionLevel 属性值,系统根据该属性值确定自定义权限的使用方式 

属性值限定方式
normal默认值。较低风险的权限,对其他应用,系统和用户来说风险最小。系统在安装应用时会自动批准授予应用该类型的权限,不要求用户明确批准(虽然用户在安装之前总是可以选择查看这些权限)
dangerous较高风险的权限,请求该类型权限的应用程序会访问用户私有数据或对设备进行控制,从而可能对用户造成负面影响。因为这种类型的许可引入了潜在风险,所以系统可能不会自动将其授予请求的应用。例如,系统可以向用户显示由应用请求的任何危险许可,并且在继续之前需要确认,或者可以采取一些其他方法来避免用户自动允许
signature只有在请求该权限的应用与声明权限的应用使用相同的证书签名时,系统才会授予权限。如果证书匹配,系统会自动授予权限而不通知用户或要求用户的明确批准
signatureOrSystem系统仅授予Android系统映像中与声明权限的应用使用相同的证书签名的应用。请避免使用此选项,“signature”级别足以满足大多数需求,“signatureOrSystem”权限用于某些特殊情况

5.1 发送方指定权限

发送方:

    <permission
        android:name="com.bsoft.ck.permission.mydemo"
        android:protectionLevel="normal" />
    private void sendStaticBroadcast() {
        Intent intent = new Intent();
        intent.setPackage(getPackageName());
        intent.setAction(MyPermissionReceiver.ACTION);
        sendBroadcast(intent, MyPermissionReceiver.PERMISSION);
    }

 

接收方:

    <uses-permission android:name="com.bsoft.ck.permission.mydemo" />
    private void register() {
        receiver = new MyPermissionReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(MyPermissionReceiver.ACTION);
        registerReceiver(receiver, filter, MyPermissionReceiver.PERMISSION, null);
    }

    private void unRegister() {
        unregisterReceiver(receiver);
    }

 

5.2 接收方指定权限:

接收方:

    <permission
        android:name="com.bsoft.ck.permission.mydemo"
        android:protectionLevel="normal" />
    private void register() {
        receiver = new MyPermissionReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(MyPermissionReceiver.ACTION);
        registerReceiver(receiver, filter, MyPermissionReceiver.PERMISSION, null);
    }

    private void unRegister() {
        unregisterReceiver(receiver);
    }

 

发送方:

    <uses-permission android:name="com.bsoft.ck.permission.mydemo" />
    private void sendStaticBroadcast() {
        Intent intent = new Intent();
        intent.setPackage(getPackageName());
        intent.setAction(MyPermissionReceiver.ACTION);
        sendBroadcast(intent, MyPermissionReceiver.PERMISSION);
    }

 

六 参考

https://blog.youkuaiyun.com/carson_ho/article/details/52973504

https://www.jianshu.com/p/f348f6d7fe59

https://blog.youkuaiyun.com/weixin_34122604/article/details/92349568

demo:https://github.com/TonyChen-9102/Broadcast

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值