您的位置:首页 > 移动开发 > Android开发

深入探讨BroadcastReceiver

2014-05-05 18:17 351 查看
关于BroadcastReceiver的基础讲解部分,请参考点击打开链接点击打开链接

下面将深入讲解广播接受者:

一:广播的种类:

上节提到,当系统以一个Intent的形式发送一个Broadcast出去之后,所有与之匹配的BroadcastReceiver都会被实例化,但是这里是有区别的,根据Broadcast的传播方式区别,在系统中有如下两种Broadcast:

    普通广播:Normal Broadcase,它是完全异步的,也就是说,在逻辑上,当一个Broadcast被发出之后,所有的与之匹配的BroadcastReceiver都同时接收到Broadcast。优点是传递效率比较高,但是也有缺点,就是一个BroadcastReceiver不能影响其他响应这条Broadcast的BroadcastReceiver。

    有序广播:Ordered Broadcast,它是同步执行的,也就是说有序广播的接收器将会按照预先声明的优先级依次接受Broadcast,是链式结构,优先级越高(-1000~1000),越先被执行。因为是顺序执行,所有优先级高的接收器,可以把执行结果传入下一个接收器中,也可以终止Broadcast的传播(通过abortBroadcast()方法),一旦Broadcast的传播被终止,优先级低于它的接收器就不会再接收到这条Broadcast了。

  虽然系统存在两种类型的Broadcast,但是一般系统发送出来的Broadcast均是有序广播,所以可以通过优先级的控制,在系统内置的程序响应前,对Broadcast提前进行响应。这就是市场上一些拦截器类(如:短信拦截器、电话拦截器)的软件的原理。

如何发送一个广播

  上面已经介绍了系统中两种不同的Broadcast,而根据Broadcast传播的方式,Context提供了不同的方法来发布它们:

    sendBroadcast():发送普通广播。

    sendOrderedBroadcast():发送有序广播。

  以上两个方法都有多个重载方法,根据不同的场景使用,最简单的莫过于直接传递一个Intent来发送一个广播。

 

如何使用BroadcastReceiver

   BroadcastReceiver本质上还是一个监听器,所以使用BroadcastReceiver的方法也是非常简单,只需要继承BroadcastReceiver,在其中重写onReceive(Context context,Intent intent)即可。一旦实现了BroadcastReceiver,并部署到系统中后,就可以在系统的任何位置,通过sendBroadcast、sendOrderedBroadcast方法发送Broadcast给这个BroadcastReceiver。

  但是仅仅继承BroadcastReceiver和实现onReceive()方法是不够的,同为Android系统组件,它也必须在Android系统中注册,注册一个BroadcastReceiver有两种方式:

    在代码中使用Content.registerReceiver(BroadcastReceiver receiver, IntentFilter filter)进行注册,在使用完毕使用Content.unregisterReceiver(BroadcastReceiver receiver)方法进行注销。

    使用清单文件AndroidManifest.xml注册,在<application/>节点中,使用<receiver/>节点注册,并用android:name属性中指定注册的BroadcastReceiver对象,一般还会通过<Intent-filter/>指定<action/>和<category/>,并在<Intent-filter/>节点中通过android:priority属性设置BroadcastReceiver的优先级,在-1000~1000(没有测试过,有些文档说是Integer.Max什么的)范围内,数值越到优先级越高。

二:广播的优先级

 经过上面的说明,我们知道广播可以设定优先级。优先级越高的广播接收者会最先收到广播。参考下面例子。

在manifest文件中注册下面3个广播接收者:

<receiver android:name="cn.test.Receiver1">
<intent-filter android:priority="1000">
<action android:name="cn.test.receiver.priority"/>
</intent-filter>
</receiver>

<receiver android:name="cn.test.Receiver2">
<intent-filter android:priority="500">
<action android:name="cn.test.receiver.priority"/>
</intent-filter>
</receiver>

<receiver android:name="cn.test.Receiver3">
<intent-filter android:priority="-1000">
<action android:name="cn.test.receiver.priority"/>
</intent-filter>
</receiver>


定义3个广播接受者:

public class Receiver1 extends BroadcastReceiver {
private static final String tag = "Receiver1";

@Override
public void onReceive(Context arg0, Intent intent) {
if(intent.getAction().equals("cn.test.receiver.priority")){
Log.e(tag, "action===="+intent.getAction());
}
}

}

public class Receiver2 extends BroadcastReceiver {
private static final String tag = "Receiver2";

@Override
public void onReceive(Context arg0, Intent intent) {
if(intent.getAction().equals("cn.test.receiver.priority")){
Log.e(tag, "action===="+intent.getAction());
}
}

}

public class Receiver3 extends BroadcastReceiver {
private static final String tag = "Receiver3";

@Override
public void onReceive(Context arg0, Intent intent) {
if(intent.getAction().equals("cn.test.receiver.priority")){
Log.e(tag, "action===="+intent.getAction());
}
}

}


main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >

<Button
android:text="测试广播接收者的优先级"
android:id="@+id/btn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>

</LinearLayout>


MainActivity.java核心代码及测试结果:

findViewById(R.id.btn).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
sendBroadcast(new Intent("cn.test.receiver.priority"));

}
});


结果发现:Receiver1、Receiver2、Receiver3依次收到了广播。优先级最高的最先收到了广播。

扩展知识点:

我们设置完优先级后,还可以在优先级高的广播接收者中去拦截(有些说是中断)广播,那么优先级低的就得不到广播我们该怎么办?解决方案:

上面代码中修改Receiver1的代码,添加一句:

abortBroadcast();    //添加拦截部分


修改MainActivity.java中代码:

findViewById(R.id.btn).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
sendOrderedBroadcast(new Intent("cn.test.receiver.priority"), null, new Receiver3(),
null, 0, null, null);
}
});

总结:经过测试发现,当我们指定了要接收的广播接收者之后,我们希望处理事件的广播接收者一样可以收到广播。



其实,我们看android系统短信源码即可看到,系统注册的通知即为有序广播,并指定最终的广播接收者。

这样可以防止第三方应用注册广播后拦截系统的收件箱。在android4.0以后的版本中都可以看到。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息