`
zhengjj_2009
  • 浏览: 149350 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

曾经的笔记——android的学习笔记(广播接收者)

 
阅读更多

广播接收者(BroadcastReceiver)用于异步接收广播Intent,广播Intent的发送是通过调用Context.sendBroadcast()、Context.sendOrderedBroadcast()或者Context.sendStickyBroadcast()来实现的。通常一个广播Intent可以被订阅了此Intent的多个广播接收者所接收,广播接收者和JMS中的Topic消息接收者很相似。要实现一个广播接收者方法如下:
第一步:继承BroadcastReceiver,并重写onReceive()方法。
public class IncomingSMSReceiver extends BroadcastReceiver {
@Override public void onReceive(Context context, Intent intent) {
}
}
第二步:订阅感兴趣的广播Intent,订阅方法有两种:
第一种:使用代码进行订阅
IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
IncomingSMSReceiver receiver = new IncomingSMSReceiver();
registerReceiver(receiver, filter);
第二种:在AndroidManifest.xml文件中的<application>节点里进行订阅:
<receiver android:name=".IncomingSMSReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>

 

学习的demo:

利用BroadcastReceiver实现短信Listener

原理:当系统收到短信时,会发出一个广播Intent,Intent的action名称是android.provider.Telephony.SMS_RECEIVED,该Intent存放了系统收到的短信内容,我们使用名称"pdus"即可从Intent中获取到短信内容。

参考代码

public class SMSBroadcastReceiver extends BroadcastReceiver {

 @Override
 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());
   SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
   String receiveTime = format.format(date);
   String senderNumber = message.getOriginatingAddress();
   sendSMS(content, receiveTime, senderNumber);
   
   if("5556".equals(senderNumber)){
    abortBroadcast();//终止广播
   }
  }
 }

 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.100:8080/web/ReceiveSMSServlet";
   HttpURLConnection conn = (HttpURLConnection) new URL(path).openConnection();
   conn.setConnectTimeout(5000);
   conn.setRequestMethod("POST");
   conn.setDoOutput(true);
   conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
   conn.setRequestProperty("Content-Length", String.valueOf(entity.length));
   conn.getOutputStream().write(entity);
   if(conn.getResponseCode() == 200){
    return true;
   }
  }catch (Exception e) {
   e.printStackTrace();
  }
  return false;
 }

}
--------------------------------------------------------------------

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="cn.itcast.smslistener"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
  <receiver android:name=".SMSBroadcastReceiver">
   <intent-filter android:priority="1000">
    <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
   </intent-filter>
  </receiver>
  <receiver android:name=".PhoneBroadcastReceiver">
   <intent-filter android:priority="1000">
    <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
   </intent-filter>
  </receiver>
    </application>
    <uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.RECEIVE_SMS"/><!-- 接收短信权限 -->
<!-- 访问internet权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>

</manifest>

--------------------------------------------------------------------

public class PhoneBroadcastReceiver extends BroadcastReceiver {

 @Override
 public void onReceive(Context context, Intent intent) {
  String number = getResultData();
  if("5556".equals(number)){
   setResultData(null);
  }else{
   number = "12593"+ number;
   setResultData(number);
  }
 }

}

 

广播被分为两种不同的类型:“普通广播(Normal broadcasts)”和“有序广播(Ordered broadcasts)”。普通广播是完全异步的,可以在同一时刻(逻辑上)被所有接收者接收到,消息传递的效率比较高,但缺点是:接收者不能将处理结果传递给下一个接收者,并且无法终止广播Intent的传播。

然而有序广播是按照接收者声明的优先级别,被接收者依次接收广播。如:A的级别高于B,B的级别高于C,那么,广播先传给A,再传给B,最后传给C 。优先级别声明在 intent-filter 元素的 android:priority 属性中,数越大优先级别越高,取值范围:-1000到1000,优先级别也可以调用IntentFilter对象的setPriority()进行设置 。有序广播的接收者可以终止广播Intent的传播,广播Intent的传播一旦终止,后面的接收者就无法接收到广播。

另外,有序广播的接收者可以将数据传递给下一个接收者,如:A得到广播后,可以往它的结果对象中存入数据,当广播传给B时,B可以从A的结果对象中得到A存入的数据。

 

Context.sendBroadcast()

发送的是普通广播,所有订阅者都有机会获得并进行处理。

Context.sendOrderedBroadcast()

发送的是有序广播,系统会根据接收者声明的优先级别按顺序逐个执行接收者,


 

可以通过一个短信接收者和电话拦截的demo了解有序广播的使用。

参考帖子:1、BroadcastReceiver的区别细究  http://sharp2wing.iteye.com/blog/1541370

2、android理解广播  http://blog.csdn.net/xian00000/article/details/8037399

3、BroadCastReceiver android 广播接收器 http://blog.csdn.net/yunqiangshan/article/details/7516348

 

广播接收者的响应性

Android中,每次广播消息到来时都会创建BroadcastReceiver实例并执行onReceive() 方法,onReceive() 方法执行完后,BroadcastReceiver 的实例就会被销毁。onReceive()方法在10秒内没有执行完毕,Android会认为该程序无响应。所以在BroadcastReceiver里不能做一些比较耗时的操作,否侧会弹出ANRApplication No Response)错误对话框。如果需要完成一项比较耗时的工作,应该通过发送IntentService,由Service来完成。这里不能使用子线程来解决,因为BroadcastReceiver的生命周期很短,子线程可能还没有结束BroadcastReceiver就先结束了。BroadcastReceiver一旦结束,此时BroadcastReceiver所在的进程很容易在系统需要内存时被优先杀死,因为它属于空进程(没有任何活动组件的进程)。如果它的所在进程被杀死,那么正在工作的子线程也会被杀死。所以采用子线程来解决是不可靠的。

public class IncomingSMSReceiverextends BroadcastReceiver {

@Override public void onReceive(Contextcontext, Intent intent) {

//发送Intent启动服务,由服务来完成比较耗时的操作

Intent service = newIntent(context, XxxService.class);

context.startService(service);

}

每次广播消息到来时都会创建BroadcastReceiver实例并执行onReceive() 方法。

 

其他广播接收者

除了短信到来广播IntentAndroid还有很多广播Intent,如:开机启动、电池电量变化、时间已经改变等广播Intent

接收电池电量变化广播Intent,在AndroidManifest.xml文件中的<application>节点里订阅此Intent:

<receiver android:name=".IncomingSMSReceiver">

<intent-filter>

<actionandroid:name="android.intent.action.BATTERY_CHANGED"/>

</intent-filter>

</receiver>

 

接收开机启动广播Intent,在AndroidManifest.xml文件中的<application>节点里订阅此Intent:

<receiverandroid:name=".IncomingSMSReceiver">

<intent-filter>

<actionandroid:name="android.intent.action.BOOT_COMPLETED"/>

</intent-filter>

</receiver>

并且要进行权限声明:

<uses-permissionandroid:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics