Android入门——Broadcast Receiver详解与应用

引言

作为Android四大组件之一——BroadcastReceive。BroadcastReceive广泛运用在APP的开发中,其他的三大应用组件不同一样,是唯一需要被动接收,即负责接收的广播接收器永远不知道什么时候可以接收到广播,这种机制其实有点像Event,你永远无法预知什么时候Button的Click方法会被执行,运行在进程的主线程中。广播可以看成是一种事件机制,也可以看成是全局事件,Android 定义了很多这种全局事件,当Android系统发生某些系统事件时,就会向整个系统发出一个全局信息即广播。比如收到短信,来电、电池电量变化等等广播,只要我们实现了他们的action的广播,那么我们就能接收他们的数据了,以便做出一些处理。比如说拦截系统短信,拦截骚扰电话等等 。实现了不同的程序之间的数据传输与共享,因为只要是和发送广播的action相同的接受者都能接受这个广播。

一 服务BroadcastReceiver的概念

Android四大组件中只有广播接收器是需要被动接收,即广播接收器不能主动调用,换言之负责接收的广播接收器永远不知道什么时候可以接收到广播,一个APP可以有多个广播接收器,只要继承BroadcastReceiver即可。广播主要涉及接收和优先级, 只要将广播接收器注册到某个消息上,不管有多少广播接收器,这些的接收器都会按照不同的优先级接收到这个广播,虽然广播接收器和服务一样没有交互UI,但可以在广播接收器中启动一个Activity来响应广播动作。

二 定义广播接收器

通常一个BroadcastReceiver对象的生命周期不超过5秒,所以在BroadcastReceiver里不能做一些比较耗时的操作,如果需要完成一项比较耗时的工作,可以通过发送Intent给Activity或Service,由Activity或Service来完成。

  1. 继承BroadcastReceiver,重写onReceive方法
  2. 在manifest清单文件中声明,作用就是指明了你这个接收器是要接收那个具体的广播
//定义一个电池电量变化广播接收器
public class BroadcastReceiverDemo extends BroadcastReceiver{
    @Override
    public void onReceive(Context context,Intent intent){
        //当收到广播的时候会触发
        ...
    }
}
/*接收电池电量变化广播Intent ,在AndroidManifest.xml文件中的<application>节点里订阅此Intent:
<receiver android:name=".IncomingSMSReceiver">
    <intent-filter>
         <action android:name="android.intent.action.BATTERY_CHANGED"/>
    </intent-filter>
</receiver>
*/

三 广播的分类及优先级

BroadcastReceiver 用于异步接收广播Intent。主要有两大类,用于接收广播的:
1. 正常广播 Normal broadcasts(用 Context.sendBroadcast()发送)是完全异步的。它们都运行在一个未定义的顺序,通常是在同一时间。这样会更有效,但意味着receiver不能包含所要使用的结果或中止的API。
2. 有序广播 Ordered broadcasts(用 Context.sendOrderedBroadcast()发送)每次被发送到一个receiver。所谓有序,就是每个receiver执行后可以传播到下一个receiver,也可以完全中止传播–不传播给其他receiver。 而receiver运行的顺序可以通过匹配intent-filter 里面的android:priority来控制,当priority优先级相同的时候,Receiver以任意的顺序运行。priority值越大优先级越高。
3. 要注意的是,即使是Normal broadcasts,系统在某些情况下可能会恢复到一次传播给一个receiver。 特别是receiver可能需要创建一个进程,为了避免系统超载,只能一次运行一个receiver。Broadcast Receiver 并没有提供可视化的界面来显示广播信息。可以使用Notification和Notification Manager来实现可视化的信息的界面,显示广播信息的内容,图标及震动信息。

四 广播接收器的订阅

创建完了广播接收器,继承BroadcastReceiver并实现相关方法之后,还不能正常使用,必须还要进行订阅工作,订阅有两种方式,静态订阅方式通过manifest清单文件注册通过registerReceiver方法订阅和unregisterReceiver取消订阅
1. 通过清单文件在AndroidManifest.xml文件中的application节点里订阅此Intent:

<receiver android:name=".IncomingSMSReceiver">
    <intent-filter>
         <action android:name="android.intent.action.BATTERY_CHANGED"/>
    </intent-filter>
</receiver>
  1. 通过registerReceiver方法订阅和unregisterReceiver取消订阅
BroadcastReceiverDemo receiver=new BroadcastReceiverDemo ();//创建接收器对象
//订阅对应的广播
regeisterReceiver(receiver,new IntentFilter("android.provider.Telephoy.SMS_RECEIVED"));

//取消订阅
unregeisterReceiver(receiver);

五 几种常见的广播Intent

  • 接收电池电量变化广播Intent
<receiver android:name=".YourCastReceiver">
    <intent-filter>
         <action android:name="android.intent.action.BATTERY_CHANGED"/>
    </intent-filter>
</receiver>
  • 接收开机启动广播Intent
