Android 四大组件之 BroadcastReceiver

读前思考

学习一门技术或者看一篇文章最好的方式就是带着问题去学习,这样才能在过程中有茅塞顿开、灯火阑珊的感觉,记忆也会更深刻。

  1. 广播有几种形式?什么特点?
  2. 广播的两种注册形式?区别在哪?
  3. 对于 8.0+ 系统广播会有何不同?

两种注册方式

广播的注册有两种方法:
一种在活动里通过代码动态注册,另一种在配置文件里静态注册
两种方式的相同点是都完成了对接收器以及它能接收的广播值这两个值的定义;不同点是动态注册的接收器必须要在程序启动之后才能接收到广播,而静态注册的接收器即便程序未启动也能接收到广播,比如想接收到手机开机完成后系统发出的广播就只能用静态注册了。

广播的四种形式

普通广播、有序广播、本地广播、粘性广播

1. 普通广播

普通广播是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们接收的先后是随机的。另外,接收器不能截断普通广播。

广播发送(需要适配 8.0+)

安卓系统 8.0 对广播做了如下修改:除了有限的例外情况,应用无法使用清单注册隐式广播。 它们仍然可以在运行时注册这些广播,并且可以使用清单注册专门针对它们的显式广播。

//如果广播接收器为动态注册或 8.0 以下系统的静态注册,则使用如下进行发送

//设置 action
Intent intent = new Intent("com.keven.receiver.MY_BROCASTRECEIVER");
//设置传递数据
Bundle bundle=new Bundle();
bundle.putString("key","Hello Receiver!");
intent.putExtras(bundle);
//发送广播
sendBroadcast(intent);
//如果在 8.0+ 广播接收器仍想用静态注册,则使用如下进行发送

Intent intent = new Intent("com.keven.receiver.MY_BROCASTRECEIVER");
//第一个参数为广播接收器所在应用的包名
//第二个参数为广播接收器包名+类名
intent.setComponent(new ComponentName("com.keven.jianshu","com.keven.jianshu.part1.MyReceiver"));
Bundle bundle=new Bundle();
bundle.putString("key","Hello Receiver!");
intent.putExtras(bundle);
sendBroadcast(intent);

注意:
如果动态注册的广播接收器,当在发送广播时使用 setComponent( ) , 反而是收不到广播的。

广播接收

  1. 新建类继承 BroadcastReceiver
public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle extras = intent.getExtras();
        String value = extras.getString("key");
        LogUtils.i("MyReceiver 收到广播,广播内容是:"+value);
    }
}
  1. 在清单文件中(或动态注册)广播接收器
<!-- 清单文件中注册广播接收器 -->
<receiver
        android:name=".part1.MyReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="com.keven.receiver.MY_BROCASTRECEIVER" />
        </intent-filter>
</receiver>
//代码中动态注册广播接收器
IntentFilter filter = new IntentFilter();
filter.addAction("com.keven.receiver.MY_BROCASTRECEIVER");
MyReceiver receiver = new MyReceiver();
registerReceiver(receiver, filter);

/**
*在 onDestory( ) 方法中解绑
*/
unregisterReceiver(receiver);

当正确注册广播接收器并发送广播后,广播接收器可以正常收到广播。

com.keven.jianshu I/TAG: MyReceiver 收到广播,广播内容是:Hello Receiver!

2. 有序广播

有序广播是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递,所以此时的广播接收器是有先后顺序的,且优先级(priority)高的广播接收器会先收到广播消息。有序广播可以被接收器截断使得后面的接收器无法收到它。

广播发送

Intent intent = new Intent("com.keven.receiver.MY_BROCASTRECEIVER");
Bundle bundle=new Bundle();
bundle.putString("key","Hello Receiver!");
intent.putExtras(bundle);
sendOrderedBroadcast(intent,null);

广播接收

//第一个广播接收器
public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle extras = intent.getExtras();
        String value = extras.getString("key");
        LogUtils.i("MyReceiver 收到广播,广播内容是:"+value);
    }
}


