Android基础 —— Broadcast 使用

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

Broadcast 类型

普通广播

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

有序广播

按照接收者声明的优先级别(声明在元素的属性中,数越大优先级别越高,取值范围:-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 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()这个函数回来去处理异步的操作,但是这个广播接收者不再被激活,系统将会在异步操作完成前结束进程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值