Android-BroadcastReceiver
在Android中,Broadcast是一种广泛运用的在应用程序之间传输信息的机制。而BroadcastReceiver是对发送出来的Broadcast进行过滤接受并响应的一类组件。
广播接收者(BroadcastReceiver)用于接收广播Intent的, 广播Intent的发送是通过调用sendBroadcast/sendOrderedBroadcast来实现的。通常一个广播Intent可以被订阅了此Intent的多个广播接收者所接收。
需求:定义一个广播接收器,用于接收SDCard移除时发送的广播。
创建一个新的Android工程《广播接收器》,包名:com.itheima.broadcastReciver。
在src目录下新建一个SDCardUnmountedReceiver类继承BroadcastReceiver类,覆写onReceive方法,代码清单如下:
public class SDCardUnmountedReceiver extendsBroadcastReceiver {
@Override
public voidonReceive(Context context, Intent intent) {
Toast.makeText(context, "SDCard已经被移除!", 0).show();
}
}
注册SDCardUnmountedReceiver。
:注册一个广播接收者有两种方式。
静态注册:在AndroidManifest.xml中注册广播
在AndroidManifest.xml文件中添加如下配置:
<receiver android:name="com.itheima.broadcastReciver.SDCardUnmountedReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_UNMOUNTED"/>
<data android:scheme="file">data>
intent-filter>
receiver>
动态注册:在Java代码中注册
public class MainActivity extendsActivity {
@Override
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilterintentFilter = newIntentFilter("android.intent.action.MEDIA_UNMOUNTED");
intentFilter.addDataScheme("file");
registerReceiver(newSDCardUnmountedReceiver(), intentFilter);
System.out.println("广播接收器已经注册成功。");
}
}
由于Android高版本中已经不支持SDCard的卸载,因此我们使用Android 2.3版本的模拟器。在settings->Storagesettings中可以找到Unmount SD Card。点击此选项可以移除SDCard。
发现Toast成功打印出了“SDCard已经被移除”信息。
:
★java代码注册的广播接收者优先级要比清单文件的要高, 但是当前的广播接收者的生命周期的期限和activity是相关联的,activity销毁,广播接收者也就不再起作用。
★通过清单文件注册的广播接收者在系统中运行一次后就会被注册到系统中,以后无需运行此广播接受者,但是也可以接收到广播。
★接收广播时要注意在清单文件中添加对应的权限。
需求:监听用户拨打电话,在用户拨打电话号码前自动加上17951等。
拦截的广播:
<action android:name="android.intent.action.NEW_OUTGOING_CALL">action>
需要的权限:
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
新创建一个Android工程《IPCaller》。
在src目录下新创建一个类IPCallerReceiver继承BroadcastReceiver,重写OnReceive方法。
在AndroidManifest.xml中注册广播接收者。
在下面的配置文件中 <intent-filter android:priority="1000">属性代表着给当前接收者设置优先级,优先级越高越优先接收到广播。
运行上面的代码,然后拨打电话5556,发现拨出去的号码已经变为179515556。
需求:
拦截手机开机的广播,手机开机后,弹一个提示。
拦截的广播:
<action android:name="android.intent.action.BOOT_COMPLETED">action>
需要的权限:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
虚拟机重启命令:adb shell reboot
:3.0以上版本必须加权限,以下的版本可以不加,3.0以上的版本如果用户没有启动过程序, 接收不到开启启动完成的广播。
新创建一个Android工程《开机启动》。
在src目录下新创建一个类BootReceiver继承BroadcastReceiver,重写OnReceive方法。
public class BootReceiver extendsBroadcastReceiver {
@Override
public voidonReceive(Context context, Intent intent) {
Toast.makeText(context, "开机启动已经完成", 1).show();
}
}
在AndroidManifest.xml中注册广播接收者。
<receiver android:name="com.itheima.bootStart.BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED">action>
intent-filter>
receiver>
将上面的代码部署到模拟器上,然后关机重启模拟器。
需求:
监听程序的安装或者卸载,并在LogCat中输出提示信息。
拦截的广播:
<actionandroid:name="android.intent.action.PACKAGE_ADDED">action>
<actionandroid:name="android.intent.action.PACKAGE_REMOVED">action>
指定scheme: package
新创建一个Android工程《监听应用安装与卸载》
新创建InstallReceiver类继承BroadcastReceiver类,覆写onReceive方法
public class InstallReceiver extendsBroadcastReceiver {
@Override
public voidonReceive(Context context, Intent intent) {
//获取包名称
StringpackageName = intent.getData().toString();
Stringaction = intent.getAction();
//如果是卸载动作
if ("android.intent.action.PACKAGE_REMOVED".equals(action)){
Toast.makeText(context,packageName + "已经被删除!", 1).show();
System.out.println(packageName + "已经被删除!");
//如果是安装动作
} else if ("android.intent.action.PACKAGE_ADDED".equals(action)){
Toast.makeText(context,packageName + "已经被安装!", 1).show();
System.out.println(packageName + "已经被安装!");
}
}
}
在AndroidManifest.xml清单中注册InstallReceiver。
<receiver android:name="com.itheima.installReceiver.InstallReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
<action android:name="android.intent.action.PACKAGE_ADDED"/>
<data android:scheme="package"/>
intent-filter>
receiver>
将上面的工程部署在模拟器上。然后通过系统应用管理工具,卸载一个应用程序,发现成功接收到了应用被卸载的广播。
需求:
对用户接收的短信进行拦截,若是10086发来的短信,将此短信拦截。
拦截的广播:
<actionandroid:name="android.provider.Telephony.SMS_RECEIVED">action>
需要的权限:
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
:android 4.2 后废除了此action。
新创建一个工程《短信拦截》,在src目录下新建SMSReceiver类继承BroadcastReceiver类
public class SMSReceiver extends BroadcastReceiver {
@Override
public voidonReceive(Context context, Intent intent) {
//获取短信数据pdus:短信集合
Object[]objs = (Object[]) intent.getExtras().get("pdus");
for(Objectpdu : objs){
//通过Android API中的SmsMessage类将短信字节数组转化为短信对象
SmsMessage message = SmsMessage.createFromPdu((byte[])pdu);
//获取短信来源
String address =message.getOriginatingAddress();
//获取短信内容
String body = message.getMessageBody();
//短信短信内容
System.out.println(address+"--"+body);
Toast.makeText(context,address+"--"+body, 1).show();
//终止广播
abortBroadcast();
}
}
在AndroidManifest.xml中注册短信拦截器
<receiver android:name="com.itheima.smsreceiver.SMSReceiver">
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
intent-filter>
receiver>
在AndroidManifest.xml中添加权限
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
将上面的工程部署在模拟器上
打开DDMS视图,选择Emulator Control 选项卡,在Incomeing number:中填写一个号码,模拟发送消息的号码。然后选择SMS单选按钮,在右侧的输入框输入短信的内容。然后点击Send按钮,发送信息。
发现成功拦截了刚才发送的短信。
无序广播不可以被拦截,如果被拦截的话会报错:
BroadcastReceiver trying to return result during a non-orderedbroadcast
所有接收无序广播的广播接收者在此广播被发送时均能接收到此广播
无序广播使用sendBroadcast方法来发送
:无序广播的实现比较简单,因此这里只给出核心代码。
public void sendBroadcast(View view){
//定义一个意图
Intentintent = newIntent();
//设置Action
intent.setAction("com.itheima.broadcast");
//绑定数据
intent.putExtra("data", "我是无序广播数据");
//发送无序广播
sendBroadcast(intent);
}
有序广播可以被拦截,且优先级高的接收者可以拦截优先级低的
广播接收者的优先级的取值范围是: 1000(最高) ~ -1000(最低)
相同优先级下,接收的顺序要看在清单文件中声明的顺序,先声明的接收者比后声明的要先收到广播
无序广播使用sendOrderedBroadcast方法来发送,使用abortBroadcast方法拦截
广播接收者的优先级在清单文件中声明接收者时,在
我们新创建一个项目,来演示无序广播的发送和接收过程。
新创建一个Android工程《广播发送和接收》,包名com.itheima.broadcastAndreceiver。
在默认的MainActivity的布局中添加一个按钮,绑定事件,该事件的核心功能是发送一个有序广播,MainActivity类代码清单如下:
public class MainActivity extendsActivity {
@Override
protected voidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public voidsendOrder(View view) {
// 意图
Intentintent = newIntent();
intent.setAction("com.itheima.data");
/**
* intent The Intent to broadcast; allreceivers matching this Intent
* will receive the broadcast.receiverPermission String naming a
* permissions that a receiver must hold inorder to receive your
* broadcast. If null, no permission isrequired. resultReceiver Your
* own BroadcastReceiver to treat as the finalreceiver of the
* broadcast. scheduler A custom Handler withwhich to schedule the
* resultReceiver callback; if null it will bescheduled in the
*Context's main thread. initialCode An initial value for the result
* code. Often Activity.RESULT_OK. initialDataAn initial value for the
* result data. Often null. initialExtras Aninitial value for the
* result extras. Often null.
* 第一个参数 Intent类型:意图
* 第二个参数 String类型 receiverPermission,接收器需要的权限
* 第三个参数BroadcastReceiver类型,自己定义的接收器作为最终接收器
* 第四个参数Handler类型,用于执行接收器的回调,如果为null则在主线程中执行
* 第五个参数int类型,结果代码的初始码
* 第六个参数初始化参数
* 第七个参数Bundle类型,额外的数据
*/
sendOrderedBroadcast(intent, null, null,
null, RESULT_OK, "1万元钱", null);
}
分别编写MyReceiver和MyReceiver2类,继承BroadcastReceiver类
MyReceiver类代码清单:
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Contextcontext, Intent intent) {
Stringaction = intent.getAction();
StringresultData = getResultData();
Toast.makeText(context, "MyReceiver接收到"+action+"发布的广播:"+resultData, 1).show();
System.out.println("MyReceiver接收到"+action+"发布的广播:"+resultData);
}
}
MyReceiver2类代码清单:
public class MyReceiver2 extendsBroadcastReceiver {
@Override
public voidonReceive(Context context, Intent intent) {
Stringaction = intent.getAction();
StringresultData = getResultData();
Toast.makeText(context, "MyReceiver2接收到"+action+"发布的广播:"+resultData, 1).show();
System.out.println("MyReceiver2接收到"+action+"发布的广播:"+resultData);
}
}
在AndroidManifest.xml中注册MyReceiver和MyReceiver2
<receiver android:name="com.itheima.broadcastAndreceiver.MyReceiver">
<intent-filter android:priority="1000">
<action android:name="com.itheima.data">action>
intent-filter>
receiver>
<receiver android:name="com.itheima.broadcastAndreceiver.MyReceiver2">
<intent-filter android:priority="-1000">
<action android:name="com.itheima.data">action>
intent-filter>
receiver>
:在上面清单文件中我们给MyReceiver设置了最高优先级1000,给MyReceiver2设置了最低优先级-1000。
下面我们分多钟情况,分别演示有序广播的接收规律
1、直接部署上面的工程到模拟器,点击发送广播按钮,控制台结果为:
我们发现MyReceiver先接收到了广播,然后MyReceiver2才接收到广播。
2、修改MyReceiver类的代码:在onReceive方法中添加abortBroadcast()方法,
public class MyReceiver extends BroadcastReceiver {
@Override
public voidonReceive(Context context, Intent intent) {
Stringaction = intent.getAction();
StringresultData = getResultData();
Toast.makeText(context, "MyReceiver接收到"+action+"发布的广播:"+resultData, 1).show();
System.out.println("MyReceiver接收到"+action+"发布的广播:"+resultData);
abortBroadcast();
}
}
然重新部署该工程,运行,点击发送广播按钮。
我们发现只有MyReceiver接收到了广播,而MyReceiver2没有接收到广播。原因就是我们在MyReceiver中执行了abortBroadcast()方法,终止了该广播。
3、在第二种情况的基础上,我们修改MainActivity类中sendOrder方法,修改
sendOrderedBroadcast中第三个参数,指定一个最终接收器。
public void sendOrder(View view) {
// 意图
Intentintent = newIntent();
intent.setAction("com.itheima.data");
sendOrderedBroadcast(intent, null, new MyReceiver2(),
null, RESULT_OK, "1万元钱", null);
}
运行上面工程,然后点击发送广播按钮,发现控制台输出如下信息:
我们发现,虽然在MyReceiver中我们调用了abortBroadcast();方法,但是广播依然被MyReceiver2接收到。原因是我们在sendOrderedBroadcast方法中指定了MyReceiver2接收器为最终接收器,因此该广播被终止的时候MyReceiver2接收器依然可以接收到广播。
4、在第3种情形的基础上,我们修改MyReceiver类,我们将该类中的onReceive方法中的abortBroadcast();方法去掉。然后运行上面工程。发现控制台输入如下信息:
我们发现MyReceiver第一个接收到广播,MyReceiver2第二个接收到广播,然后MyReceiver2又接收到一次广播。对的,结果确实是这样,因为我们在sendOrderedBroadcast方法中,将MyReceiver2作为最终接收器,那么我们发出的广播会被所有符合条件的接收器接收,最后指定的最终接收器不管是否已经接收过信息依然会再次接收。