Android基础之四大组件---BroadcastReceiver
2016-05-19 15:49
423 查看
学习Android一段时间,来总结下BroadcastReceiver的使用方法。
一、什么是广播,广播接受者
广播:广泛运用在应用程序之间传输信息的机制。
广播接受者(BroadcastReceiver):接收来自系统和应用中的广播。
Android系统中,广播体现在很多方面,例如开机启动后会发出一条广播,当接收到这条广播就能实现开机启动服务的功能。当网络状态发生变化时产生一条广播,接收到后能及时做出提示和保存数据等操作。当电池电量改变时,系统会产生一条广播,接收到这条广播就能在电量低时告知用户及时保存进度,等等。
二、广播注册的两种方式
1.静态注册
静态注册方式是在AndroidManifest.xml中配置。如下所示
如果当注册一些如短信的广播时,需要配置权限
2.动态注册
动态注册需要在代码中动态的指定广播地址并注册,通常我们是在Activity或Service注册一个广播,下面我们就来看一下注册的代码:
但是代码中注册也分两种情况
注册方法一:registerReceiver(BroadcastReceiver receiver, IntentFilter fileter);第一个参数是我们要处理广播的BroadcastReceiver;第二个参数是意图过滤器。
注册方式二:registerReceiver(receiver, filter, broadcastPermission, scheduler)第一个参数是 BroadcastReceiver (广播接收者,可以是系统的,也可以是自定义的);第二个参数是意图过滤器;第三个参数是广播权限;第四个参数是 Hander ;
note:权限重复问题,如果AndroidManifest.xml注册了该权限,用该方法再注册,则receiver无法接收到广播;如果AndroidManifest.xml没有注册该权限,该方法注册也无法收到广播;当该方法没有注册权限,AndroidManifest.xml注册的时候,receiver可以接收到广播。
三、Android中使用广播的一般步骤
1.定义广播接受者
2.注册广播
3.发送广播
4.接收广播、处理操作
四、广播类型
1、普通广播(Normal Broadcast) :接受者不能终止广播。普通广播对于多个接收者来说是完全异步的,通常每个接收者都无需等待即可以接收到广播,接收者相互之间不会有影响。对于这种广播,接收者无法终止广播,即无法阻止其他接收者的接收动作。
为了验证以上论断,我们新建三个BroadcastReceiver,演示一下这个过程,FirstReceiver、SecondReceiver和ThirdReceiver的代码如下:
注册完广播后,发送广播,控制台打印如下:
然后在三个广播接受者的onReceive()中加入abortBroadcast()方法终止广播。再次点击发送按钮,我们会发现,控制台中三个接收者仍然都打印了自己的日志,因此接收者并不能终止广播。
2、有序广播(Ordered Broadcast)
有序广播按照接受者的优先级顺序接收广播,优先级别在intent-filter中的priority中声明。-1000到1000之间,值越大,优先级越高。它每次只发送到优先级较高的接收者那里,然后由优先级高的接受者再传播到优先级低的接收者那里,优先级高的接收者有能力终止这个广播。
演示有序广播流程,修改上面三个接收者的代码,如下所示。
FirstReceiver.java
SecondReceiver.java
ThirdReceiver.java
在FirstReceiver和SecondReceiver中最后都使用了setResultExtras方法将一个Bundle对象设置为结果集对象,传递到下一个接收者那里,这样以来,优先级低的接收者可以用getResultExtras获取到最新的经过处理的信息集合。
代码改完之后,我们需要为三个接收者注册广播地址,我们修改一下AndroidMainfest.xml文件:
最后,修改发送广播的代码:
注意,使用sendOrderedBroadcast方法发送有序广播时,需要一个权限参数,如果为null则表示不要求接收者声明指定的权限,如果不为null,则表示接收者若要接收此广播,需声明指定权限。这样做是从安全角度考虑的,例如系统的短信就是有序广播的形式,一个应用可能是具有拦截垃圾短信的功能,当短信到来时它可以先接受到短信广播,必要时终止广播传递,这样的软件就必须声明接收短信的权限。
所以我们在AndroidMainfest.xml中定义一个权限:
然后声明使用了此权限:
然后我们点击发送按钮发送一条广播,控制台打印如下:
我们看到接收是按照顺序的,第一个和第二个都在结果集中加入了自己的标记,并且向优先级低的接收者传递下去。
既然是顺序传递,试着终止这种传递,看一看效果如何,我们修改FirstReceiver的代码,在onReceive的最后一行添加以下代码:abortBroadcast();
再次运行控制台只打印了
此次,只有第一个接收者执行了,其它两个都没能执行,因为广播被第一个接收者终止了。
五、实例
1.开机启动服务
我们经常有这样的应用场合,比如消息推送服务,需要开机启动就能实现。实现该功能,必须订阅开机启动完成这条广播,接收到这条广播后,即可启动我们的消息推送服务。接收开机完成的广播接收者BootCompleteReceiver.java和消息推送服务MsgPushService.java如下所示
接下来在AnroidManifest.xml配置相关信息
我们看到BootCompleteReceiver注册了“android.intent.action.BOOT_COMPLETED”这个开机广播地址,从安全角度考虑,系统要求必须声明接收开机启动广播的权限,于是我们再声明使用下面的权限:
经过上面的几个步骤之后,我们就完成了开机启动的功能,将应用运行在模拟器上,然后重启模拟器,控制台打印如下:
2.网络变化服务
在某些场合,比如用户浏览网络信息时,网络突然断开,我们要及时地提醒用户网络已断开。要实现这个功能,我们可以接收网络状态改变这样一条广播,当由连接状态变为断开状态时,系统就会发送一条广播,我们接收到之后,再通过网络的状态做出相应的操作。下面就来实现一下这个功能:
注册接收者的信息:
因为在isNetworkAvailable方法中我们使用到了网络状态相关的API,所以需要声明相关的权限才行,下面就是对应的权限声明:
六、注意的问题
BroadcastReceiver的哦你Receive()生命周期只有十秒左右,如果在 onReceive() 内做超过十秒内的事情,就会报错。
每次广播到来时 , 会重新创建 BroadcastReceiver 对象 , 并且调用 onReceive() 方法 , 执行完以后 , 该对象即被销毁 . 当 onReceive() 方法在 10 秒内没有执行完毕, Android 会认为该程序无响应 . 所以在
BroadcastReceiver 里不能做一些比较耗时的操作 , 否侧会弹出 ANR(Application No Response) 的对话框。
如果需要完成一项比较耗时的工作 , 应该通过发送 Intent 给 Service, 由 Service 来完成 .
一、什么是广播,广播接受者
广播:广泛运用在应用程序之间传输信息的机制。
广播接受者(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 来完成 .
相关文章推荐
- Android之 MTP框架和流程分析 (1)
- android模拟器默认位置的修改
- 生产者-消费者模型在Android开发中的应用
- Android Studio 运行代码时device不能识别genymotion设备
- Android中bool的使用
- 使用响应式编程(RxJava)开发Android App
- Android 自定义 ViewPager 打造千变万化的图片切换效果
- Android自定义控件实战——仿淘宝商品浏览界面
- Android自定义验证码组件
- Android组件(Content Provider)
- Android 属性动画(Property Animation) 完全解析 (下)
- PopularGitHub Android Libraries(android流行开源库分类)
- Android简单对话框、输入对话框、单选对话框、复选对话框、列表对话框、自定义对话框、时间对话框
- Android 属性动画(Property Animation) 完全解析 (上)
- AndroidStudio下SVN使用介绍
- Android基础之十六Handle机制
- 在android listview中使用editText无法获取焦点和输入窗
- Android--173个项目源码
- android 休眠唤醒机制分析(二) — early_suspend
- Android应用界面开发(二)