Broadcast 应该知道的

在Android中,Broadcast是一种广泛运用的在应用程序之间传输信息的机制。所以非常有必要详细学习一下 Broadcast 的使用。

Broadcast 类型

普通广播

完全异步的,可以在同一时刻(逻辑上)被所有接收者接收到,消息传递的效率比较高,但缺点是:接收者不能将处理结果传递给下一个接收者,并且无法终止广播Intent的传播。

有序广播

按照接收者声明的优先级别(声明在<intent-filter>元素的<android:priority>属性中,数越大优先级别越高,取值范围:-1000到1000。也可以调用IntentFilter对象的setPriority()进行设置),被接收者依次接收广播。如:A的级别高于B,B的级别高于C,那么,广播先传给A,再传给B,最后传给C。A得到广播后,可以往广播里存入数据,当广播传给B时,B可以从广播中得到A存入的数据。

Broadcast 注册方式

无论是什么注册方式,都要创建实现BroadcastReceiver 类并实现 onReceive 方法:

public class MyBroadcast extends BroadcastReceiver{
    private static final String TAG = "MyBroadcast";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG,"broadcast msg ----->" + intent.getStringExtra("name"));
        Log.d(TAG,"broadcastReceiver  ----->");
    }
}

Broadcast 静态注册

隐式注册只要在 AndroidManifest.xml 中用<receiver>标签注册,并在标签内用<intent-filter>标签设置过滤器。
注册代码如下:

<receiver android:name=".broadcast.MyBroadcast">
    <intent-filter>
        <action android:name="com.cfox.boradcast"/>
    </intent-filter>
</receiver>

发送广播代码:

Intent intent = new Intent();
intent.putExtra("name","my broadcast");
intent.setAction("com.cfox.boradcast");
sendBroadcast(intent);

Broadcast 动态注册

定义并设置好一个 IntentFilter 对象,然后在需要注册的地方调Context.registerReceiver()方法,如果取消时就调用 Context.unregisterReceiver()方法。如果用动态方式注册的BroadcastReceiver的Context对象被销毁时,BroadcastReceiver也就自动取消注册了。

注册代码如下

IntentFilter filter = new IntentFilter();
filter.addAction("com.cfox.boradcastFilter");
MyBroadcast broadcast = new MyBroadcast();
registerReceiver(broadcast,filter);

发送代码如下

Intent intent = new Intent();
intent.putExtra("name","my broadcast");
intent.setAction("com.cfox.boradcastFilter");
sendBroadcast(intent);

普通广播

上面介绍的都是基于普通广播的,在这里就不多说了,重新贴一下上面的代码,复习一下吧。
注册代码如下:

<receiver android:name=".broadcast.MyBroadcast">
    <intent-filter>
        <action android:name="com.cfox.boradcast"/>
    </intent-filter>
</receiver>

发送广播代码:

Intent intent = new Intent();
intent.putExtra("name","my broadcast");
intent.setAction("com.cfox.boradcast");
sendBroadcast(intent);

有序广播的使用

使用有序广播,我们要对其设置优先级,上面有说,所以在这里不再介绍。
注册代码(静态):

<receiver android:name=".broadcast.MyBroadcastOne" >
    <intent-filter android:priority="1000">
        <action android:name="com.cfox.broadcast"/>
    </intent-filter>
</receiver>

<receiver android:name=".broadcast.MyBroadcastTow" >
    <intent-filter android:priority="999">
        <action android:name="com.cfox.broadcast"/>
    </intent-filter>
</receiver>

注册代码(动态):

IntentFilter filter1 = new IntentFilter();
filter1.addAction("com.cfox.broadcast");
filter1.setPriority(1000);
MyBroadcastOne broadcastOne = new MyBroadcastOne();
registerReceiver(broadcastOne,filter1);

IntentFilter filter2 = new IntentFilter();
filter2.addAction("com.cfox.broadcast");
filter2.setPriority(999);
MyBroadcastTow broadcastTwo = new MyBroadcastTow();
registerReceiver(broadcastTwo,filter2);
发送有序广播

首先我们要先看一下,发送有序广播的方法:

sendOrderedBroadcast(
        Intent intent, String receiverPermission, BroadcastReceiver resultReceiver,
        Handler scheduler, int initialCode, String initialData,
        Bundle initialExtras)

