本文主要介绍BroadcastReceiver的概念、使用、生命周期、安全性、分类、特殊的BroadcastReceiver(本地、粘性、有序、粘性有序广播)。
示例代码见BroadcastReceiverDemo,示例APK见:TrineaAndroidDemo.apk

1、概念介绍及两种注册方式的区别

BroadcastReceiver作为Android四大组件之一,不像Activity,没有可显示的界面。BroadcastReceiver包括两个概念,广播发送者和广播接收者(Receiver),这里的广播实际就是指Intent,程序可以自己发送广播自己接收,也可以接受系统或其他应用的广播或是发送广播给其他应用程序。

发送者可以通过类似Context.sendBroadcast接口发送广播,接收者通过Context.registerReceiver()动态注册或在AndroidManifest.xml文件中通过<receiver>标签静态注册,注册完成后,当发送者发送某个广播时系统会将发送的广播(Intent)与系统中所有注册的符合条件的接收者(Receiver) 的IntentFilter进行匹配,若匹配成功则执行相应接收者的onReceive函数,匹配规则见Intent和IntentFilter的匹配规则。

关于registerReceiver动态注册和通过<receiver>标签静态注册广播的区别如下:

a.对bindService的调用,<receiver>注册的广播,在onReceive结束后广播即不存在,所以不能在其中给自己异步传递结果,如bindService而只能使用startService,如果想跟service交互可使用peekService。

b. 手动控制。registerReceiver为动态注册,自己可以手动注册或是取消注册;<receiver>标签为静态注册,由系统开机时自动扫描注册,所以无法手动控制,开机一直运行中。

c. 资源消耗不同。registerReceiver可以手动控制,所以适当的注册和取消注册能节省系统资源,<receiver>标签系统开机后一直有效。

d. 有效期不同。通过registerReceiver注册的BroadcastReceiver在对其进行注册的Context对象"销毁"了或者调用了unregisterReceiver方法时也就失效了,而通过<receiver>标签注册的BroadcastReceiver只要应用程序没有被删除就一直有效。

e. 对registerReceiver函数的调用许可不同。通过registerReceiver注册的BroadcastReceiver在其onReceive函数中可以再次调用某个Context的registerReceiver函数,而通过<receiver>标签注册的BroadcastReceiver不允许再调用某个Context的registerReceiver函数 。

f. 使用情况不同。对于自己发送和接受的广播可以通过registerReceiver注册,对于系统常用广播的接收通常用<receiver>标签注册。

2、使用举例

BroadcastReceiverDemo

R.layout.broadcast_receiver_demo的内容为一个简单的id为sendBroadcast的Button

从上面代码可以看到我们

a. 新建BroadcastReceiver只需要继承BroadcastReceiver并重写OnReceiver函数,加上自己的处理逻辑。

b. 通过registerReceiver注册广播,通过unregisterReceiver取消注册广播,通过sendBroadcast发送广播。

其中注册和取消注册广播放在了OnResume和OnPause函数中可以有效的节省系统消耗。如果希望广播一直运行中可以在Activity的OnCreate函数中注册,在OnDestrory函数中取消注册。

这里的MyBroadcastReceiver也可以在AndroidManifest.xml文件中静态注册,这样程序安装后便一直运行中。比如希望接收到短信到来时的广播,如下:

<receiver android:name="MyBroadcastReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>

3、生命周期

BroadcastReceiver在onReceive函数执行结束后即表示生命周期结束,所以不适合在onReceive中做绑定服务操作,结束后若某个进程只含有该BroadcastReceiver,则优先级将降低可能被系统回收,所以BroadcastReceiver中不适合做一些异步操作,如新建线程下载数据,BroadcastReceiver结束后可能在异步操作完成前进程已经被系统kill。

同时由于ANR限制BroadcastReceiver的onReceive函数必须在10秒内完成,而且onReceive默认会在主线程中执行,所以BroadcastReceiver中不适合做一些耗时操作,对于耗时操作需要交给service处理,比如网络或数据库耗时操作、对话框的显示(因为现实时间可能超时,用Notification代替)。

4、安全性

BroadcastReceiver的设计初衷就是从全局考虑的,可以方便应用程序和系统、应用程序之间、应用程序内的通信,所以对单个应用程序而言BroadcastReceiver是存在安全性问题的,相应问题及解决如下:

a、当应用程序发送某个广播时系统会将发送的Intent与系统中所有注册的BroadcastReceiver的IntentFilter进行匹配,若匹配成功则执行相应的onReceive函数。可以通过类似sendBroadcast(Intent, String)的接口在发送广播时指定接收者必须具备的permission。或通过Intent.setPackage设置广播仅对某个程序有效。

b. 当应用程序注册了某个广播时,即便设置了IntentFilter还是会接收到来自其他应用程序的广播进行匹配判断。对于动态注册的广播可以通过类似registerReceiver(BroadcastReceiver, IntentFilter, String, android.os.Handler)的接口指定发送者必须具备的permission,对于静态注册的广播可以通过android:exported="false"属性表示接收者对外部应用程序不可用,即不接受来自外部的广播。

c.上面两个问题其实都可以通过LocalBroadcastManager来解决,LocalBroadcastManager只会将广播限定在当前应用程序中,具体见下面6特殊的BroadcastReceiver中的介绍

d.使用android:protectionLevel

5、分类

BroadcastReceiver可以分为普通和有序两种,下面6特殊BroadcastReceiver中介绍了其他一些种类。

通过Context.sendBroadcast发送的广播即为普通广播,对于普通广播接收者接收到它的顺序是不定的,所以接收者接收到后无法使用其他接收者对它的处理结果也无法停止它。

通过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方法修改或获取数据,可以见本文最后的实例代码举例。

6、特殊的BroadcastReceiver

a. LocalBroadcastManager本地广播

android引入了LocalBroadcastManager解决在第4部分安全性介绍的一些问题,LocalBroadcastManager除了能解决BroadcastReceiver进程间安全性问题外,相对Context操作的BroadcastReceiver而言还具有更高的运行效率。

使用LocalBroadcastManager需要引入Android Support Library,如何引入见Add Support Package

本地广播通过LocalBroadcastManager.getInstance(context).sendBroadcast(intent)发送广播,LocalBroadcastManager.getInstance(context).registerReceiver注册服务,通过LocalBroadcastManager.getInstance(context).unregisterReceiver取消注册服务,其他同普通广播.

b. Sticky Broadcast粘性广播

如果发送者发送了某个广播,而接收者在这个广播发送后才注册自己的Receiver,这时接收者便无法接收到刚才的广播,为此Android引入了StickyBroadcast,在广播发送结束后会保存刚刚发送的广播(Intent),这样当接收者注册完Receiver后就可以继续使用刚才的广播。如果在接收者注册完成前发送了多条相同Action的粘性广播,注册完成后只会收到一条该Action的广播,并且消息内容是最后一次广播内容。系统网络状态的改变发送的广播就是粘性广播。

粘性广播通过Context的sendStickyBroadcast(Intent)接口发送,需要添加权限<uses-permission android:name="android.permission.BROADCAST_STICKY"/>

也可以通过Context的removeStickyBroadcast(Intent intent)接口移除缓存的粘性广播。

c. OrderedBroadcastReceiver有序广播

这个在5分类中已经介绍,接收者有序接收广播并可以修改广播结果或是取消广播,通过Context的sendOrderedBroadcast接口发送

d. StickyOrderedBroadcast粘性有序广播

这个就是粘性广播和有序广播的结合了,通过Context的sendStickyOrderedBroadcast接口发送。

各种广播操作Demo示例代码见BroadcastReceiverDemo,由于本地广播的support library暂时下载不了,不包括本地广播,本地广播操作间上面介绍。

注意AndroidManifest文件中需要添加粘性广播操作权限<uses-permission android:name="android.permission.BROADCAST_STICKY"/>

参考:

http://developer.android.com/reference/android/content/BroadcastReceiver.html

from :http://www.cnblogs.com/trinea/archive/2012/11/09/2763182.html

