您的位置:首页 > 移动开发 > Android开发

Android基础之四大组件---BroadcastReceiver

2016-05-19 15:49 423 查看
学习Android一段时间,来总结下BroadcastReceiver的使用方法。

一、什么是广播,广播接受者

广播:广泛运用在应用程序之间传输信息的机制。

广播接受者(BroadcastReceiver):接收来自系统和应用中的广播。

Android系统中,广播体现在很多方面,例如开机启动后会发出一条广播,当接收到这条广播就能实现开机启动服务的功能。当网络状态发生变化时产生一条广播,接收到后能及时做出提示和保存数据等操作。当电池电量改变时,系统会产生一条广播,接收到这条广播就能在电量低时告知用户及时保存进度,等等。

二、广播注册的两种方式

1.静态注册

静态注册方式是在AndroidManifest.xml中配置。如下所示

<receiver android:name=".MyBroadcastReceiver">
<intent-filter>
<action android:name="com.hlh.base"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>


如果当注册一些如短信的广播时,需要配置权限

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

//加上权限
< uses-permission android:name= "android.permission.RECEIVE_SMS"/>
< uses-permission android:name= "android.permission.SEND_SMS"/>


2.动态注册

动态注册需要在代码中动态的指定广播地址并注册,通常我们是在Activity或Service注册一个广播,下面我们就来看一下注册的代码:

MyBroadcastReceiver receiver = new MyBroadcastReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("com.hlh.base");
registerReceiver(receiver, filter);


但是代码中注册也分两种情况

注册方法一:registerReceiver(BroadcastReceiver receiver, IntentFilter fileter);第一个参数是我们要处理广播的BroadcastReceiver;第二个参数是意图过滤器。

注册方式二:registerReceiver(receiver, filter, broadcastPermission, scheduler)第一个参数是 BroadcastReceiver (广播接收者,可以是系统的,也可以是自定义的);第二个参数是意图过滤器;第三个参数是广播权限;第四个参数是 Hander ;

note:权限重复问题,如果AndroidManifest.xml注册了该权限,用该方法再注册,则receiver无法接收到广播;如果AndroidManifest.xml没有注册该权限,该方法注册也无法收到广播;当该方法没有注册权限,AndroidManifest.xml注册的时候,receiver可以接收到广播。

三、Android中使用广播的一般步骤

1.定义广播接受者

public class MyBroadcastReceiver extends BroadcastReceiver{
public static final String TAG= "broadcastreceiver";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "接收到广播" + intent.getStringExtra("msg"));
}
}


2.注册广播

MyBroadcastReceiver receiver = new MyBroadcastReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("com.hlh.base");
registerReceiver(receiver, filter);


3.发送广播

Intent intent = new Intent("com.hlh.base");
intent.putExtra("msg", "love Android");
sendBroadcast(intent);


4.接收广播、处理操作



四、广播类型

1、普通广播(Normal Broadcast) :接受者不能终止广播。普通广播对于多个接收者来说是完全异步的,通常每个接收者都无需等待即可以接收到广播,接收者相互之间不会有影响。对于这种广播,接收者无法终止广播,即无法阻止其他接收者的接收动作。

为了验证以上论断,我们新建三个BroadcastReceiver,演示一下这个过程,FirstReceiver、SecondReceiver和ThirdReceiver的代码如下:

public class FirstReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Log.d(MyConfig.LOG, "FirstReceiver  " + intent.getStringExtra("msg"));
}
}


public class SecondReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Log.d(MyConfig.LOG, "SecondReceiver " + intent.getStringExtra("msg"));
}
}


public class ThirdReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Log.d(MyConfig.LOG, "ThirdReceiver " + intent.getStringExtra("msg"));
}
}


注册完广播后,发送广播,控制台打印如下:



然后在三个广播接受者的onReceive()中加入abortBroadcast()方法终止广播。再次点击发送按钮,我们会发现,控制台中三个接收者仍然都打印了自己的日志,因此接收者并不能终止广播。

2、有序广播(Ordered Broadcast)

有序广播按照接受者的优先级顺序接收广播,优先级别在intent-filter中的priority中声明。-1000到1000之间,值越大,优先级越高。它每次只发送到优先级较高的接收者那里,然后由优先级高的接受者再传播到优先级低的接收者那里,优先级高的接收者有能力终止这个广播。

演示有序广播流程,修改上面三个接收者的代码,如下所示。

FirstReceiver.java

public class FirstReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Log.d(MyConfig.LOG, "FirstReceiver  " + intent.getStringExtra("msg"));

Bundle bundle = new Bundle();
bundle.putString("msg", intent.getStringExtra("msg") + " @FirstReceiver");
setResultExtras(bundle);
}
}


SecondReceiver.java

public class SecondReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Log.d(MyConfig.LOG, "SecondReceiver " + getResultExtras(true).getString("msg"));

Bundle bundle = new Bundle();
bundle.putString("msg", getResultExtras(true).getString("msg") + " @SecondReceiver");
setResultExtras(bundle);
}
}


ThirdReceiver.java

public class ThirdReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Log.d(MyConfig.LOG, "ThirdReceiver " + getResultExtras(true).getString("msg"));
}
}


在FirstReceiver和SecondReceiver中最后都使用了setResultExtras方法将一个Bundle对象设置为结果集对象,传递到下一个接收者那里,这样以来,优先级低的接收者可以用getResultExtras获取到最新的经过处理的信息集合。

