广播是一种广泛运用在应用程序之间传输信息的机制,android中的广播用于监听系统事件或应用程序事件!android中的广播包括普通广播、有序广播以及异步广播(粘性广播)!
广播又有常驻型广播和非常驻型广播,常驻型广播是在xml中进行注册的,当应用程序关闭后,如果有对应的广播发送过来,广播接收器还是能够被激活;非常驻型广播是在代码中进行注册的,当应用程序关闭,广播也就取消了,我们可以在Activity中的onCreate或者onResume方法中注册广播,然后在onDestory或者onPause方法中取消注册广播;
注意:如果是非常驻型广播,应用程序关闭后,必须取消注册广播,否则会抛出异常!!
普通广播的发送
普通广播的发送使用方式:
sendBroadcast(Intent intent):intent表示意图,所有匹配该广播的意图都能收到该广播信息
sendBroadcast(intent, String receiverPermission);intent与上面一样,receiverPermission表示权限,与之匹配权限的广播才能接收到相应的广播,如果为null,表示不经许可的要求!
一、使用sendBroadcast(Intent intent)发送广播
1)通过代码注册非常驻型广播:
//定义两个广播接收者 BroadcastReceiver receiver1=new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { System.out.println("receiver1 started!"); } }; BroadcastReceiver receiver2=new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { System.out.println("receiver2 started!"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //注册广播 IntentFilter filter=new IntentFilter(); filter.addAction("com.xin.action.broadcast"); registerReceiver(receiver1, filter); registerReceiver(receiver2, filter); } @Override protected void onPause() { super.onPause(); //取消注册广播 unregisterReceiver(receiver1); unregisterReceiver(receiver2); }代码注册属于非常驻型广播,我们需在Activity相应的生命周期中取消注册广播:unregisterReceiver
2)通过xml文件注册常驻型广播,此时的MyBroadcast1、MyBroadcast2为两个广播类:
public class MyBroadcast1 extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { System.out.println("MyBroadcast1 started!"); } }
public class MyBroadcast2 extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { System.out.println("MyBroadcast2 started!"); } }
在AndroidManifest.xml中的application中添加:
<receiver android:name=".MyBroadcast1"> <intent-filter> <action android:name="com.xin.action.broadcast"/> </intent-filter> </receiver> <receiver android:name=".MyBroadcast2"> <intent-filter> <action android:name="com.xin.action.broadcast"/> </intent-filter> </receiver>代码中的IntentFilter和xml文件中的intent-filter是一样的,都是Intent意图,表示Intent(String actionName)发送出去的广播能被哪些广播接收者所接收!
3)广播的发送:与之匹配的intent意图的广播将被激活
Intent intent=new Intent("com.xin.action.broadcast"); sendBroadcast(intent);输出结果为:MyBroadcast1 started,MyBroadcast2 started!!
二、使用sendBroadcast(intent, String receiverPermission)发送广播
第二个参数的介绍如上面所示,指的是一个权限,我们需在AndroidManifest.xml中声明一个权限:
<permission android:name="com.xin.permission" android:protectionLevel="normal"/>里面还有很多的属性可供我们选择,大家可以去自己去了解一下;
然后我们的发送广播方和接收广播方都需要该权限定义:
发送广播方使用该权限:
<uses-permission android:name="com.xin.permission"/>通过方法发送广播:sendBroadcast(intent,"com.xin.permission");其中第二个参数表示我们定义的权限name
接收方声明广播权限:
<receiver android:name=".MyBroadcast1" android:permission="com.xin.permission"> <intent-filter> <action android:name="com.xin.action.broadcast"/> </intent-filter> </receiver>这样,使用带权限的广播就定义好了,我们在发送方和接收方都需要给权限进行定义,否则消息发送不过去!
注意,通过sendBroadcast(intent,"com.xin.permission");发送的广播,并不一定需要在receiver中添加android:permission才能接收到,测试发现,没有添加这个也能接收到:
<receiver android:name=".MyBroadcast2"> <intent-filter> <action android:name="com.xin.action.broadcast"/> </intent-filter> </receiver>
有序广播的发送
顾名思义,有序广播就是广播的发送是按照顺序进行的,它根据优先级别的定义android:priority的高低来进行有序发送,一个接受完发给下一个接收,优先级越高,表示它接收到的广播级别高,android:priority的范围一般是在-1000到1000之间;
有序广播和普通广播之间的区别:
有序广播和无序广播的区别:我们发送完无序广播之后,我们不知道谁先接收谁后接收,更不要说当这个接收了之后不要再发给另外的了。而有序广播就可以做到这一点,它通过设置优先级可以决定广播接受者的顺序。
有序广播的发送方式:
sendOrderedBroadcast(intent, receiverPermission);
sendOrderedBroadcast(intent, receiverPermission, resultReceiver,
scheduler, initialCode, initialData, initialExtras)
意图,广播,所有匹配的这一意图将接收机接收广播。
receiverPermission 这是权限,一个接收器必须持以接收您的广播。如果为 null ,不经许可的要求。
resultReceiver 您自己 BroadcastReceiver 来当作最后的广播接收器。
调度自定义处理程序,用以安排 resultReceiver 回调 ; 如果为 null 将语境中的主线程举行。
initialCode 一种结果代码的初始值。通常为 Activity.RESULT_OK 。这个值是 -1 ;为其他 int 型 也可以,如 0,1,2;
initialData 一种结果数据的初始值。通常情况下为空 , 是 String 类型 ;
initialExtras 一种结果额外的初始值。通常情况下为空 , 是 Bundle;
1, 该广播的级别有级别之分,级别数值是在 -1000 到 1000 之间 , 值越大 , 优先级越高;
2, 同级别接收是先后是随机的,再到级别低的收到广播;
3, 同级别接收是先后是随机的,如果先接收到的把广播截断了,同级别的例外的接收者是无法收到该广播的,截断广播的方式:abortBroadcast() ;
4 ,能截断广播的继续传播,高级别的广播收到该广播后,可以决定把该钟广播是否截断掉。
5 ,实验现象,在这个方法发来的广播中,代码注册方式中,收到广播先后次序为:注明优先级的、代码
代码演示:
下面给大家演示一下发送有序广播,并且通过Intent在广播之间传递数据,因为关于权限那块上面已经说了,所以在有序广播这里就不再描述了,通过sendOrderedBroadcast(intent, receiverPermission);方法发送有序广播,第二个参数就设置为null了:这里我们通过xml注册广播
1)定义广播
public class MyBroadcast2 extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { System.out.println("MyBroadcast2 started!"); //接收sendOrderedBroadcast传递过来的Intent中的参数 System.out.println(intent.getStringExtra("test")); //添加另一个参数 Bundle bundle=new Bundle(); bundle.putString("test2", "我是从MyBroadcast2中存储的数据"); //将其封装为Bundle对象,让下一个广播接收 setResultExtras(bundle); } }
public class MyBroadcast1 extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { System.out.println("MyBroadcast started!"); //接收sendOrderedBroadcast传递过来的Intent中的参数 System.out.println(intent.getStringExtra("test")); //得到从上一个广播中携带过来的另一个数据 Bundle bundle=getResultExtras(true); System.out.println(bundle.getString("test2")); } }2)在AndroidManifest.xml中声明广播:
<receiver android:name=".MyBroadcast1"> <intent-filter android:priority="900"> <action android:name="com.xin.action.broadcast"/> </intent-filter> </receiver> <receiver android:name=".MyBroadcast2"> <intent-filter android:priority="1000"> <action android:name="com.xin.action.broadcast"/> </intent-filter>上面声明的广播中,MyBroadcast2比Mybroadcast1的优先级高!
3)发送有序广播
Intent intent=new Intent("com.xin.action.broadcast"); intent.putExtra("test", "我是sendOrderedBroadcast发送过来的数据!"); sendOrderedBroadcast(intent,null);测试结果:
因为Mybroadcast2的优先级(1000)比Mybroadcast1(900)的高,所以广播通过sendOrderedBroadcast发送出去后,首先被Mybroadcast2接收,然后再Mybroadcast2中通过setResultExtras设置了另一些参数一起传到Mybroadcast1,然后Mybroadcast1接收到广播,也通过getResultExtras(true)接收从Mybroadcast2中携带过来的数据,所以出现上面的结果!
经测试发现,在使用sendBroadcast时候,如果在BroadcastReceiver中使用setResultExtras或者getResultExtras,程序会报错,因为它发送的不是有序广播!
注意:
1、如果是在代码中注册的,我们可以通过filter.setPriority(1000);来设置其优先级,这里就不举例说明了!
2、如果我们想让有序广播在一个BroadcastReceiver中接收后,不再往下一个广播执行,可以调用其abortBroadcast();中断广播的发送,后面的广播将接收不到!
粘性广播(异步广播)的发送
在网上专业名称各不一样,有人讲它是粘性广播,也有人说它是异步广播,先不讨论它的专业名词的问题了,先来让我们了解它有什么用,它与普通广播的区别就是当广播取消注册后,然后发送一个粘性广播,广播重新注册后仍然能接收到粘性广播发送过来的消息!
普通广播与粘性广播最大的区别:
我们知道,我们先注册广播,然后发送广播,那么无论是什么广播都能被接收到,那么如果我们先发送广播,后注册广播呢:
普通广播:未注册广播-->发送广播-->注册广播-->接收不到广播
粘性广播:未注册广播-->发送广播-->注册广播-->能接收到广播,并且能接收到多次发送广播的最后一条广播信息
这就是两者之间的区别,下面我们通过代码的方式给大家举一个例子,我们的广播是在代码中注册的非常驻型广播:
页面只包含三个测试按钮:
我们在注册广播的Activity中注册广播:RegisterActivity,在其生命周期的onPause方法中取消注册广播unregisterBr
//定义广播 BroadcastReceiver receiver=new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action=intent.getAction(); int count=intent.getIntExtra("count", 0); System.out.println("action="+action+",count="+count); } }; //注册广播 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.register); IntentFilter filter=new IntentFilter(); //添加广播Action filter.addAction("com.xin.action.broadcast"); filter.addAction("com.xin.action.sticky.broadcast"); registerReceiver(receiver, filter); } //取消注册广播 @Override protected void onPause() { super.onPause(); System.out.println("RegisterBroadActivity onPause!"); unregisterReceiver(receiver); }在MainActivity中发送广播:
//定义一个变量,来统计点击发送粘性广播的次数,然后测试粘性广播的接收是不是最后一条广播 private int count; @Override public void onClick(View v) { Intent intent=null; switch(v.getId()){ case R.id.btn_send1://发出广播sendBroadcast intent=new Intent("com.xin.action.broadcast"); sendBroadcast(intent); break; case R.id.btn_send2://发出粘性广播sendStickyBroadcast count++; intent=new Intent("com.xin.action.sticky.broadcast"); intent.putExtra("count", count); sendStickyBroadcast(intent); break; case R.id.register://启动注册广播页面 intent=new Intent(MainActivity.this,RegisterBroadActivity.class); startActivity(intent); break; } } @Override protected void onResume() { super.onResume(); count=0; System.out.println("MainActivity onResume!"); }注意,发送粘性广播,我们需要在AndroidManifest.xml中添加能够发送粘性广播的权限,否则会报错:
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>测试及结论:
当我们点击发送sendBroadcast按钮3次--点击注册按钮,控制台无输出结果
当我们点击发送sendStickyBroadcast按钮4次--点击注册按钮,控制台输出结果:action=com.xin.action.sticky.broadcast,count=4
这就是普通广播和粘性广播的区别
sendBroadcast发送出去的广播,如果没有广播进行注册,那么该广告也就接收不到了,当重新注册广播后,也接收不到
sendStickyBroadcast发送出去的广播,如果没有广播进行注册,那么该广告此时也就接收不到了,当重新注册广播后,会接收到,并且会接受sendStickyBroadcast发出去的最后一条广播,所以上面的输出结果中点击发送stickybroadcast 4次,count变为4,那么当重新注册广播后,控制台会输出结果count=4;
sendStickyBroadcast发出的最后一个Intent会被保留,下次当Recevier处于活跃的 时候,又会接受到它。
当我们需要移除掉粘性广播的时候,调用方法:removeStickyBroadcast(intent);即可清除掉粘性广播
还有一个发送广播的方式:sendStickyOrderedBroadcast (),测试在这个方法发来的广播,代码注册方式中,收到广播先后次序为:注明优先级的、代码注册的、没有优先级的;如果都没有优先级,代码注册收到为最先。
上面给大家介绍了广播操作中的几种方式:
发送广播:sendBroadcast(Intent intent)、sendBroadcast(Intent intent,String receiverPermission);
发送有序广播:sendOrderedBroadcast(Intent intent,String receiverPermission);
发送粘性广播:sendStickyBroadcast(Intent intent);
还有一种方式:sendStickyOrderedBroadcast();(未研究,不知道用的多不多)
在Android的广播操作中,我们还应该知道:
1、无论对于有序广播还是无序广播,广播接收器默认都是运行在主线程中的(main线程,即UI线程)。可以通过在程序中使用registerReceiver(receiver, filter, broadcastPermission, scheduler)方法中的最后一个参数指定要运行的广播接收器的线程。也可以在Manifest.xml文件中设置(Intent-filter标签中设置android:process)。
2、我们在代码中注册广播registerBroadcast十次,那么广播发送过来的时候会接收十次,注销广播只需一次!
3、每次广播到来时 , 会重新创建 BroadcastReceiver 对象 , 并且调用 onReceive() 方法 , 执行完以后 , 该对象即被销毁 . 当 onReceive() 方法在 10 秒内没有执行完毕, Android 会认为该程序无响应 . 所以在BroadcastReceiver 里不能做一些比较耗时的操作 , 否侧会弹出 ANR(Application NoResponse) 的对话框,如果需要完成一项比较耗时的工作 , 应该通过发送 Intent 给 Service, 由 Service 来完成 . 这里不能使用子线程来解决 , 因为 BroadcastReceiver 的生命周期很短 , 子线程可能还没有结束BroadcastReceiver 就先结束了 .BroadcastReceiver 一旦结束 , 此时 BroadcastReceiver 的所在进程很容易在系统需要内存时被优先杀死 , 因为它属于空进程 ( 没有任何活动组件的进程 ). 如果它的宿主进程被杀死 , 那么正在工作的子线程也会被杀死 . 所以采用子线程来解决是不可靠的 .
4、耗时的操作应该通过广播启动service来执行操作
BroadcastReceiver receiver=new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Intent intent=new Intent(context,TestService.class); startService(intent); } };