【转】Android BroadcastReceiver介绍的更多相关文章

  1. Android BroadcastReceiver介绍 (转)

    原文地址:http://www.cnblogs.com/trinea/archive/2012/11/09/2763182.html 本文主要介绍BroadcastReceiver的概念.使用.生命周 ...

  2. 【转】Android bluetooth介绍(三): 蓝牙扫描(scan)设备分析

    原文网址:http://blog.csdn.net/xubin341719/article/details/38584469 关键词:蓝牙blueZ  A2DP.SINK.sink_connect.s ...

  3. Android bluetooth介绍(三): 蓝牙扫描(scan)设备分析

    关键词:蓝牙blueZ  A2DP.SINK.sink_connect.sink_disconnect.sink_suspend.sink_resume.sink_is_connected.sink_ ...

  4. android Animation介绍

    Animation介绍: 在Android SDK介绍了2种Animation模式: 1. Tween Animation:间动画,通过对场景里的对象不断做图像变换(平移.缩放.旋转)产生动画效果,即 ...

  5. android AsyncTask介绍(转)

    android AsyncTask介绍 AsyncTask和Handler对比 1 ) AsyncTask实现的原理,和适用的优缺点 AsyncTask,是android提供的轻量级的异步类,可以直接 ...

  6. android BroadcastReceiver ACTION_TIME_TICK 系统时间监听不到

    android BroadcastReceiver ACTION_TIME_TICK 系统时间监听不到 今天做android上的消息推送,启动了一个独立service,然后在里面监听系统的ACTION ...

  7. Android monkey介绍

    Android monkey介绍 原文地址 1 简略 monkey是android下自动化测试比较重要的的一个工具,该工具可以运行在host端或者设备(模拟器或真实设备).它会向系统发送随机事件流(即 ...

  8. [Learn Android Studio 汉化教程]第一章 : Android Studio 介绍

    注:为了看上去比较清晰这里只转载了中文 原地址:  [Learn Android Studio 汉化教程]第一章 : Android Studio 介绍 本章将引导您完成安装和设置开发环境,然后你就可 ...

  9. Android bluetooth介绍(四): a2dp connect流程分析

    关键词:蓝牙blueZ  A2DP.SINK.sink_connect.sink_disconnect.sink_suspend.sink_resume.sink_is_connected.sink_ ...

随机推荐

  1. java中使用nextLine(); 没有输入就自动跳过的问题?

    [问题分析] 必要的知识:in.nextLine();不能放在in.nextInt();代码段后面否则in.nextLine();会读入"\n"字符,但"\n" ...

  2. 用dango框架搭建博客网站

    1.我早先下载了Anaconda35.0.1.但是Anaconda自带的编辑器Spyder我用的不太熟练.所以还是使用Pycharm来编辑代码.我的Pycharm试用期已经到了,所以需要注册码来使用P ...

  3. 如何利用fastjson将JSON格式的字符串转换为Map,再返回至前端成为js对象

    //注意,这里的jsonStr是json格式的字符串,里面如果遇到双引号嵌套双引号的,一般是嵌套的双引号经过转义 //    \",假如有这样的一个场景,这些字符串里面有需要的css样式的j ...

  4. Python import搜索路径相关

    import搜索路径 在当前目录下搜索该模块 在环境变量 PYTHONPATH 中指定的路径列表中依次搜索 在 Python 安装路径的 lib 库中搜索 查看当前的搜索路径 import sys p ...

  5. 剑指offer中经典的算法题之从头到尾打印链表

    话不多说上代码: 我自己的算法是: /** * public class ListNode { * int val; * ListNode next = null; * * ListNode(int ...

  6. C# IO流 File.Exists,Directory.Exists, File.Create,Directory.CreateDirectory

    void Start() { CreateDirectory(); CreateFile(); } //平台的路径(封装起来的一个属性,这不是一个方法) public string path { ge ...

  7. 021-动态生成验证码jsp代码模板

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  8. 《深入浅出Node.js》学习笔记(一)

    看了朴灵前辈的node.js系列文章,很开阔视野,虽然能力有限还是有很多不懂,但是还是希望能写下笔记,初步对node.js有点了解. 一.概念 Node.js不是JS应用.而是JS运行平台 Node. ...

  9. Weblogic中配置Active Directory Authentication Provider

    其要点或者容易出错的关键点是:(<>及其中说明代表需要替换的内容)         Host: ads.yourdomain.com         Host填AD服务器的域名或IP    ...

  10. npm EPERM: operation not permitted, rename解决

    此问题并非权限问题! 执行如下3条命令解决: 1.清理npm缓存 npm cache clean --force 2.升级npm版本 npm install -g npm@latest --force ...