Broadcast(广播)是一种广泛运用在应用程序之间传输信息的机制。
BroadcastReceiver(广播接收者)是对发送出来的广播进行过滤接收并响应的一类组件,它就是用来接收来自系统和应用中的广播。
用途:当开机完成后系统会产生一条广播,当网络状态改变时系统会产生一条广播,当电池电量改变时,系统会产生一条广播等。
作为开发者,只需要掌握BroadcastReceiver即可。一般处理Service与Activity之间的消息传递。
使用方法:
1、发送
把信息装入一个Intent对象(如Action、Category)
通过调用相应的方法将Intent对象以广播的方式发送出去
sendBroadcast()
sendOrderBroadcast()
sendStickyBroadcast()
2、接收
当Intent发送以后,所有已经注册的BroadcastReceiver会检查注册时的IntentFilter是否与发送的Intent相匹配,若匹配则就会调用BroadcastReceiver的onReceive()方法。所以当我们定义一个BroadcastReceiver的时候,都要实现onReceive()方法。
注意:BroadcastReceiver需要注册(静态注册:在AndroidMainfest.xml中注册、代码注册:在Java类中注册)
BroadcastReceiver的使用注意事项:
1、BroadcastReceiver的生命周期只有十秒左右
2、在BroadcastReceiver里不能做一些比较耗时的操作
3、如果有耗时操作,应该通过发送Intent给Service,有Service来完成
4、不能使用子线程,因为子线程可能还没有完成任务,BroadcastReceiver就已经结束,这是子线程也会被杀掉
广播种类(前两种比较常用)
1、普通广播(Normal broadcasts):所有监听该广播的广播接收者都可以监听到该广播。
2、有序广播(Ordered broadcasts):按照接收者的优先级顺序接收广播,优先级别在intent-filter中的priority中声明,-1000到1000之间,值越大,优先级越高。可以终止广播意图的继续传播。接收者可以篡改内容。
3、异步广播(粘滞性滞留广播):不能将处理结果传给下一个接收者,无法终止广播,即广播始终存在。
普通广播特点
1、同级别接收先后是随机的(无序)
2、级别低的后收到广播
3、接收器不能截断广播的继续传播,也不能处理广播
4、同级别动态注册高于静态注册
有序广播特点
1、同级别接收先后是随机的
2、能截断广播的继续传播,高级别的广播接收器收到该广播后,可以决定把该广播是否截断。
3、接收器能截断广播的继续传播,也能处理广播
4、同级别动态注册高于静态注册
广播使用实例:
普通广播
1、布局文件中添加发送广播按钮
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:onClick="doClick"
android:text="发送一条普通广播" />
</RelativeLayout>
2、使用Java代码实现点击按钮发送广播功能
package com.cx.broadcastreceiver;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void doClick(View v){
switch (v.getId()) {
case R.id.button1://发送普通广播
Intent intent = new Intent();
intent.putExtra("msg", "这是一条普通广播");
//为了过滤广播设置Action,唯一的
intent.setAction("cx_one");
sendBroadcast(intent);
break;
}
}
}
3、定义一个广播接收类,并打印广播信息
package com.cx.broadcastreceiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
/*
* 接收广播
*/
public class MyBroadcastReceiver1 extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String s = intent.getStringExtra("msg");
Log.e("11111111111111111", s);
}
}
4、在AndroidMainfest.xml中注册广播
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cx.broadcastreceiver"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.cx.broadcastreceiver.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name="com.cx.broadcastreceiver.MyBroadcastReceiver1">
<!-- 添加过滤器 ,与发送广播设置的Action相同-->
<!-- 接收系统广播时,只需匹配系统Action就可以了 -->
<intent-filter >
<action android:name="cx_one"/>
</intent-filter>
</receiver>
</application>
</manifest>
这样,我们就完成了广播的发送与接收,运行程序点击发送按钮,就会看到打印广播信息
为了验证普通广播的无序特点
1、我们增加一个广播接收类MyBroadcastReceiver2
package com.cx.broadcastreceiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
/*
* 接收广播
*/
public class MyBroadcastReceiver2 extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String s = intent.getStringExtra("msg");
Log.e("2222222222222222", s);
}
}
2、在AndroidMainfest.xml中添加MyBroadcastReceiver2的注册
<receiver android:name="com.cx.broadcastreceiver.MyBroadcastReceiver2">
<intent-filter >
<action android:name="cx_one"/>
</intent-filter>
</receiver>
运行程序查看消息打印时间,正常情况下时间是相同的。但是我在测试的时候出现,MyBroadcastReceiver1先打印,MyBroadcastReceiver2后打印,时间相差3~4ms。
下面在以上代码的基础上,验证级别低的后收到广播特点
1、在AndroidMainfest.xml中设置广播级别
<pre name="code" class="html"><receiver android:name="com.cx.broadcastreceiver.MyBroadcastReceiver1">
<!-- 添加过滤器 ,与发送广播设置的Action相同-->
<!-- 接收系统广播时,只需匹配系统Action就可以了 -->
<intent-filter
android:priority="100">
<action android:name="cx_one"/>
</intent-filter>
</receiver>
<receiver android:name="com.cx.broadcastreceiver.MyBroadcastReceiver2">
<intent-filter
android:priority="200">
<action android:name="cx_one"/>
</intent-filter>
</receiver>
这里将MyBroadcastReceiver1的优先级设置为100,MyBroadcastReceiver2的优先级设置为200,所以会出现MyBroadcastReceiver2广播信息先打印。在测试时如果将优先级设置相同,会出现MyBroadcastReceiver1先打印,MyBroadcastReceiver2后打印,时间相差3~4ms。
接下来我们验证普通广播接收器不能截断广播的特点
1、在设置优先级MyBroadcastReceiver2大于MyBroadcastReceiver1的情况下,在MyBroadcastReceiver2中添加广播截断代码
package com.cx.broadcastreceiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
/*
* 接收广播
*/
public class MyBroadcastReceiver2 extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String s = intent.getStringExtra("msg");
Log.e("2222222222222222", s);
// //截断广播测试
abortBroadcast();
}
}
运行程序,打印MyBroadcastReceiver2中广播信息后,会打印报错代码,接着打印MyBroadcastReceiver1中的广播信息。
验证普通广播接收器不能处理广播的特点
1、在设置优先级MyBroadcastReceiver2大于MyBroadcastReceiver1的情况下,在MyBroadcastReceiver2中添加数据处理代码
package com.cx.broadcastreceiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
/*
* 接收广播
*/
public class MyBroadcastReceiver2 extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String s = intent.getStringExtra("msg");
Log.e("2222222222222222", s);
//数据处理
Bundle bundle = new Bundle();
bundle.putString("test", "处理的数据");
setResultExtras(bundle);
}
}
2、在MyBroadcastReceiver1中增加数据接收代码
package com.cx.broadcastreceiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
/*
* 接收广播
*/
public class MyBroadcastReceiver1 extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String s = intent.getStringExtra("msg");
Log.e("11111111111111", s);
//广播处理代码接收
Bundle bundle = getResultExtras(true);
String s2 = bundle.getString("test");
Log.e("22222221111111", "结果是:" + s2);
}
}
运行程序,打印MyBroadcastReceiver2中广播信息后,会打印报错代码,接着打印MyBroadcastReceiver1中的广播信息,广播处理信息为空
验证同级别动态注册高于静态注册特点
1、将MyBroadcastReceiver2在AndroidMainfest.xml中的注册信息删除,并在主页面中增加MyBroadcastReceiver2的注册信息
package com.cx.broadcastreceiver;
import android.app.Activity;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//动态注册MyBroadcastReceiver2
IntentFilter intentFilter = new IntentFilter("cx_one");
MyBroadcastReceiver2 myBroadcastReceiver = new MyBroadcastReceiver2();
registerReceiver(myBroadcastReceiver, intentFilter);
}
public void doClick(View v){
switch (v.getId()) {
case R.id.button1://发送普通广播
Intent intent = new Intent();
intent.putExtra("msg", "这是一条普通广播");
//为了过滤广播设置Action,唯一的
intent.setAction("cx_one");
sendBroadcast(intent);
break;
}
}
}
运行程序会发现MyBroadcastReceiver2先打印。动态注册缺点,如果注册类生命周期结束,该广播接收器也将收不到广播。
有序广播
1、布局文件中增加有关有序广播按钮
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:onClick="doClick"
android:text="发送一条普通广播" />
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginTop="48dp"
android:onClick="doClick"
android:text="发送一条有序广播" />
</RelativeLayout>
2、Java代码中增加有序广播按钮点击事件
package com.cx.broadcastreceiver;
import android.app.Activity;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//动态注册MyBroadcastReceiver2
IntentFilter intentFilter = new IntentFilter("cx_one");
MyBroadcastReceiver2 myBroadcastReceiver = new MyBroadcastReceiver2();
registerReceiver(myBroadcastReceiver, intentFilter);
}
public void doClick(View v){
switch (v.getId()) {
case R.id.button1://发送普通广播
Intent intent = new Intent();
intent.putExtra("msg", "这是一条普通广播");
//为了过滤广播设置Action,唯一的
intent.setAction("cx_one");
sendBroadcast(intent);
break;
case R.id.button2://发送普通广播
Intent intent2 = new Intent();
intent2.putExtra("msg", "这是一条有序广播");
//为了过滤广播设置Action,唯一的
intent2.setAction("cx_one");
//这里权限设为null
sendOrderedBroadcast(intent2, null);
break;
}
}
}
3、重复普通广播中的测试,发现能够实现截断广播和处理广播。
异步广播
1、布局文件中增加异步广播按钮
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:onClick="doClick"
android:text="发送一条普通广播" />
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginTop="48dp"
android:onClick="doClick"
android:text="发送一条有序广播" />
<Button
android:id="@+id/button3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginTop="96dp"
android:onClick="doClick"
android:text="发送一条异步广播" />
</RelativeLayout>
2、增加一个广播接收类MyBroadcastReceiver3
package com.cx.broadcastreceiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class MyBroadcastReceiver3 extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String s = intent.getStringExtra("msg");
Log.e("3333333333333333", s);
}
}
3、Java代码中增加异步广播按钮点击事件
package com.cx.broadcastreceiver;
import android.app.Activity;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//动态注册MyBroadcastReceiver2
IntentFilter intentFilter = new IntentFilter("cx_one");
MyBroadcastReceiver2 myBroadcastReceiver = new MyBroadcastReceiver2();
registerReceiver(myBroadcastReceiver, intentFilter);
}
public void doClick(View v){
switch (v.getId()) {
case R.id.button1://发送普通广播
Intent intent = new Intent();
intent.putExtra("msg", "这是一条普通广播");
//为了过滤广播设置Action,唯一的
intent.setAction("cx_one");
sendBroadcast(intent);
break;
case R.id.button2://发送有序广播
Intent intent2 = new Intent();
intent2.putExtra("msg", "这是一条有序广播");
//为了过滤广播设置Action,唯一的
intent2.setAction("cx_one");
//这里权限设为null
sendOrderedBroadcast(intent2, null);
break;
case R.id.button3://发送异步广播
Intent intent3 = new Intent();
intent3.putExtra("msg", "这是一条异步广播");
//为了过滤广播设置Action,唯一的
intent3.setAction("cx_three");
sendStickyBroadcast(intent3);
//前两种广播必须是先注册,后发送。这里先发送,后注册
IntentFilter intentFilter = new IntentFilter("cx_three");
MyBroadcastReceiver3 myBroadcastReceiver = new MyBroadcastReceiver3();
registerReceiver(myBroadcastReceiver, intentFilter);
break;
}
}
}
4、增加异步广播需要权限
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
注意:对于上面的所有代码,凡是在主页面中动态注册广播的,都要在页面结束时销毁广播。不好意思上面的忘记写了。
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
unregisterReceiver(myBroadcastReceiver2);
unregisterReceiver(myBroadcastReceiver3);
}
源码下载