深入探讨BroadcastReceiver

本文详细解析了Android中BroadcastReceiver的工作原理,包括普通广播与有序广播的区别、如何发送与接收广播,以及广播优先级的设定与应用案例。
关于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以后的版本中都可以看到。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值