//第二个广播接收器
public class MyReceiver2 extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle extras = intent.getExtras();
        String value = extras.getString("key");
        LogUtils.i("MyReceiver2 收到广播,广播内容是:"+value);
    }
}

广播注册(为了方便适配直接使用动态注册)

filter1 = new IntentFilter();
filter1.addAction("com.keven.receiver.MY_BROCASTRECEIVER");
filter1.setPriority(100);
receiver = new MyReceiver();
registerReceiver(receiver, filter1);

filter2 = new IntentFilter();
filter2.addAction("com.keven.receiver.MY_BROCASTRECEIVER");
filter2.setPriority(200);
receiver2 = new MyReceiver2();
registerReceiver(receiver2, filter2);


/**
*在 onDestory( ) 方法中解绑
*/
unregisterReceiver(receiver);
unregisterReceiver(receiver2);

结果输出

com.keven.jianshu I/TAG: MyReceiver2 收到广播,广播内容是:Hello Receiver!
com.keven.jianshu I/TAG: MyReceiver 收到广播,广播内容是:Hello Receiver!

可以看到,广播接收器 2 先收到了广播,接收器 1 后收到了广播,所以 Priority 数值越大,优先级越高,越先收到广播。

如果在广播接收器中调用 abortBroadcast( ) 方法,则之后的接收器无法收到该广播!

public class MyReceiver2 extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle extras = intent.getExtras();
        String value = extras.getString("key");
        LogUtils.i("MyReceiver2 收到广播,广播内容是:"+value);
        
        //如果在广播接收器中调用 abortBroadcast( ) 方法,则之后的接收器无法收到该广播
        abortBroadcast();
    }
}

3. 本地广播

本地广播机制,使用这个机制发出的广播只能够在应用程序的内部进行传递,并且广播接收器也只能接收本应用程序发出的广播。

发送广播

//先获取 LocalBroadcastManager
LocalBroadcastManager localBroadcastManager=LocalBroadcastManager.getInstance(this);
Intent intent = new Intent("com.keven.receiver.MY_BROCASTRECEIVER");
Bundle bundle=new Bundle();
bundle.putString("key","Hello Receiver!");
intent.putExtras(bundle);
//通过 LocalBroadcastManager 进行广播发送
localBroadcastManager.sendBroadcast(intent);

广播接收

public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle extras = intent.getExtras();
        String value = extras.getString("key");
        LogUtils.i("MyReceiver 收到广播,广播内容是:"+value);
    }
}

广播注册

//先获取 LocalBroadcastManager
localBroadcastManager = LocalBroadcastManager.getInstance(MainActivity.this);
filter1 = new IntentFilter();
filter1.addAction("com.keven.receiver.MY_BROCASTRECEIVER");
filter1.setPriority(100);
receiver = new MyReceiver();
//通过 LocalBroadcastManager 进行广播注册
localBroadcastManager.registerReceiver(receiver, filter1);


/**
*在 onDestory( ) 方法中使用 LocalBroadcastManager 解绑
*/
localBroadcastManager.unregisterReceiver(receiver);

4. 粘性广播

通过 Context.sendStickyBroadcast() 方法可发送粘性 (sticky) 广播,这种广播会一直滞留,当有匹配该广播的接收器被注册后,该接收器就会收到此条广播。

注意,发送粘性广播还需要BROADCAST_STICKY权限:

<uses-permission android:name="android.permission.BROADCAST_STICKY"/>

sendStickyBroadcast() 只保留最后一条广播,并且一直保留下去,这样即使已经有广播接收器处理了该广播,一旦又有匹配的广播接收器被注册,该粘性广播仍会被接收。如果只想处理一遍该广播,可通过 removeStickyBroadcast() 方法来实现。接收粘性广播的过程和普通广播是一样的,不再过多赘述。

文章已经读到末尾了,不知道最初的几个问题你都会了吗?如果不会的话?可以再针对不会的问题进行精读哦!答案都在文中,相信你肯定可以解决的!

    原文作者:kevenZheng
    原文地址: https://www.jianshu.com/p/85e85bcbee58
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