Android基础笔记(九)- 广播

技术分享

启程!!!

广播的概念

广播的种类:
无序广播(Normal broadcasts),类似于日常使用的WIFI,由一个广播者发出信号,可以有很多接收者同时接收,并且信号无法被中断和篡改;
有序广播(Ordered broadcasts),可以有最终的接收者,并存在信号接收的优先级;
定义广播接收者的步骤:
①定义一个类,继承BroadcastReceiver,并重写onReceive(Context context, Intent intent)方法,处理广播到来的事件;
②注册广播接收者。有两种方式,一种是静态的:在AndroidManifest.xml文件中实现<receiver>标签;一种是动态的:使用Context.registerReceiver()方法动态注册广播接收者;
注意:注册你的广播接收者在Activity.onResume()方法中;反注册你的广播接收者在Activity.onPause()中。

本篇注册的广播接收者,都在清单文件中声明;代码注册的方式在下一篇中讲解;

案例-监听短信到来并解析短信内容

**注意:**4.0版本之后为了安全考虑,要求应用程序必须有界面,且被运行过一次,的程序才能接收广播事件。

通过一个小小的案例来讲解下广播接收者的使用步骤和短信的广播的监听与操作,和一些常用的API;

第一步:定义一个类,继承BroadcastReceiver,并重写onReceive(Context context, Intent intent)方法,处理广播到来的事件;

public class SmsReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // 以下是获取短信信息的固定写法 

        Bundle bundle = intent.getExtras();
        // 获取到短信的数据
        Object[] objects = (Object[]) bundle.get("pdus");
        for (Object object : objects) {
            SmsMessage sms = SmsMessage.createFromPdu((byte[]) object);
            // 获取短信的发送者
            String originatingAddress = sms.getOriginatingAddress();
            // 获取短信的内容
            String messageBody = sms.getMessageBody();
            System.out.println("广播接收者收到短信:(" + originatingAddress + "," + messageBody + ")");
        }

    }
}

第二步:注册广播接收者。在AndroidManifest.xml文件中实现<receiver>标签;

<!-- 接收短信的权限 -->
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<!-- 声明广播接收者 -->
<receiver android:name="com.bzh.sms.SmsReceiver" >
   <!-- 接收短信广播事件的意图过滤器 -->
   <intent-filter>
       <action android:name="android.provider.Telephony.SMS_RECEIVED" />
   </intent-filter>
</receiver>

值得我们注意的是,在清单文件中声明<receiver>时,千万不要用错标签,假如写成了<activity>的话,系统运行不会报错,但是会接收不到广播事件。

另外,在onReceiver()方法中的解析短信是固定写法,不需要记住,用的时候查一下就行了。

案例-拦截外拨电话并设置区号

也是个很简单的案例,按照上边的步骤创建并声明、添加过滤器就可以了 ,这里主要演示一下几个API的使用。

<!-- 监听外拨电话的权限 -->
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<!-- 声明广播接收者 -->
<receiver android:name="com.bzh.ip.OutCallReceiver" >
    <!-- 接收外拨电话广播需要添加的过滤器 -->
    <intent-filter>
        <action android:name="android.intent.action.NEW_OUTGOING_CALL" >
        </action>
    </intent-filter>
</receiver>

看一下广播接收着中的代码:

public class OutCallReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        String resultData = getResultData();
        System.out.println("未加拨区号前:" + resultData);
        setResultData("010" + resultData);
    }
}

请看一下测试图:
技术分享

我们拨打的是110,在经过我们自定义的广播接收者后变成了010110,说明我们已经成功的修改了外拨电话广播中的数据。那么我们看一下getResultData()setResultData(String),一个是获取广播中的数据,一个是修改广播中的数据;

但是我们又发现setResultData(String)方法的API中有这么一句only works with broadcasts sent through Context.sendOrderedBroadcast,这说明外拨电话广播事件,是个有序广播,使用Context.sendOrderedBroadcast这个方法来发送的,这个方法下面的案例再详细讲解。

案例-SD卡状态监听

清单文件中所需的过滤器如下,为了监听卸载SD卡的状态,必须指定scheme的类型为file:

<receiver android:name="com.bzh.sdcard.SDCardReceiver" >
    <intent-filter>
        <action android:name="android.intent.action.MEDIA_UNMOUNTED" />
        <data android:scheme="file" />
    </intent-filter>
</receiver>

再看下onReceiver()中的代码

@Override
public void onReceive(Context context, Intent intent) {

    // 获取到触发广播的动作
    String action = intent.getAction();
    if ("android.intent.action.MEDIA_UNMOUNTED".equals(action)) {
        System.out.println("SD卡被卸载了");
    }
}

这里指的注意的是,我们可以通过onReceiver()传递给我们的intent意图对象,拿到触发广播的动作。

介绍一些常用的广播

开机自动启动广播

Android3.0以前不需要加权限, 3.0版本以后增加了安全性, 如果应用程序没有被开启过, 是不可以接收到系统启动完成的广播的.

拦截的动作:android.intent.action.BOOT_COMPLETED
需要的权限:android.permission.RECEIVE_BOOT_COMPLETED
安装和卸载程序的广播

拦截动作:

安装: android.intent.action.PACKAGE_ADDED
卸载: android.intent.action.PACKAGE_REMOVED

指定scheme: package

拦截接收的短信广播

(android 4.2 后废除了此action),但是还是可以使用,拦截动作:

android.provider.Telephony.SMS_RECEIVED      
优先级别设置为最大, 在系统收到短信之前接收短信:priority="1000“
需要权限: android.permission.RECEIVE_SMS