代码改完之后,我们需要为三个接收者注册广播地址,我们修改一下AndroidMainfest.xml文件:

<receiver android:name=".FirstReceiver">
<intent-filter android:priority="1000">
<action android:name="com.hlh.base"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
<receiver android:name=".SecondReceiver">
<intent-filter android:priority="500">
<action android:name="com.hlh.base"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
<receiver android:name=".ThirdReceiver">
<intent-filter android:priority="0">
<action android:name="com.hlh.base"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>


最后,修改发送广播的代码:

Intent intent = new Intent("com.hlh.base");
intent.putExtra("msg", "love Android");
sendOrderedBroadcast(intent, "com.hlh.base.MY_BROADCASTRECEIVER_PERMISSION");


注意,使用sendOrderedBroadcast方法发送有序广播时,需要一个权限参数,如果为null则表示不要求接收者声明指定的权限,如果不为null,则表示接收者若要接收此广播,需声明指定权限。这样做是从安全角度考虑的,例如系统的短信就是有序广播的形式,一个应用可能是具有拦截垃圾短信的功能,当短信到来时它可以先接受到短信广播,必要时终止广播传递,这样的软件就必须声明接收短信的权限。

所以我们在AndroidMainfest.xml中定义一个权限:

<permission
android:name="com.hlh.base.MY_BROADCASTRECEIVER_PERMISSION"
android:protectionLevel="normal"/>


然后声明使用了此权限:

<uses-permission android:name="com.hlh.base.MY_BROADCASTRECEIVER_PERMISSION"/>


然后我们点击发送按钮发送一条广播,控制台打印如下:



我们看到接收是按照顺序的,第一个和第二个都在结果集中加入了自己的标记,并且向优先级低的接收者传递下去。

既然是顺序传递,试着终止这种传递,看一看效果如何,我们修改FirstReceiver的代码,在onReceive的最后一行添加以下代码:abortBroadcast();

再次运行控制台只打印了



此次,只有第一个接收者执行了,其它两个都没能执行,因为广播被第一个接收者终止了。

五、实例

1.开机启动服务

我们经常有这样的应用场合,比如消息推送服务,需要开机启动就能实现。实现该功能,必须订阅开机启动完成这条广播,接收到这条广播后,即可启动我们的消息推送服务。接收开机完成的广播接收者BootCompleteReceiver.java和消息推送服务MsgPushService.java如下所示

public class BootCompleteReceiver extends BroadcastReceiver{
private static final String MSG = "BootCompleteReceiver";
@Override
public void onReceive(Context context, Intent intent) {
//启动消息推送服务
Intent service = new Intent(context, MsgPushService.class);
context.startService(service);
Log.d(MSG, "Boot Complete , Starting MsgPushService...");
}
}


public class MsgPushService extends Service{
private static final String TAG = "MsgPushService";

@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate complete...");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand complete... ");
return super.onStartCommand(intent, flags, startId);
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}


接下来在AnroidManifest.xml配置相关信息

<receiver android:name=".BootCompleteReceiver">
<intent-filter>
<!--注册广播接收地址-->
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</receiver>
<!--消息推送服务-->
<service android:name=".MsgPushService"/>


我们看到BootCompleteReceiver注册了“android.intent.action.BOOT_COMPLETED”这个开机广播地址,从安全角度考虑,系统要求必须声明接收开机启动广播的权限,于是我们再声明使用下面的权限:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>


经过上面的几个步骤之后,我们就完成了开机启动的功能,将应用运行在模拟器上,然后重启模拟器,控制台打印如下:





2.网络变化服务

在某些场合,比如用户浏览网络信息时,网络突然断开,我们要及时地提醒用户网络已断开。要实现这个功能,我们可以接收网络状态改变这样一条广播,当由连接状态变为断开状态时,系统就会发送一条广播,我们接收到之后,再通过网络的状态做出相应的操作。下面就来实现一下这个功能:

public class NetworkStateReceiver extends BroadcastReceiver{
private static final String TAG = "NetworkStateReceiver";
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "network state changed");
if (!isNetworkAvailable(context)) {
Toast.makeText(context, "network disconnected error", Toast.LENGTH_SHORT).show();
}
}

/**
* 网络是否可用
*/
public static boolean isNetworkAvailable(Context context) {
ConnectivityManager ctm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo[] info = ctm.getAllNetworkInfo();
if (info != null) {
for (int i = 0; i < info.length; i++) {
if(info[i].getState() == NetworkInfo.State.CONNECTED)
return true;
}
}
return false;
}
}


注册接收者的信息:

<receiver android:name=".NetworkStateReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>


因为在isNetworkAvailable方法中我们使用到了网络状态相关的API,所以需要声明相关的权限才行,下面就是对应的权限声明:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>


六、注意的问题

BroadcastReceiver的哦你Receive()生命周期只有十秒左右,如果在 onReceive() 内做超过十秒内的事情,就会报错。

每次广播到来时 , 会重新创建 BroadcastReceiver 对象 , 并且调用 onReceive() 方法 , 执行完以后 , 该对象即被销毁 . 当 onReceive() 方法在 10 秒内没有执行完毕, Android 会认为该程序无响应 . 所以在

BroadcastReceiver 里不能做一些比较耗时的操作 , 否侧会弹出 ANR(Application No Response) 的对话框。

如果需要完成一项比较耗时的工作 , 应该通过发送 Intent 给 Service, 由 Service 来完成 .
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: