Android四大组件之BroadcastReceiver详细解析
2016-05-25 17:02
465 查看
什么是BroadcastReceiver?
BroadcastReceiver作为Android四大组件之一,在实际开发中也发挥着重要的作用,广播机制在Android程序通信中至关重要,广播其实与我们现实生活中的电台很相似,电台在某个频道上发送它的内容,那么只要有在收听这个频道的人都会收到这些内容。在Android中,广播也同样分为两个角色:广播发送者、广播接收者。BroadcastReceiver的应用场景
1.在一个应用中,我们的Activity与Service的通信就需要用到广播来作为中介,比如Service在后台进行着下载任务,当下载成功后,需要通知Activity,这个时候就可以用到广播了。2.在Android中,有时候两个app之间需要进行通信,比如你再一个app里面点击某个按钮时需要通知另外一个app的启动,这个时候就需要在点击按钮时发送一个广播,而另外那个app就是作为广播接收者。
3.另外一种应用场景是由系统来发出广播,你的应用充当广播接收者的角色,比如你需要在手机断网时在你的App中马上做出相应提示,在手机启动时让你的app收到系统发来的广播:“手机启动了哦!”,然后你的应用就会马上进行相应的操作,比如开机自启动等等。
广播最大的特点就是:发送方与接收方是解耦的,即发送方虽然发送了广播,但它并不关系接收方到底收到了没有,或者接受方拿到广播之后要干嘛,而接收方只需要注册有这个广播,就会在收到相同类型的广播消息时做出相应。而且广播可以是一个发送者,多个接收者。
如何使用广播?
前面说过了,广播是需要注册的,也就是需要注册一个广播接收者,在Android中,广播注册分为两种方式:1.静态注册广播【在AndroidManifest.xml中注册BroadcastReceiver】
2.动态注册广播【通过代码注册BroadcastReceiver】
静态方式注册自定义广播
1.发送广播,这里以Activity为例,在Activity的onCreate中发送一个广播public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(); //这条广播的标志 intent.setAction("broadcast_test"); //携带数据 intent.putExtra("msg", "这是自定义静态广播消息"); //发送广播 sendBroadcast(intent); } }
关键在于sendBroadcast这个方法,通过这个方法将广播的intent发出,可以通过intent携带数据
注意:setAction表示为intent设置上一个action,相当于这个广播的一个标志,只有与这个标志匹配的广播接收者才会接收到这个消息。
2.创建广播接收者,新建一个类继承于BroadCastReceiver,实现其中的onReceive方法
public class MyReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub //获得广播中的数据 String msg = intent.getStringExtra("msg"); //模拟响应 Toast.makeText(context, msg, 1000).show(); } }
在onReceive方法中进行接收到广播后做出的各种响应操作,onReceive方法有两个参数:context表示发送广播的那个地方,一个就是广播所携带的intent咯,也就是上一步中的sendBroadcast中发送过来的intent。所以自然而然就能够从中拿到相应的数据。
3.在AndroidManifest.xml中注册我们定义好的广播
注意:action标签的name一定要与第一步中intent所设置的action一致,才能收到广播
运行
动态方式注册自定义广播
1.发送广播,这里以Activity为例,在Activity的onCreate中发送一个广播public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //动态注册receiver的Intent过滤器和action IntentFilter filter = new IntentFilter(); filter.addAction("broadcast_test"); registerReceiver(new MyReceiver(), filter); Intent intent = new Intent(); //这条广播的标志 intent.setAction("broadcast_test"); //携带数据 intent.putExtra("msg", "这是自定义动态广播消息"); //发送广播 sendBroadcast(intent); } }
可以看到,这里与静态的不同就在于多了IntentFileter的生成和receiver的注册,相当于将在xml中receiver的注册变成用代码来进行注册
2.同样需要有广播接收者,新建一个类继承于BroadCastReceiver,实现其中的onReceive方法
public class MyReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub //获得广播中的数据 String msg = intent.getStringExtra("msg"); //模拟响应 Toast.makeText(context, msg, 1000).show(); } }
运行
上面演示了如何静态和动态发送自定义广播,下面通过手机飞行模式的开关来演示如何静态和动态接收来自系统的广播
静态接收系统广播
1.新建一个广播接收者,用来接收特定的系统广播public class MyReceiver extends BroadcastReceiver{ //用来作为标志,判断是开启还是关闭 private static int count = 0; //如果是飞行模式状态变化的广播,就执行操作 @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub //每改变一次飞行状态,count就+1 count++; switch (count%2) { //如果余数为1,说明count是奇数,也就是操作--->开启飞行模式 case 1: Toast.makeText(context, "开启飞行模式", 1000).show(); break; //如果余数为0,说明count是偶数,也就是操作--->关闭飞行模式 case 0: Toast.makeText(context, "关闭飞行模式", 1000).show(); break; } } }
2.在AndroidManifest中注册该广播接收者
<receiver android:name=".MyReceiver"> <intent-filter> <action android:name="android.intent.action.AIRPLANE_MODE"/> </intent-filter> </receiver>
注意这里用的action是android.intent.action.AIRPLANE_MODE,这是由系统提供的当手机飞行状态改变时发出的广播,正是因为此处将MyReceiver注册为接收指定的系统广播,才会在onReceive中接收到这个广播
动态接收系统广播
1.新建一个广播接收者,与静态的基本一致public class MyReceiver extends BroadcastReceiver{ //用来作为标志,判断是开启还是关闭 private static int count = 0; //如果是飞行模式状态变化的广播,就执行操作 @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub //每改变一次飞行状态,count就+1 count++; switch (count%2) { //如果余数为1,说明count是奇数,也就是操作--->开启飞行模式 case 1: Toast.makeText(context, "开启飞行模式", 1000).show(); break; //如果余数为0,说明count是偶数,也就是操作--->关闭飞行模式 case 0: Toast.makeText(context, "关闭飞行模式", 1000).show(); break; } } }
2.在Activity中对它进行注册
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); IntentFilter filter = new IntentFilter(); //这里将飞行模式改变的Action添加到过滤器中 filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); registerReceiver(new MyReceiver(), filter); } }
运行
如何取消注册广播?
在上面的动态注册自定义广播的例子中,如果你尝试将当前应用程序kill掉,就会发现Logcat报出如下错误:从报错信息中可以看出,是由于我们是动态注册的自定义广播,所以在Activity被销毁时,广播接收者将不再接收相应的广播,系统要求必须注销该广播
解决方法很简单,只需要在Activity的onDestroy方法中,调用unregisterReceiver(myreceiver);就可以在Activity退出时注销广播:
@Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); unregisterReceiver(myreceiver); }
有序广播
上面所演示的广播都是通过sendBroadcast发送出去的,是无序的广播,有时候广播接收者是有多个的,如果我们需要将它们设定一定的优先级,就需要通过sendOrderedBroadcast()来发送有序广播下面通过自定义三个广播接收者和一个广播发送者,演示如何使用有序广播:
1.创建三个广播接收者
有序广播
上面所演示的广播都是通过sendBroadcast发送出去的,是无序的广播,有时候广播接收者是有多个的,如果我们需要将它们设定一定的优先级,就需要通过sendOrderedBroadcast()来发送有序广播
下面通过自定义三个广播接收者和一个广播发送者,演示如何使用有序广播:
1.创建三个广播接收者
MyFirstReceiver.java:
public class MyFirstReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub String msg = intent.getStringExtra("msg"); Log.d("MyFirstReceiver", msg); //将数据传输给下一个广播接收者 setResultData("This is the Second Msg From MyFirstReceiver"); } }
MySecondReceiver.java:
public class MySecondReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub //获得上一个广播接收者传过来的数据 String msg = getResultData(); Log.d("MySecondReceiver", msg); //将数据传输给下一个广播接收者 setResultData("This is the Third Msg From MySecondReceiver"); } }
MyThirdReceiver.java:
public class MyThirdReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub //获得上一个广播接收者传过来的数据 String msg = getResultData(); Log.d("MyThirdReceiver", msg); } }
2.在AndroidManifest.xml中注册三个广播接收者:
<receiver android:name=".MyFirstReceiver"> <intent-filter android:priority="300"> <action android:name="OrderBroadcast"/> </intent-filter> </receiver> <receiver android:name=".MySecondReceiver"> <intent-filter android:priority="200"> <action android:name="OrderBroadcast"/> </intent-filter> </receiver> <receiver android:name=".MyThirdReceiver"> <intent-filter android:priority="100"> <action android:name="OrderBroadcast"/> </intent-filter> </receiver>
注意到这里每个接收者都多加了一个属性:priority,这个属性表示有序广播中的优先级,值越高表示优先级越高,那么当广播发出时,优先级最高的便会第一个接收到广播并拦截下来。然后才会继续往优先级低的传递下去。
3.发送有序广播
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent("OrderBroadcast"); intent.putExtra("msg", "This is the First Msg From Activity"); sendOrderedBroadcast(intent, null); } }
运行,查看Logcat打印结果:
局部广播
上面的有序广播和无序广播都是属于全局广播,也就是当发出这个广播,整个系统都有机会接收到该广播,但有时候出于安全性问题的考虑,Android还提供了局部广播,这种广播只有在同一个App内的广播接收器才能收到,其它应用不会接收到。局部广播的使用:
public class MainActivity extends Activity { private MyReceiver receiver = new MyReceiver(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this); IntentFilter filter = new IntentFilter(); filter.addAction("broadcasttest"); //注册局部广播 manager.registerReceiver(receiver , filter); Intent intent = new Intent(); intent.setAction("broadcasttest"); //发送广播 manager.sendBroadcast(intent); } }
BroadcastReceiver的生命周期
【三部曲】调用广播--->执行onReceive()--->onReceive方法return之后即结束该广播该注意的点
Android中规定了BroadCastReceiver不能处理复杂长时间的逻辑操作,如果在onReceive方法在10s内没法执行完毕,则系统会视之为未响应状态,可能会报ANR错误。可以将这些耗时操作放在Service中开辟子线程去执行。至此,对于BroadcastReceiver在Android中的使用已经基本了解,我会在以后的博文中用实战demo来演示广播在开发中的应用!整理不易,如果你觉得本文对你有所帮助,请点个赞,如果有哪些地方存在不足,还望指出,共同探讨。
相关文章推荐
- android启动过程之init.rc文件浅析
- RecyclerView分割线之RecyclerView.ItemDecoration的理解(笔记)
- Android签名总结
- Android : DevicePolicyManager
- Android Activity生命周期及启动模式详解
- 关于Android的Dialog
- Android的原子操作函数
- Android蓝牙编程 之 同时打开SPP和音频A2DP服务
- Android-onInterceptTouchEvent()和onTouchEvent()总结
- Android学习笔记开篇
- 提高工作效率的16条Android开发小经验
- Android SearchView搜索框组件的使用方法
- 一个介绍android 的log的一些进一步封装与快捷操作的文章
- (4.1.20.2)Android 5.0 可以给一个 View 单独设置一个 theme
- Android性能优化
- Android常用英文词汇
- Android 快速开发框架:推荐10个框架:afinal、ThinkAndroid、andBase、KJFrameForAndroid、SmartAndroid、dhroid..
- 【Android】24、如何随时随地退出程序
- (4.1.20)android的样式(style)与主题(theme)
- android N 分屏