Broadcast(广播)和BroadcastReceiver(广播接收器)

BroadcastReceiver 简介

广播接收者( BroadcastReceiver )用于接收广播 Intent ,广播 Intent 的发送是通过调用Context.sendBroadcast() 、 Context.sendOrderedBroadcast() 、 Context.sendStickyBroadcast()来实现的通常一个广播 Intent 可以被订阅了此 Intent 的多个广播接收者所接收(就像真的收音机一样)。

广播(Broadcas)是一种广泛运用的在应用程序之间传输信息的机制 。而 广播接收者(BroadcastReceiver)是对发送出来的广播进行过滤接收并响应的一类组件。

来自普通应用程序,如一个应用程序通知其他应用程序某些数据已经下载完毕。

BroadcastReceiver 自身并不实现图形用户界面,但是当它收到某个通知后, BroadcastReceiver 可以启动Activity 作为响应,或者通过 NotificationMananger 提醒用户,或者启动 Service 等等。

BroadcastReceiver 广泛应用与应用间的交流。官方文档有这么一段话:

If you don't need to send broadcasts across applications, consider using this class with LocalBroadcastManager instead of the more general facilities described below. This will give you a much more efficient implementation (no cross-process communication needed) and allow you to avoid thinking about any security issues related to other applications being able to receive or send your broadcasts.

意思是说, 如果你的广播信息是用于应用的自我交流(不需要与其它应用协作),那么建议使用LocalBroadcastManager。LocalBroadcastManager 比 BroadcastReceiver 有更高的传输效率,并且避免了 BroadcastReceiver 中存在的安全问题。因为BroadcastReceiver发送的消息游走与整个Android系统之间,并且有可能被别的应用恶意串改。

BroadcastReceiver生命周期

每次广播到来时 , 会重新创建 BroadcastReceiver 对象 , 并且调用 onReceive() 方法 , 执行完以后 , 该对象即被销毁 . 当 onReceive() 方法在 10 秒内没有执行完毕,就会导致ANR。如果需要执行长任务,那么就有必要使用Service。千万不要使用新线程,这是很危险的事情。因为有可能线程没有执行完,BroadcastReceiver就挂了。
另外注意, BroadcastReceiver 会堵塞主线程。唯有 onReceive() 结束,主线程才得以继续进行。

注册BroadcastReceiver

先来说说怎样接收广播。如其他组件一样,BroadcastReceiver是要注册的,但是不同的是,BroadcastReceiver可以动态注册,也可以静态注册。
在 Android 的广播机制中,动态注册(即代码注册)的优先级是要高于静态注册(AndroidMainifest注册)优先级的,因此在必要的情况下,我们是需要动态注册广播接收器的。

静态注册


和其他组件一样,在AndroidMainfest.xml里面直接声明,这样在整个应用运行过程中,这个广播都处于注册状态,每时每刻都能收到指定广播Action。
receiver位置与activity于同一级别。
        <receiver android:name=".MyBroadcastReceiver" >
            <intent-filter android:priority="1000" >
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
            </intent-filter>
        </receiver>
android:priority表示优先级,Android官方规定范围为-1000到1000。优先级的用处在于,在有序的广播中能够更靠前的获得消息。然而实际上,当 priority 值为integer 的最大值才时,才是优先级最高的,即  2147483647;当然,“最高”只是限于静态注册。
上面是注册一个监听手机网络变化的广播。注意,标签是receiver而不是broadcastreceiver。
当然,要能正常监听到广播,还得加上权限声明:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

这样,一个静态的广播就注册好了。当然你也可以不定义action,那样你有权限收到的广播,都会收到,但是这样有一个问题就是,你收到不必要的广播也会启动BroadcastReceiver占用资源 ,而且还得自己过滤,比较麻烦,所以在最好把你需要的广播定义在intent-filter里面。action可以定义不止一个,可以定义多个,一个BroadcastReceiver可以监听多种广播,就像收音机有多个频道一样。
MyBroadcastReceiver代码:
手机网络状态当然不只有无网络,wifi和default三种,但是在我手机里面只有这三种,没有4G网络,没有其他的,所以只列了这三种状态。在现在很多大流量的APP中,都会有这样的提示,比如某某音乐,你点了一首歌,开始下载,或者下载到一半网络变化了,若不是WIFI状态,会提醒你,“不是wifi状态,是否继续”一般就是监听的这个广播。
public class MyBroadcastReceiver extends BroadcastReceiver {

	@Override
	public void onReceive(Context context, Intent intent) {
		ConnectivityManager connectivityManager = (ConnectivityManager) context
				.getSystemService(Context.CONNECTIVITY_SERVICE);
		NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();

		if(activeNetInfo == null) {
			sLog("无网络状态");
		} else {
			switch(activeNetInfo.getType()) {
			case ConnectivityManager.TYPE_WIFI:
				sLog("WIFI状态");
				break;
			default :
				sLog("3G/2G状态");
				break;
			}
		}
	}

	private void sLog(String msg) {
		Log.e("NetworkChangeReceiver", msg);
	}
}
注意了,该类必须是public的。
每当你改变网络状态一次,BroadcastReceiver都会被调用一次。
运行结果如下:
运行结果.png

