当前位置: 代码迷 >> 综合 >> 【安卓笔记】BroadcastReceiver
  详细解决方案

【安卓笔记】BroadcastReceiver

热度:46   发布时间:2023-12-19 10:14:26.0
一.什么是BroadcastReceiver?                                                                                              
BroadcastReceiver,中文叫广播接收者。它是android的四大组件之一。
广播接收者是一个专注于接收广播信息,并做出对应处理的组件。很多广播是源自于系统自带的。比如,通知时区改变、电池电量低、拍摄了一张照片或者用户改变了语言选项。应用程序也可以进行广播。比如说,通知其它应用程序一些数据下载完成并处于可用状态。
应用程序可以拥有任意数量的广播接收器以对所有它感兴趣的通知信息予以响应。所有的接收器均继承自BroadcastReceiver基类。
广播接收器没有用户界面。然而,它们可以启动一个activity来响应它们收到的信息,或者用NotificationManager来通知用户。通知可以用很多种方式来吸引用户的注意力──闪动背灯、震动、播放声音等等。一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。
Android中的广播事件有两种,一种就是系统广播事件,比如:ACTION_BOOT_COMPLETED(系统启动完成后触发),ACTION_TIME_CHANGED(系统时间改变时触发),ACTION_BATTERY_LOW(电量低时触发)等等。另外一种是我们自定义的广播事件。
二.BroadcastReceiver的生命周期?                                                                                      
BroadcastReceiver在onReceive函数执行结束后即表示生命周期结束.
所以使用BroadcastReceiver需注意几点:
1. BroadcastReceiver中不适合做一些异步操作,如新建线程下载数据,BroadcastReceiver结束后可能在异步操作完成前进程已经被系统kill。
2.BroadcastReceiver的onReceive函数必须在10秒内完成,否则会ANR。而且onReceive默认会在主线程中执行,所以 BroadcastReceiver中不适合做一些耗时操作,对于耗时操作需要交给service处理,比如网络或数据库耗时操作、对话框的显示(因为现实时间可能超时,用Notification代替)。
3.建议使用动态注册的形式注册广播接收者。 在onResume注册接收者,在onStop方法中卸载接收者。因为这样能够节省资源。
三.使用 BroadcastReceiver                                                                                                        
3.1创建并注册BroadcastReceiver
    首先定义一个广播接收者。继承BroadcastReceiver抽象类即可,逻辑写在onReceive方法中.参数intent即接收到的意图,你可以获取该意图携带的信息(getxxx)。