发送自定义广播

发送自定的广播也很简单,根据Google的Api发现可以使用sendBroadcast(intent)方法,把一个意图作为广播发送出去。

此外,我们知道Intent对象可以设置意图(广播)的动作Action;这样的话只要广播接收者设置关心的动作,就能够接收到广播了;

下面是一个超级简单的发送广播的代码;

public void click(View v) {

    Intent intent = new Intent();
    intent.setAction("com.bzh.biezhihua");
    intent.putExtra("name", "别志华");

    // Broadcast the given intent to all interested BroadcastReceivers.
    sendBroadcast(intent);
}

在另一个工程中,我们创建广播接收者并设置意图过滤器(指定关心的动作),就可以得到数据了;

下面是清单文件中广播接收者的配置。

<receiver android:name="com.bzh.receiverbroadcast.BiezhihuaReceiver" >
    <intent-filter>

        <!-- 接收感兴趣的广播事件 -->
        <action android:name="com.bzh.biezhihua" />
    </intent-filter>
</receiver>

下面是接收到广播后,代码的处理。

@Override
public void onReceive(Context context, Intent intent) {
    // 取出数据
    String extra = intent.getStringExtra("name");
    System.out.println(extra);
}

有序广播和无序广播

在一开始我们就知道了有无序广播和有序广播,而有序广播在上面已经讲述了如何创建和使用了,那么无序广播如何创建和使用?以及它们之间有什么区别?

无序广播
不可以被拦截
有序广播
①按照一定的优先级发送,可以在<intent-filter android:priority="1000">中配置优先级;优先级范围是(-1000,1000)
②可以被拦截、数据可以被修改;

接下来一步一步使用一下有序广播,看看它是怎么样工作的;

需要提前说一下的是:在有序广播中,我们可以使用broadcastReceiver.setResult(int code, String data, Bundle extras)方法修改广播中的数据,也可以使用broadcastReceiver.abortBroadcast()方法终止广播;

① 首先,创建发送有序广播工程,并发送一个有序广播,有序广播有很多参数,在代码中已经给出了注释;

其中,我们给广播设置的动作是com.bzh.sendorder这意味着,广播的接收者需要在意图过滤器中指定该动作和优先级;

public void click(View v) {
    // 被发送的广播
    Intent intent = new Intent();
    intent.setAction("com.bzh.sendorder");// 设置动作

    // 接收广播需要的权限;一般填入null
    String receiverPermission = null;

    // 有序广播的监听者,会在最后接收到发送出的广播
    BroadcastReceiver resultReceiver = new FinalReceiver();

    Handler scheduler = null;

    // 广播的发送码
    int initialCode = 200;

    // 广播的内容,可以使用getResultDataa()方法获取
    String initialData = "我是广播发送者";

    // 广播携带的数据
    Bundle initialExtras = new Bundle();
    initialExtras.putString("name", "别志华");

    sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler, initialCode, initialData, initialExtras);

    System.out.println("发送了有序广播");
}

可能你已经注意到了BroadcastReceiver resultReceiver = new FinalReceiver();它代表着监察广播工作的广播接收者,它会在广播的最后收到广播,用以监察广播中的数据改变;

同样是继承BroadcastReceiver但是却不需要在清单文件中声明;

下面是FinalReceiver监察者的代码;

@Override
public void onReceive(Context context, Intent intent) {
    int resultCode = getResultCode();
    String resultData = getResultData();
    Bundle resultExtras = getResultExtras(true);
    String name = resultExtras.getString("name");

    System.out.println("我是有序广播最后的监听者-结果码:" + resultCode + ",内容:" + resultData + ",携带的数据:" + name);
}

② 然后,创建有序广播接收者工程,并创建FirstReceiverSecondReceiver两个广播接收者;

下面是清单文件中的声明和代码;

<receiver android:name="com.bzh.receiverorder.FirstReceiver" >
   <intent-filter android:priority="1000" >
        <action android:name="com.bzh.sendorder" />
    </intent-filter>
</receiver>
<receiver android:name="com.bzh.receiverorder.SecondReceiver" >
    <intent-filter android:priority="900" >
        <action android:name="com.bzh.sendorder" />
    </intent-filter>
</receiver>

这是第一个广播接收者的代码:

@Override
public void onReceive(Context context, Intent intent) {

    // 拿到广播发送的结果码
    int resultCode = getResultCode();

    // 拿到广播发送的内容
    String resultData = getResultData();

    // 拿到广播携带的数据
    Bundle resultExtras = getResultExtras(true);
    String name = resultExtras.getString("name");

    System.out.println("第一个接收者-结果码:" + resultCode + ",内容:" + resultData + ",携带的数据:" + name);

    // 修改携带的数据
    resultExtras.putString("name", "胡玉琼");

    // 继续传播广播
    setResult(300, "我是第一个接收者", resultExtras);
}

这是第二个广播接收者的代码:

@Override
public void onReceive(Context context, Intent intent) {

    int resultCode = getResultCode();
    String resultData = getResultData();
    Bundle resultExtras = getResultExtras(true);
    String name = resultExtras.getString("name");

    System.out.println("第二个接收者-结果码:" + resultCode + ",内容:" + resultData + ",携带的数据:" + name);

    resultExtras.putString("name", "我爱大家");

    setResult(400, "我是第二个接收者", resultExtras);
}

最后,看一下测试的结果:
技术分享

可以清楚的看到,结果按照我们代码写的顺序发生;

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。