参数很多,下面我们来介绍一下:

  • 参数1:Intent
  • 参数2:设置broadcast 权限
  • 参数3:这是一个广播(broadcastReceiver),改广播在有序广播结束后调用该广播,如果有序广播在执行中被终止了,则这个广播将不会被执行。
  • 参数4:Handler,可以为null,如果为 null ,将会使用主线程中的 Context
  • 参数5:结果码,经常Activity.RESULT_OK
  • 参数6:初始数据,可以在 onReceive 中使用 getResultData() 方法获取。通常为null.
  • 参数7:Bundle , 经常为null

下面我们看看如何发送一个有序广播:

Intent intent = new Intent();
intent.putExtra("name","my broadcast");
intent.setAction("com.cfox.broadcast");
sendOrderedBroadcast(intent,null,new Receiver(),null,0,"hello good",null);

代码不多,也不必解释,下面把继承 BroadcastReceiver 类贴一下:

  • MyBroadcastOne.class
public class MyBroadcastOne extends BroadcastReceiver {
    private static final String TAG = "MyBroadcastOne";
    @Override
    public void onReceive(Context context, Intent intent) {

        Log.d(TAG,"MyBroadcastOne msg ----->" + intent.getStringExtra("name"));
        Log.d(TAG,"MyBroadcastOne  ----->");
        Log.d(TAG,"receiver--isOrderedBroadcast-->" + isOrderedBroadcast());

        if (intent.getStringExtra("name").equals("my broadcast")){
            Log.d(TAG,"ResultData msg ----->" + getResultData());
            setResultData(getResultData() + " good good");
//            abortBroadcast();// 终止广播
        }
    }
}
  • MyBroadcastTow.class
public class MyBroadcastTow extends BroadcastReceiver{
    private static final String TAG = "MyBroadcastTow";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG,"MyBroadcastTow msg ----->" + intent.getStringExtra("name"));
        Log.d(TAG,"MyBroadcastTow  ----->");
        Log.d(TAG,"ResultData msg ----->" + getResultData());
        Log.d(TAG,"receiver--isOrderedBroadcast-->" + isOrderedBroadcast());
    }
}
  • Receiver
public class Receiver extends BroadcastReceiver {
    private static final String TAG = "Receiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG,"ResultData msg ----------->" + getResultData());
        Log.d(TAG,"receiver--isOrderedBroadcast-->" + isOrderedBroadcast());

    }
}

运行结果
D/MyBroadcastOne: MyBroadcastOne msg ----->my broadcast
D/MyBroadcastOne: MyBroadcastOne  ----->
D/MyBroadcastOne: receiver--isOrderedBroadcast-->true
D/MyBroadcastOne: ResultData msg ----->hello good
D/MyBroadcastTow: MyBroadcastTow msg ----->my broadcast
D/MyBroadcastTow: MyBroadcastTow  ----->
D/MyBroadcastTow: ResultData msg ----->hello good good good
D/MyBroadcastTow: receiver--isOrderedBroadcast-->true
D/Receiver: ResultData msg ----------------------->hello good good good
D/Receiver: receiver--isOrderedBroadcast-->false

看到运行结果,很多东西就都清楚了。下面再简单介绍一下。

终止有序广播

在有序广播中onReceive 方法中适当的位置调用 abortBroadcast() 方法终止广播。

一些方法介绍

  • isOrderedBroadcast()
    判断该 BroadcastReceiver 是不是有序广播。
  • getResultData()
    获取 BroadcastReceiver 间传递数据,这个数据可以在发送有序广播时通过第六个参数进行初始化设置。

使用 LocalBroadcastManager 动态注册

IntentFilter filter1 = new IntentFilter();
filter1.addAction("com.cfox.broadcast");
filter1.setPriority(1000);
MyBroadcastOne broadcastOne = new MyBroadcastOne();

IntentFilter filter2 = new IntentFilter();
filter2.addAction("com.cfox.broadcast");
filter2.setPriority(999);
MyBroadcastTow broadcastTwo = new MyBroadcastTow();

LocalBroadcastManager.getInstance(this).registerReceiver(broadcastOne,filter1);
LocalBroadcastManager.getInstance(this).registerReceiver(broadcastTwo,filter2);

不同注册方式的广播接收器回调onReceive(context, intent)中的context具体类型