<receiver android:name=".BootSMSReceiver">
    <intent-filter>
         <action android:name="android.intent.action.BOOT_COMPLETED"/>
    </intent-filter>
</receiver>
<!--并且要进行权限声明:-->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  • 接收短信息广播Intent
<receiver android:name=".SMSBroadcastReceiver">
            <intent-filter android:priority="1000">    <action android:name="android.provider.Telephony.SMS_RECEIVED" />
                <action android:name="android.intent.action.PHONE_STATE"/>             
                 <action android:name="android.intent.action.NEW_OUTGOING_CALL" /> 
            </intent-filter>
        </receiver>
  • 接收来去电广播Intent
<receiver android:name=".PhoneBroadcastReceiver">
            <intent-filter android:priority="1000">
                <action android:name="android.intent.action.PHONE_STATE"/>             
                 <action android:name="android.intent.action.NEW_OUTGOING_CALL" /> 
            </intent-filter>
        </receiver>

六 广播接收器BroadcastReceiver的应用

5.1 接收Android预定义的广播

正如前面所说的系统预定义了很多广播,诸如来去电、接收到短信、电池电量变化、开关机等等,我们要想接收到这些广播,只需要两步:

  1. 继承BroadcastReceiver,重写onReceive方法(onReceive() 方法执行完后,BroadcastReceiver 的实例就会被销毁。当onReceive() 方法在10秒内没有执行完毕,Android会认为该程序无响应。所以在BroadcastReceiver里不能做一些比较耗时的操作,否侧会弹出ANR的对话框)
/*通常一个BroadcastReceiver对象的生命周期不超过10秒,所以在BroadcastReceiver里不能做一些比较耗时的操作,如果需要完成一项比较耗时的工作,可以通过发送Intent给Activity或Service,由Activity或Service来完成。*/
public class IncomingSMSReceiver extends BroadcastReceiver {
    @Override public void onReceive(Context context, Intent intent) {
            //发送Intent启动服务,由服务来完成比较耗时的操作
            Intent service = new Intent(context, XxxService.class);
            context.startService(service);
            //发送Intent启动Activity,由Activity来完成比较耗时的操作
            Intent newIntent = new Intent(context, XxxActivity.class);
            context.startActivity(newIntent);
    }
}
  1. 在清单文件中声明对应的权限和设置对应的action值或者利用代码手动订阅广播和取消订阅广播

下面模拟一个监听短信广播,接收到短信之后的处理,静态订阅广播,第一步实现广播接收器

package cmo.test.broadcast;

import java.text.SimpleDateFormat;
import java.util.Date;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.SmsMessage;
import android.util.Log;

public class SMSBroadcastReceiver extends BroadcastReceiver {
    /**
     * 接收Sms的广播接收器
     * onReceive() 方法执行完后,BroadcastReceiver 的实例就会被销毁。当onReceive() 方法在10秒内没有执行完毕,Android会认为该程序无响应。        
     * 所以在BroadcastReceiver里不能做一些比较耗时的操作,否侧会弹出ANR(Application No Response)的对话框。 
     * @author cmo
     */
    @Override
    public void onReceive(Context context, Intent intent) {     
        Log.d("SMSBroadcastReceiver","接收到了短信");
        String sms=monitorSMS(intent);
        ……
    }

    private String monitorSMS(Intent intent){
        Log.d("SMSBroadcastReceiver","接收到了短信ing");
        Object[] msgs=(Object[])intent.getExtras().get("pdus");
        String content="";
        String receiveDate="";
        String sendrNumber="";
        for(Object obj: msgs){
            byte[] sms=(byte[]) obj;
            SmsMessage message=SmsMessage.createFromPdu(sms);
            content=message.getMessageBody();
            Date date=new Date(message.getTimestampMillis());
            receiveDate=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
            sendrNumber=message.getOriginatingAddress();
        }
        if(sendrNumber.("1001")){
            abortBroadcast();//终止广播的继续传递,其他应用就无法接收到了,前提是你的获取短信和监听广播的权限没有被系统本身屏蔽或者其他安全软件
        }
        return "发信人:"+sendrNumber+"发信时间:"+receiveDate+"短信内容:"+content;
    }
}

第二,在清单文件中声明权限和注册广播

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cmo.test.broadcast"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="22" />

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

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <receiver android:name=".SMSBroadcastReceiver">
            <!-- 设置广播接收器的优先等级priority(-1000————1000?)为 最大1000 肯定能超过手机自带的短信功能,但是还会首先被其他诸如360、LBE首先拦截,不知道为什么? -->
            <intent-filter android:priority="1000">
                <!-- 配置action对应的值  就指定了该接收什么类型的广播 -->
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
        </receiver>
    </application>
</manifest>

但出现一个问题,在有些系统上不能正常读取到短信或者拦截短信,也许是读取短信的权限被系统或者安全软件屏蔽了静态注册吧!

还是模拟一个监听短信广播,接收到短信之后的处理,与前面一个例子不同的是这次改为利用代码订阅广播

5.2 利用代码动态订阅广播和取消订阅

//首先定义一个Activity,在Activity的声明周期中代码订阅广播
package cmo.test.costomcastreceiver;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends Activity {
    public static final String SMS_ACTION = "android.provider.Telephony.SMS_RECEIVED";
    BroadcastReceiver mReceiver;  
    static final String Tag = "SMSBROADCAST"; 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override  
    protected void onStart() {  
        super.onStart(); 
        Log.d(Tag, " onStart ");
         //注册广播  
        mReceiver = new SmsBroadcastRecevier();  
        IntentFilter filter  = new IntentFilter(SMS_ACTION);  
        filter.setPriority(1000);
        registerReceiver(mReceiver, filter);    
    }

    @Override  
    protected void onStop() {  
        super.onStop(); 
        Log.d(Tag, " onStop ");
      //取消广播  
        unregisterReceiver(mReceiver);
    } 
}

实现广播接收器,接收到了短信,并且屏蔽了所有短信

package cmo.test.costomcastreceiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.util.Log;
import android.widget.Toast;

public class SmsBroadcastRecevier extends BroadcastReceiver {
    public static final String SMS_ACTION = "android.provider.Telephony.SMS_RECEIVED";
    static final String Tag = "SMSBROADCAST"; 
    String addr,body;  
    @Override
    public void onReceive(Context arg0, Intent arg1) {
        if(arg1.getAction().equals(SmsBroadcastRecevier.SMS_ACTION)){  
            Toast.makeText(arg0, "监测到系统短信", Toast.LENGTH_SHORT).show();  
            //获取intent参数  
            Bundle bundle=arg1.getExtras();  
            //判断bundle内容  
            if (bundle!=null) {  
                //获得并解析短信  
                Object[] pdus=(Object[])bundle.get("pdus");//取 pdus内容  
                SmsMessage[] messages = new SmsMessage[pdus.length];//解析短信  

                for(int i=0;i<messages.length;i++)  
                {   
                    Log.d(Tag, " receive data ");
                    byte[] pdu=(byte[])pdus[i];  
                    messages[i]=SmsMessage.createFromPdu(pdu);     
                    addr = messages[0].getDisplayOriginatingAddress().toString();  
                    body = messages[0].getDisplayMessageBody().toString();
                    System.out.println("\n"+"addr :"+addr + "body:"+body);
                }  
                Log.d(Tag, " abortBroadcast ");
                 //取消系统短信广播  
                abortBroadcast();
            }
        }
    }
}

在清单文件中声明权限

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cmo.test.costomcastreceiver"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="14" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.READ_SMS" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name=".SmsBroadcastRecevier">
        </receiver>
    </application>
</manifest>

运行结果:成功截取到了短信并且拦截了
这里写图片描述

5.3 模拟广播机制,发送自定义广播和接收广播信息

  • 继承BroadcastReceiver,重写广播接收器
  • 初始化广播接收器对象,定义意图过滤器action
  • 注册自定义广播registerReceiver(myReceiver);
  • 发送自定义广播 sendBroadcast(new Intent(myAction)
  • 取消广播的订阅unregisterReceiver(myReceiver);
//接收到了自定义广播的时候,就会执行onReceive方法
package cmo.test.broadcast;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class MonitorBroadcast extends BroadcastReceiver {
    /**
     * 定义接收模拟广播的接收器
     */
    final String TAG="MONITOR_BROAD" ;
    @Override
    public void onReceive(Context arg0, Intent arg1) {
        Log.d(TAG,"接收到了"+arg1.getAction()+"的自定义广播");
    }
}

在Activity主界面完成广播的注册、发送、取消订阅

package cmo.test.broadcast;

import android.app.Activity;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

public class MainActivity extends Activity {
    private final String TAG="MONITOR_BROAD" ;
    private final String myAction="cmo.test.broadcast.MONITOR_BROAD";
    private MonitorBroadcast myReceiver;
    private IntentFilter intentFilter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myReceiver=new MonitorBroadcast();
        Log.d(TAG,"初始化自定义广播对象");
        intentFilter=new IntentFilter(TAG);
        Log.d(TAG,"初始化意图过滤器");
        registerReceiver(myReceiver, intentFilter);//注册自定义广播
        Log.d(TAG,"注册自定义广播");
    }
    public void sendCast(View view){
        //发送自定义myAction的广播
        Intent intnet = new Intent(myAction);
        sendBroadcast(intnet);//发送自定义myAction的广播
        Log.d(TAG,"发送自定义广播");
    }
    public void stopCast(View view){
        unregisterReceiver(myReceiver);
        Log.d(TAG,"取消了自定义广播的订阅");
    }
}

运行结果
这里写图片描述

小结

广播接收者(BroadcastReceiver)用于异步接收广播Intent,广播Intent的发送是通过调用Context.sendBroadcast()、Context.sendOrderedBroadcast()或者Context.sendStickyBroadcast()来实现的。通常一个广播Intent可以被订阅了此Intent的多个广播接收者所接收

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CrazyMo_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值