public class NetworkReceiver extends BroadcastReceiver
{@Overridepublic void onReceive(Context context, Intent intent){//TODO}
}
第二步是注册广播接收者。你有两种选择,动态注册和静态注册。所谓静态注册,就是在清单文件中写死,动态注册就是在代码中注册.
静态注册(application节点下):
<receiver android:name="MyBroadcastReceiver"> <intent-filter android:priority="1000"> <action android:name=“" /></intent-filter>
</receiver>
动态注册:
一般在activity中注册.
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission,  Handler scheduler)
此种方式注册的广播接收者可以卸载:
public void unregisterReceiver(BroadcastReceiver receiver)
如果待接收的广播需要权限的话,必须声明。
比如监听网络情况,需加上权限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />  
监听短信到来,需加上权限:
< uses-permission android:name = "android.permission.RECEIVE_SMS" />
也可以为自定义广播添加权限,一旦增加了权限,广播接收者必须声明该权限才能接收到广播。
注意:
动态注册与静态注册的区别
1.registerReceiver为动态注册,自己可以手动注册或是取消注册;<receiver>标签为静态注册,由系统开机时自动扫描注册,所以无法手动控制,开机一直运行中。
2. 资源消耗不同。registerReceiver可以手动控制,所以适当的注册和取消注册能节省系统资源,<receiver>标签系统开机后一直有效。
3.使用情景不一样。对于自己发送和接受的广播可以通过registerReceiver注册,对于系统常用广播的接收通常用<receiver>标签注册。
关于priority属性:
android:priority表示优先级,Android官方规定范围为-1000到1000。优先级的用处在于,在有序的广播中能够更靠前的获得消息。并且能拦截广播(abortBroadcast方法)使其不能传递给下一个广播接收者。当然,如果你手动设置了一个广播接收者作为你广播的默认接收者,那即使该广播被其他广播拦截,默认的广播接收者也可以接收到该广播。手动设置的方式其实就是sendBroadcast方法中传入一个广播接收者对象。
第三步是发送广播:
定义好广播接收者之后,我们还需要发广播(如果广播接收者接收到是系统定义的事件,那我们就不用发送广播了),这里的广播其实就是一个Intent,广播发送出去后,系统根据Intent中的action匹配所有注册的广播接收者监听的action,如果匹配,就调用该广播接收者的onReceive方法。
发送广播API:
public void sendBroadcast(Intent intent)
public void sendStickyBroadcast(Intent intent)
public void sendOrderedBroadcast(Intent intent, String receiverPermission)
public void sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver,Handler scheduler, int initialCode, String initialData,Bundle initialExtras)
3.2接收系统广播事件
以接收短信到来为例:
package cn.edu.chd.broadcastreceiverdemo.receiver;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;public class SmsReceiver extends BroadcastReceiver
{@Overridepublic void onReceive(Context context, Intent intent){Toast.makeText(context, "短信来了啊...",1).show();}
}
清单文件:
<receiver android:name="cn.edu.chd.broadcastreceiverdemo.receiver.SmsReceiver"><intent-filter ><action android:name="android.provider.Telephony.SMS_RECEIVED"/></intent-filter></receiver>
权限:
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
通过上面的配置,我们便创建了一个监听短信到来的广播接收者,此时只要有短信到来便会弹出Toast消息。
3.3不同的广播类型
普通广播通过Context.sendBroadcast发送的广播即为普通广播,对于普通广播接收者接收到它的顺序是不定的,所以接收者接收到后无法使用其他接收者对它的处理结果也无法停止它(即不可调用abortBroadcast方法)。
有序广播: 通过Context.sendOrderedBroadcast发送的广播即为有序广播,与普通广播的不同在于,接收者是有序接收到广播的并且可以对广播进行修改或是取消广播向下传递。系统根据接收者定义的优先级顺序决定哪个接收者先接收到它,接收者处理完后可以将结果传递给优先级低的接收者也可以停止广播使得其他优先级低的接收者无法接收到该广播。优先级通过android:priority属性定义,数值越大优先级别越高,取值范围:-1000到1000,Android系统收到短信、接到电话后发送的广播都是有序广播,所以可以进行短信或电话的拦截,即取消广播。
粘性广播: Sticky Broadcast。如果发送者发送了某个广播,而接收者在这个广播发送后才注册自己的Receiver,这时接收者便无法接收到刚才的广播,为此Android引入了StickyBroadcast,在广播发送结束后会保存刚刚发送的广播(Intent),这样当接收者注册完Receiver后就可以继续使用刚才的广播如果在接收者注册完成前发送了多条相同Action的粘性广播,注册完成后只会收到一条该Action的广播,并且消息内容是最后一次广播内容。系统网络状态的改变发送的广播就是粘性广播。粘性广播通过Context的sendStickyBroadcast(Intetn)接口发送,需要添加权限:
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>

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

本地广播android引入了LocalBroadcastManager解决一些安全性问题,LocalBroadcastManager除了能解决BroadcastReceiver进程间安全性问题外,相对Context操作的BroadcastReceiver而言还具有更高的运行效率。这个类在support包中,具体使用见下一部分。

四.BroadcastReceiver的安全性简介                                                                                        

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

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

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

3.使用LocalBroadcastManager,这个类在support包中。使用方式如下:

注册广播:LocalBroadcastManager.getInstance(context).registerReceiver解除注册:LocalBroadcastManager.getInstance(context).unregisterReceiver发送广播:LocalBroadcastManager.getInstance(context).sendBroadcast(intent)