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() 方法来实现。接收粘性广播的过程和普通广播是一样的,不再过多赘述。

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容