启程!!!
在Android中,Broadcast是一种广泛运用的在应用程序之间传输信息的机制。而BroadcastReceiver
是对发送出来的Broadcast进行过滤接受并响应的一类组件。
广播接收者(BroadcastReceiver
)用于接收广播Intent的, 广播Intent的发送是通过调用sendBroadcast/sendOrderedBroadcast
来实现的。通常一个广播Intent可以被订阅了此Intent的多个广播接收者所接收。
BroadcastReceiver
,并重写
onReceive(Context context, Intent intent)
方法,处理广播到来的事件;
AndroidManifest.xml
文件中实现
<receiver>
标签;一种是动态的:使用
Context.registerReceiver()
方法动态注册广播接收者;
注意:注册你的广播接收者在Activity.onResume()
方法中;反注册你的广播接收者在Activity.onPause()
中。
本篇注册的广播接收者,都在清单文件中声明;代码注册的方式在下一篇中讲解;
广播接收者也是运行在主线程中,所以在广播接收者的onReceive方法内不能有耗时的操作,需要放在子线程中做。
onReceive
的生命周期很短,有可能广播接收者结束,子线程还没有结束,这时广播接收者所在进程很有可能被杀掉,这样子线程就会出问题,所以耗时操作最好放到service服务中。
Application No Response
错误对话框。
**注意:**4.0版本之后为了安全考虑,要求应用程序必须有界面,且被运行过一次,的程序才能接收广播事件。
通过一个小小的案例来讲解下广播接收者的使用步骤和短信的广播的监听与操作,和一些常用的API;
第一步:定义一个类,继承BroadcastReceiver
,并重写onReceive(Context context, Intent intent)
方法,处理广播到来的事件;
public class SmsReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 以下是获取短信信息的固定写法
Bundle bundle = intent.getExtras();
// 获取到短信的数据
Object[] objects = (Object[]) bundle.get("pdus");
for (Object object : objects) {
SmsMessage sms = SmsMessage.createFromPdu((byte[]) object);
// 获取短信的发送者
String originatingAddress = sms.getOriginatingAddress();
// 获取短信的内容
String messageBody = sms.getMessageBody();
System.out.println("广播接收者收到短信:(" + originatingAddress + "," + messageBody + ")");
}
}
}
第二步:注册广播接收者。在AndroidManifest.xml
文件中实现<receiver>
标签;
<!-- 接收短信的权限 -->
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<!-- 声明广播接收者 -->
<receiver android:name="com.bzh.sms.SmsReceiver" >
<!-- 接收短信广播事件的意图过滤器 -->
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
值得我们注意的是,在清单文件中声明<receiver>
时,千万不要用错标签,假如写成了<activity>
的话,系统运行不会报错,但是会接收不到广播事件。
另外,在onReceiver()
方法中的解析短信是固定写法,不需要记住,用的时候查一下就行了。
也是个很简单的案例,按照上边的步骤创建并声明、添加过滤器就可以了 ,这里主要演示一下几个API的使用。
<!-- 监听外拨电话的权限 -->
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<!-- 声明广播接收者 -->
<receiver android:name="com.bzh.ip.OutCallReceiver" >
<!-- 接收外拨电话广播需要添加的过滤器 -->
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" >
</action>
</intent-filter>
</receiver>
看一下广播接收着中的代码:
public class OutCallReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String resultData = getResultData();
System.out.println("未加拨区号前:" + resultData);
setResultData("010" + resultData);
}
}
请看一下测试图:
我们拨打的是110,在经过我们自定义的广播接收者后变成了010110,说明我们已经成功的修改了外拨电话广播中的数据。那么我们看一下getResultData()
和setResultData(String)
,一个是获取广播中的数据,一个是修改广播中的数据;
但是我们又发现setResultData(String)
方法的API中有这么一句only works with broadcasts sent through Context.sendOrderedBroadcast
,这说明外拨电话广播事件,是个有序广播,使用Context.sendOrderedBroadcast
这个方法来发送的,这个方法下面的案例再详细讲解。
清单文件中所需的过滤器如下,为了监听卸载SD卡的状态,必须指定scheme的类型为file:
<receiver android:name="com.bzh.sdcard.SDCardReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_UNMOUNTED" />
<data android:scheme="file" />
</intent-filter>
</receiver>
再看下onReceiver()
中的代码
@Override
public void onReceive(Context context, Intent intent) {
// 获取到触发广播的动作
String action = intent.getAction();
if ("android.intent.action.MEDIA_UNMOUNTED".equals(action)) {
System.out.println("SD卡被卸载了");
}
}
这里指的注意的是,我们可以通过onReceiver()
传递给我们的intent
意图对象,拿到触发广播的动作。
Android3.0以前不需要加权限, 3.0版本以后增加了安全性, 如果应用程序没有被开启过, 是不可以接收到系统启动完成的广播的.
拦截的动作:android.intent.action.BOOT_COMPLETED
需要的权限:android.permission.RECEIVE_BOOT_COMPLETED
拦截动作:
安装: android.intent.action.PACKAGE_ADDED
卸载: android.intent.action.PACKAGE_REMOVED
指定scheme: package
(android 4.2 后废除了此action),但是还是可以使用,拦截动作:
android.provider.Telephony.SMS_RECEIVED
优先级别设置为最大, 在系统收到短信之前接收短信:priority="1000“
android.permission.RECEIVE_SMS
发送自定的广播也很简单,根据Google的Api发现可以使用sendBroadcast(intent)
方法,把一个意图作为广播发送出去。
此外,我们知道Intent
对象可以设置意图(广播)的动作Action
;这样的话只要广播接收者设置关心的动作,就能够接收到广播了;
下面是一个超级简单的发送广播的代码;
public void click(View v) {
Intent intent = new Intent();
intent.setAction("com.bzh.biezhihua");
intent.putExtra("name", "别志华");
// Broadcast the given intent to all interested BroadcastReceivers.
sendBroadcast(intent);
}
在另一个工程中,我们创建广播接收者并设置意图过滤器(指定关心的动作),就可以得到数据了;
下面是清单文件中广播接收者的配置。
<receiver android:name="com.bzh.receiverbroadcast.BiezhihuaReceiver" >
<intent-filter>
<!-- 接收感兴趣的广播事件 -->
<action android:name="com.bzh.biezhihua" />
</intent-filter>
</receiver>
下面是接收到广播后,代码的处理。
@Override
public void onReceive(Context context, Intent intent) {
// 取出数据
String extra = intent.getStringExtra("name");
System.out.println(extra);
}
在一开始我们就知道了有无序广播和有序广播,而有序广播在上面已经讲述了如何创建和使用了,那么无序广播如何创建和使用?以及它们之间有什么区别?
<intent-filter android:priority="1000">
中配置优先级;优先级范围是(-1000,1000)
接下来一步一步使用一下有序广播,看看它是怎么样工作的;
需要提前说一下的是:在有序广播中,我们可以使用broadcastReceiver.setResult(int code, String data, Bundle extras)
方法修改广播中的数据,也可以使用broadcastReceiver.abortBroadcast()
方法终止广播;
① 首先,创建发送有序广播
工程,并发送一个有序广播,有序广播有很多参数,在代码中已经给出了注释;
其中,我们给广播设置的动作是com.bzh.sendorder
这意味着,广播的接收者需要在意图过滤器中指定该动作和优先级;
public void click(View v) {
// 被发送的广播
Intent intent = new Intent();
intent.setAction("com.bzh.sendorder");// 设置动作
// 接收广播需要的权限;一般填入null
String receiverPermission = null;
// 有序广播的监听者,会在最后接收到发送出的广播
BroadcastReceiver resultReceiver = new FinalReceiver();
Handler scheduler = null;
// 广播的发送码
int initialCode = 200;
// 广播的内容,可以使用getResultDataa()方法获取
String initialData = "我是广播发送者";
// 广播携带的数据
Bundle initialExtras = new Bundle();
initialExtras.putString("name", "别志华");
sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler, initialCode, initialData, initialExtras);
System.out.println("发送了有序广播");
}
可能你已经注意到了BroadcastReceiver resultReceiver = new FinalReceiver();
它代表着监察广播工作的广播接收者,它会在广播的最后收到广播,用以监察广播中的数据改变;
同样是继承BroadcastReceiver
但是却不需要在清单文件中声明;
下面是FinalReceiver监察者的代码;
@Override
public void onReceive(Context context, Intent intent) {
int resultCode = getResultCode();
String resultData = getResultData();
Bundle resultExtras = getResultExtras(true);
String name = resultExtras.getString("name");
System.out.println("我是有序广播最后的监听者-结果码:" + resultCode + ",内容:" + resultData + ",携带的数据:" + name);
}
② 然后,创建有序广播接收者
工程,并创建FirstReceiver
和SecondReceiver
两个广播接收者;
下面是清单文件中的声明和代码;
<receiver android:name="com.bzh.receiverorder.FirstReceiver" >
<intent-filter android:priority="1000" >
<action android:name="com.bzh.sendorder" />
</intent-filter>
</receiver>
<receiver android:name="com.bzh.receiverorder.SecondReceiver" >
<intent-filter android:priority="900" >
<action android:name="com.bzh.sendorder" />
</intent-filter>
</receiver>
这是第一个广播接收者的代码:
@Override
public void onReceive(Context context, Intent intent) {
// 拿到广播发送的结果码
int resultCode = getResultCode();
// 拿到广播发送的内容
String resultData = getResultData();
// 拿到广播携带的数据
Bundle resultExtras = getResultExtras(true);
String name = resultExtras.getString("name");
System.out.println("第一个接收者-结果码:" + resultCode + ",内容:" + resultData + ",携带的数据:" + name);
// 修改携带的数据
resultExtras.putString("name", "胡玉琼");
// 继续传播广播
setResult(300, "我是第一个接收者", resultExtras);
}
这是第二个广播接收者的代码:
@Override
public void onReceive(Context context, Intent intent) {
int resultCode = getResultCode();
String resultData = getResultData();
Bundle resultExtras = getResultExtras(true);
String name = resultExtras.getString("name");
System.out.println("第二个接收者-结果码:" + resultCode + ",内容:" + resultData + ",携带的数据:" + name);
resultExtras.putString("name", "我爱大家");
setResult(400, "我是第二个接收者", resultExtras);
}
可以清楚的看到,结果按照我们代码写的顺序发生;
结合工作和面试