以下内容参考自:http://blog.csdn.net/oonullpointeralex/article/details/48015107

  • 对于静态注册的ContextReceiver,回调onReceive(context, intent)中的context具体指的是ReceiverRestrictedContext;
  • 对于全局广播的动态注册的ContextReceiver,回调onReceive(context, intent)中的context具体指的是Activity Context;
  • 对于通过LocalBroadcastManager动态注册的ContextReceiver,回调onReceive(context, intent)中的context具体指的是Application Context。
  • :对于LocalBroadcastManager方式发送的应用内广播,只能通过LocalBroadcastManager动态注册的ContextReceiver才有可能接收到(静态注册或其他方式动态注册的ContextReceiver是接收不到的)。

使用注意

静态注册的广播接收器即使app已经退出,主要有相应的广播发出,依然可以接收到,但此种描述自Android 3.1开始有可能不再成立.

Android 3.1开始系统在Intent与广播相关的flag增加了参数,分别是FLAG_INCLUDE_STOPPED_PACKAGES和FLAG_EXCLUDE_STOPPED_PACKAGES。

  • FLAG_INCLUDE_STOPPED_PACKAGES:包含已经停止的包(停止:即包所在的进程已经退出)
  • FLAG_EXCLUDE_STOPPED_PACKAGES:不包含已经停止的包。

主要原因如下:
自Android3.1开始,系统本身则增加了对所有app当前是否处于运行状态的跟踪。在发送广播时,不管是什么广播类型,系统默认直接增加了值为FLAG_EXCLUDE_STOPPED_PACKAGES的flag,导致即使是静态注册的广播接收器,对于其所在进程已经退出的app,同样无法接收到广播。

由此,对于系统广播,由于是系统内部直接发出,无法更改此intent flag值,因此,3.1开始对于静态注册的接收系统广播的BroadcastReceiver,如果App进程已经退出,将不能接收到广播。

但是对于自定义的广播,可以通过复写此flag为FLAG_INCLUDE_STOPPED_PACKAGES,使得静态注册的BroadcastReceiver,即使所在App进程已经退出,也能能接收到广播,并会启动应用进程,但此时的BroadcastReceiver是重新新建的。

Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION);
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.putExtra("name", "qqyumidi");
sendBroadcast(intent);

注1:对于动态注册类型的BroadcastReceiver,由于此注册和取消注册实在其他组件(如Activity)中进行,因此,不受此改变影响。
注2:在3.1以前,相信不少app可能通过静态注册方式监听各种系统广播,以此进行一些业务上的处理(如即时app已经退出,仍然能接收到,可以启动service等..),3.1后,静态注册接受广播方式的改变,将直接导致此类方案不再可行。于是,通过将Service与App本身设置成不同的进程已经成为实现此类需求的可行替代方案。

BroadcastReceiver中不要执行耗时操作

BroadcastReceiver的生命周期比较短,一些比较费时的操作不应该放在onReceiver里完成。如果在onReceiver()的方法不能在10秒内执行完成,将会产生程序无响应也就是我们熟悉的ANR(Application not Response)。

广播接收者的对象只有在回调onReceive()这个函数时有效,一旦从这个函数返回,这个对象就被结束,不再激活。在onReceive()中,任何异步的操作都是不可行的。因为需要从onRecive()这个函数回来去处理异步的操作,但是这个广播接收者不再被激活,系统将会在异步操作完成前结束进程。

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

推荐阅读更多精彩内容

  • 1.Android广播机制概述 Android广播分为两个方面:广播发送者和广播接收者,通常情况下,Broadca...
    IT小魔女的故事阅读 556评论 0 2
  • 诸多无奈,最近在改一个项目的bug的时候,脑子老是一片空白,可能是最近脑子不够用,总之,好多东西忘了,阅读一些别人...
    狗子王1948阅读 7,718评论 6 53
  • 前言 本来想写一下广播的,发现查阅后有整理的不错的,只好转载图个简便,日后好复习转载:http://www.cnb...
    提升即效率阅读 1,387评论 0 10
  • 广播接收器 是Android的四大组件之一,可见广播在Android中的重要性; 1. 什么是广播? 广播(Bro...
    Lost_Robot阅读 1,954评论 2 10
  • 我家小儿,两岁半,常日在工作室混,伴着我码字,看书,备课,活动的范围就在工作室里,偶尔自己出去,也就在门前...
    肖尧阅读 609评论 0 0