动态注册

动态注册,顾名思义,在需要的时候就注册这个广播,不需要的时候就注销掉。收音机不用了就关掉,省电。动态注册不需要在AndroidMainifest里面注册。因此,对于动态注册,不需要对AndroidManifest.xml文件进行任何改动。
然后在Activity中注册,方法如下:
public class MainActivity extends Activity {
	
	private MyBroadcastReceiver receiver = new MyBroadcastReceiver();
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		IntentFilter filter = new IntentFilter();
        filter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        this.registerReceiver(receiver, filter);
	}
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
		unregisterReceiver(receiver);
	}

}

逻辑上与AndroidMainifest注册是一样的,不过动态注册要注意生命周期问题,记得要调用注销unregisterReceiver()。当然,你也可以在Activity生命周期其他阶段调用,但必须要对应。

发送Broadcast

发送广播有三种方式: Context.sendBroadcast() 、 Context.sendOrderedBroadcast() 和 Context.sendStickyBroadcast()

同步广播(也叫“普通广播”,Context.sendBroadcast()):

发送方发出后,几乎同时到达多个广播接收者处,某个接收者不能接收到广播后进行一番处理后传给下一个接收者,并且无法终止广播继续传播。也就是说,每个广播接收者所收到的广播都是一模一样的,没有应用能够对其进行窜改。

有序广播(Context.sendOrderedBroadcast()):

广播接收者需要提前设置优先级,优先级高的先接收到广播,优先级数值为-1000~1000,在AndroidManifest.xml的<intent-filter android:priority="xxx">设置;比如存在3个广播接收者A、B、C,优先级A>B>C,因此A最先收到广播,当A收到广播后,可以向广播中添加一些数据给下一个接收者(intent.putExtra()),或者终止广播(在当前BroadcastReceiver内调用方法 abortBroadcast() );

异步广播(Context.sendStickyBroadcast()):
能力有限,无法在此详细解答。

同步广播(Context.sendBroadcast())

如下代码:
		Intent intent = new Intent();  
        intent.setAction("com.plusjun.test.hahaha");  
        intent.putExtra("name", "xiazdong");  
        MainActivity.this.sendBroadcast(intent);
一个广播就完成了。
这是再普通不过的广播了。广播的标识符就是“com.plusjun.test.hahaha”。

有序广播(Context.sendOrderedBroadcast())

如下代码
Intent intent = new Intent();  
intent.setAction("com.plusjun.test.hahaha");  
intent.putExtra("name", "xiazdong");  
MainActivity.this.sendOrderedBroadcast(intent, null);
这就是有序广播。
广播会按照广播接收器的权限级别来逐个发送,数值越大,权限越大,越靠前;动态注册比静态注册权限高。只有等一个接收器完成工作了,才能轮到下一个接收器接收。
在接收器中,可以对Intent进行窜改,也可以调用 abortBroadcast() 方法停止往下传递。调用 abortBroadcast() 后,权限比他低的接收器就再也收不到这个广播了。
接收器拦截传递的例子:
public class MyReceiver extends BroadcastReceiver {  
	@Override  
	public void onReceive(Context context, Intent intent) {  
		String name = intent.getExtras().getString("name");  
		Log.i("Recevier", "接收到:"+name);  
		abortBroadcast();   //Receiver接收到广播后中断广播  
	}  
}  

异步广播(Context.sendStickyBroadcast()):

能力有限了,无法解说。找个时间再研究研究。
摘抄官方原文:
public voidsendStickyBroadcast(Intent intent)
Added in API level 1
该方法需要拥有 BROADCAST_STICKY 权限。

Perform a sendBroadcast(Intent) that is "sticky," meaning the Intent you are sending stays around after the broadcast is complete, so that others can quickly retrieve that data through the return value ofregisterReceiver(BroadcastReceiver, IntentFilter). In all other ways, this behaves the same assendBroadcast(Intent).

You must hold the BROADCAST_STICKY permission in order to use this API. If you do not hold that permission,SecurityException will be thrown.



需要收听权限的广播

先看看代码:
sendOrderedBroadcast(new Intent("com.plusjun.test.hahaha"), "com.plusjun.test");

代码中与上述例子最大的差别在于Activity中发送广播的方法:

sendOrderedBroadcast(new Intent("com.plusjun.test.hahaha"), "com.plusjun.test");

在第二个参数增加了一个字符串。

在发起广播的应用中,需要在AndroidManifest文件中配置自定义的权限:

<permission android:protectionLevel="normal" android:name="com.plusjun.test"></permission>

相应的,接收器所在的应用中必须设置接收权限:

<uses-permission android:name="com.plusjun.test"></uses-permission>

这样,接收器就可以正确接收到广播了。



http://blog.csdn.net/woaieillen/article/details/7376391
在此表示感谢。
转载请注明来源,版权归原作者所有,未经同意严禁用于任何商业用途。
微博:http://weibo.com/theworldsong
邮箱:theworldsong@foxmail.com
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值