广播机制详解——监听短信到来的广播

来源:互联网 发布:php文章分页 编辑:程序博客网 时间:2024/05/15 06:59

一,系统发送短信到来的广播,我们可以从intent中获取短信的内容

当系统收到短信时,会发出一个action名称为Android.provider.Telephony.SMS_RECEIVED的广播Intent,该Intent存放了接收到的短信内容,使用名称 “pdus”即可从Intent中获取短信内容。
pdus是一个object类型的数组,每一个object都是一个byte[]字节数组,每一项为一条短信。
多数情况下,如果一条短信太长在发送时,手机系统会自动截取为多条发送(一条短信最大容量大约为140字节)。
相应的在接收端,会监听到多次短信到来的广播。

Object[] pduses= (Object[])intent.getExtras().get("pdus");       for(Objectpdus: pduses){           byte[] pdusmessage = (byte[])pdus;           SmsMessage sms = SmsMessage.createFromPdu(pdusmessage);           String mobile = sms.getOriginatingAddress();//发送短信的手机号码           String content = sms.getMessageBody(); //短信内容           Date date = new Date(sms.getTimestampMillis());           SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");           String time = format.format(date);  //得到发送时间       }

二,使用广播接收者接收系统发送的短信到来的广播

广播接收者(BroadcastReceiver)用于接收广播Intent,广播Intent的发送是通过调用Context.sendBroadcast()、Context.sendOrdeedBroadcast()、context.sendStickyBroadcast()来实现的,通常一个广播Intent可以被订阅了此Intent的多个广播接收者所接收,这个特性跟JMS中的Topic消息接收者类似,要实现一个广播接收者方法如下:

第一步,继承BroadcastReceiver,并重写onReceive()方法

public class SMSBroadcastReceiver extends BroadcastReceiver{    @Override    public void onReceive(Context context, Intent intent) {    }}

第二步,订阅感兴趣的广播Intent,订阅方法有两种:

第一种:使用代码进行订阅

SMSBroadcastReceiver receiver = new SMSBroadcastReceiver();IntentFilter filter = new IntentFilter();       filter.addAction("android.provider.Telephony.SMS_RECEIVED");       context.registerReceiver(receiver,filter);

第二种:在AndroidManifest.xml文件中的节点里进行订阅

<receiver android:name=".SMSBroadcastReceiver">           <intent-filter>              <action android:name="android.provider.Telephony.SMS_RECEIVED"/>           </intent-filter>       </receiver>

第三步,增加接收短信权限

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

三,广播的类型

广播被分为两种不同的类型,“普通广播(Normal broadcasts)”和“有序广播(Ordered broadcasts)”。普通广播是完全异步的,可以在同一时刻(逻辑上)被所有接收者接收到,消息传递的效率比较高,但缺点是:接收者不能将处理结果传递给下一个接收者,并且无法终止广播Intent的传播;然而有序广播是按照接收者声明的优先级别(声明在intent-filter元素的android:priority属性中,数据大优先级别越高,取值范围:-1000到1000也可以调用IntentFilter对象的setPriority()进行设置),被接收者依次接收广播。如:A的级别高于B,B的级别高于C,那么,广播先传给A,再传给B,最后传给C。A得到广播后,可以往广播里存入数据,当广播传给B时,B可以从广播中得到A存入的数据。

四,发送广播的方法

Context.sendBroadcast()发送的是普通广播,所有订阅者都有机会获得并进行处理。
Context.sendOrderedBroadcast()发送的是有序广播,系统会根据接收者声明的优先级别按顺序逐个执行接收者,前面的接收者有权终止广播(BroadcastReceiver.abortBroadcast() ),如果广播被前面的接收者终止,后面的接收者就再也无法获取到广播。对于有序广播,前面的接收者可以将处理结果存进广播Intent,然后传给下一个接收者。
sendStickyBroadcast() 意思是如果发送广播之后才执行registerReceiver(BroadcastReceiver,IntentFilter).这条广播依然可以被接受到。换句话说,在ReceiverActivity里是通过代码来注册Recevier而不是在Manifest里面注册的。sendStickyBroadcast发出的最后一个Intent会被保留,当下次Recevier处于活跃的时候,又会接受到它(Perform a sendBroadcast(Intent) that is “sticky,” meaning the Intent you are sending stays around after the broadcast is complete, so that others can quickly retrieve that data through the return value of registerReceiver(BroadcastReceiver, IntentFilter))。需要加BROADCAST_STICKY权限,否则会抛SecurityException

接收电池电量变化广播:

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

接收开机启动广播

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

并在进行权限声明

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

五,onReceive()方法中不应该包含耗时的操作,否则会ANR。

在Android中,程序的响应(Responsive)被活动管理器(Activity Manager)和窗口管理器(Window Manager)这两个系统服务所监视,当BroadcastReceiver在10秒内没有执行完毕,Android会认为该程序无响应,所以在BroadcastReceiver里不能做一些比较耗时的操作,否则会弹出ANR(Application No Response)的对话框。如果需要完成一项比较耗时的工作,应该通过发送Intent给Service,由Service来完成,而不是使用子线程的方法来解决,因为BroadcastReceiver的生命周期很短(在onReceive()执行后BroadcastReceiver的实例就会被销毁),子线程可能还没有结束BroadcastReceiver就先结束了。如果BroadcastReceiver结束了,它的宿主进程还在运行,那么子线程还会继续执行。但宿主进程此时很容易在系统需要内在时被优先杀死。因为它属于空进程(没有任何活动组件的进程)。
每次广播消息到来时,都会创建BroadcastReceiver实例来执行onReceive()方法。

原文地址:http://blog.csdn.net/junjieking/article/details/6867594我对一些内容做了改动,便于自己理解。
0 0
原创粉丝点击