BroadcastReceiver是四大组件之一,有接收广播机制,相对应就有发送广播机制。Android中,通过该机制,使得消息能在各个组件间、各个进程间传递,起到邮递员的作用。Broadcast在Android系统中应用的非常广泛,比如电池状态的变化、电话的接收、短信的接收、键盘输入法切换和网络连接状态变化都会由系统发送一个广播,然后应用程序通过BroadCastReceiver可以监听这些广播并作出相应的处理。此外,BroadCastReceiver可以通过监听其它应用程序发送的广播接收传递过来的信息进而实现进程间的通信,我们再查看一下BroadcastReceiver的源码可以看到IBinder影子,就不难理解其中的原理了(Android进程通信是用IBinder实现的)。
按照跨进程和不跨进程进行分类,可以分成两种:LocalBroadcastManager、BroadcastReceiver两种。
一、BroadcastReceiver
当需要发送能够跨线程、跨进程的广播时,就可以使用BroadcastReceiver了。它接受的对象是Intent,Intent可以携带Action,也可以携带数据等。每一个BroadcastReceiver都需要建立一个Intent-filter,不然就无法过滤不想收到的Intent对象。而当某个线程想发一个广播给某个广播接收器时,发送的Intent的Action必须符合该广播接收器的Intent-filter的Action,不然无法接收。
我们再查看一下BroadcastReceiver的源码可以看到IBinder影子,就不难理解其中的原理了(Android进程通信是用IBinder实现的)。
BroadCastReceiver的使用方式分为:静态注册和动态注册
静态注册:
<receiver android:name="com.aoaoyu.receiver.TestBroadcastReceiver" android:enabled="true" android:process=":push"> <intent-filter android:priority="0x7fffffff"> <!-- 系统广播: 开屏 --> <action android:name="android.intent.action.USER_PRESENT"/> <!-- 系统广播: 网络切换 --> <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/> <!-- 系统广播: 开机 --> <action android:name="android.intent.action.BOOT_COMPLETED"/> <!-- 系统广播: USB插拔 --> <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/> <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/> <!-- 系统广播: 电池 --> <action android:name="android.intent.action.BATTERY_CHANGED"/> </intent-filter> </receiver>
动态注册:
IntentFilter _Filter = new IntentFilter(); _Filter.setPriority(0x7fffffff); //系统广播: 开屏 _Filter.addAction(Intent.ACTION_USER_PRESENT); //系统广播: 开机 _Filter.addAction(Intent.ACTION_BOOT_COMPLETED); //系统广播: USB插拔 _Filter.addAction(Intent.ACTION_POWER_CONNECTED); _Filter.addAction(Intent.ACTION_POWER_DISCONNECTED); //系统广播: 电池信息变化 _Filter.addAction(Intent.ACTION_BATTERY_CHANGED); //系统广播: 网络切换 _Filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); pContext.getApplicationContext().registerReceiver(mTestBroadcastReceiver, _Filter);
两者的区别就是前者注册是属于常驻型,就是在应用程序一开启,以该种类型注册的BroadcastReceiver就可以一直接收到系统或其它应用发送过来的广播。而后者由于在类中注册的,所以它的生命周期是跟随类对象的,若该类对象被停止销毁了,在该类中注册的BroadcastReceiver也会随之销毁。两种注册方式都有各自的特点,我们可以根据具体情况来选择需要使用哪种注册方式。
BroadCast的分类
(1)普通广播-BroadcastReceiver
通过Context.sendBroadcast发送的广播即为普通广播,发送普通广播是最常见也是使用最多的一种广播发送方式,它的特点就是当有多个BroadcastReceiver同时接收一个广播的时候,它们都是异步接收的的,换句话说就是各个BroadcastReceiver之间接收广播的时候互不干扰,互不影响,由此便可知该广播对于每个BroadcastReceiver来说,各自都无法阻止其它BroadcastReceiver的接收动作。
(2)有序广播-OrderedBroadcastReceiver
通过Context.sendOrderedBroadcast发送的广播即为有序广播,与普通广播的不同在于,接收者是有序接收到广播的并且可以对广播进行修改或是取消广播向下传递。系统根据接收者定义的优先级顺序决定哪个接收者先接收到它,接收者处理完后可以将结果传递给优先级低的接收者也可以停止广播使得其他优先级低的接收者无法接收到该广播。优先级通过android:priority属性定义,数值越大优先级别越高,取值范围:-1000到1000,虽然API文档介绍对sendBroadcast发送的广播无效,不过本人测试同样有效,相同优先级的接收者接收到广播的顺序随机。Android系统收到短信、接到电话后发送的广播都是有序广播,所以可以进行短信或电话的拦截,即取消广播。
PS:有序广播可以在onReceive函数中通过BroadcastReceiver的abortBroadcast接口(这个接口对sendBroadcast发送广播无效)取消广播,通过接口sendOrderedBroadcast(Intent, String, BroadcastReceiver, android.os.Handler, int, String, Bundle)发送的广播即便优先级高的广播取消了广播,接口参数中指定的BroadcastReceiver依然可以在其他接收者处理完后接收到广播。通过BroadcastReceiver的getResultExtras接口获得结果的Bundle再通过Bundle的putString和getString方法修改或获取数据,可以见本文最后的实例代码举例。
(3)普通粘性广播-Sticky Broadcast
如果发送者发送了某个广播,而接收者在这个广播发送后才注册自己的Receiver,这时接收者便无法接收到刚才的广播,为此Android引入了StickyBroadcast,在广播发送结束后会保存刚刚发送的广播(Intent),这样当接收者注册完Receiver后就可以继续使用刚才的广播。如果在接收者注册完成前发送了多条相同Action的粘性广播,注册完成后只会收到一条该Action的广播,并且消息内容是最后一次广播内容。系统网络状态的改变发送的广播就是粘性广播。
粘性广播通过Context的sendStickyBroadcast(Intent)接口发送,需要添加权限<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
也可以通过Context的removeStickyBroadcast(Intent intent)接口移除缓存的粘性广播。
(4)粘性有序广播-StickyOrderedBroadcast
有序粘性广播其实也和有序广播的特点是差不多的,只不过添加了粘性的特点,通过Context的sendStickyOrderedBroadcast接口发送。
二、LocalBroadcastManager
LocalBroadcastManager是android support v4包里提供的一个组件,用来在应用内发送广播。
使用方法和和Broadcast基本一致,只需要在Broadcast相关的代码前加上LocalBroadcastManager.getInstance(context)就行了。
发送广播:
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
注册广播监听器:
LocalBroadcastManager.getInstance(context).registerReceiver(receiver, filter);
注销广播监听器:
LocalBroadcastManager.getInstance(context).unregisterReceiver(receiver);
相比于发送全局广播的sendBroadcast有很多优点:
(1)广播的数据不会离开本身的进程,所以不用担心泄露私人数据;
(2)其他应用程序不可能发广播给你的应用,所以不用担心有安全漏洞会被利用;
(3)相比于经过系统的全局广播更有效率。
与Handler进行比较:
通过线程内的通信用Handler会更方便,所以这种LocalBroadcastManager也是比较少用,不过相比于Handler,LocalBroadcastManager的优势在于如果在通过线程内,多个对象要收到消息,LocalBroadcastReceiver发一次,而Handler则要发多次。
附常见的系统广播Action常量
1、ACTION_TIME_CHANGED:系统时间被改变。
2、ACTION_DATE_CHANGED:系统日期被改变。
3、ACTION_TIMEZONE_CHANGED:系统时区被改变。
4、ACTION_BOOT_COMPLETED:系统启动完成。
5、ACTION_PACKAGE_ADDED:系统中添加安装包。
6、ACTION_PACKAGE_CHANGED:系统的包被改变了。
7、ACTION_PACKAGE_REMOVED:系统的包被删除了。
9、ACTION_PACKAGE_DATA_CLEARED:系统的包数据被清空。
10、ACTION_BATTERY_CHANGED:电池电量改变。
11、ACTION_SHUTDOWN:系统被关闭。
文章评论
to me, with a facial expression that looked like pain, and di#8fliee…&sb221;I dont now why we have to live this life? why do we have to go through this….I dont know” and we just cried in eachothers arms….and it still hurts like shit when I remember it…..Death, it is always here, better to make friends with it. Thank you for your words, what a gift you have…..Love and Peace
Haha, that is one hazard of them I didn’t even think of. I’ve seen plenty of old school plastic lunchboxes, as well. The Muppets movie is AMAZING. It was very funny, spot on with their mockery of things and poking fun of current society and such. Definitely go see it (if you ha;7n̵evt already)!
Genuinely no matter if someone doesn't know after that its up to other
viewers that they will help, so here it takes place.
I truly treasure your work, Great post.
Sweet blog! I found it while browsing on Yahoo News.
Do you have any tips on how to get listed
in Yahoo News? I've been trying for a while but I never seem
to get there! Cheers