启程!!

广播的概念

在Android中。Broadcast是一种广泛运用的在应用程序之间传输信息的机制。而BroadcastReceiver是对发送出来的Broadcast进行过滤接受并响应的一类组件。

广播接收者(BroadcastReceiver)用于接收广播Intent的, 广播Intent的发送是通过调用sendBroadcast/sendOrderedBroadcast来实现的。通常一个广播Intent能够被订阅了此Intent的多个广播接收者所接收。

广播的种类:
无序广播(Normal broadcasts)。相似于日常使用的WIFI,由一个广播者发出信号。能够有非常多接收者同一时候接收,而且信号无法被中断和篡改。
有序广播(Ordered broadcasts),能够有终于的接收者。并存在信号接收的优先级;
定义广播接收者的步骤:
①定义一个类,继承BroadcastReceiver,并重写onReceive(Context context, Intent intent)方法,处理广播到来的事件。
②注冊广播接收者。

有两种方式,一种是静态的:在AndroidManifest.xml文件里实现<receiver>标签;一种是动态的:使用Context.registerReceiver()方法动态注冊广播接收者。

注意:注冊你的广播接收者在Activity.onResume()方法中;反注冊你的广播接收者在Activity.onPause()中。

本篇注冊的广播接收者。都在清单文件里声明;代码注冊的方式在下一篇中解说;

广播的生命周期

广播接收者也是执行在主线程中,所以在广播接收者的onReceive方法内不能有耗时的操作。须要放在子线程中做。

onReceive的生命周期非常短,有可能广播接收者结束。子线程还没有结束。这时广播接收者所在进程非常有可能被杀掉,这样子线程就会出问题,所以耗时操作最好放到service服务中。

注意事项:
①广播接收者的生命周期是非常短暂的,在接收到广播的时候创建,onReceive()方法结束之后销毁。
②广播接收者中不要做一些耗时的工作,否则会弹出Application No Response错误对话框。

③最好也不要在广播接收者中创建子线程做耗时的工作,由于广播接收者被销毁后进程就成为了空进程。非常容易被系统杀掉。

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

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

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

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

  1. public class SmsReceiver extends BroadcastReceiver {
  2. @Override
  3. public void onReceive(Context context, Intent intent) {
  4. // 以下是获取短信信息的固定写法
  5. Bundle bundle = intent.getExtras();
  6. // 获取到短信的数据
  7. Object[] objects = (Object[]) bundle.get("pdus");
  8. for (Object object : objects) {
  9. SmsMessage sms = SmsMessage.createFromPdu((byte[]) object);
  10. // 获取短信的发送者
  11. String originatingAddress = sms.getOriginatingAddress();
  12. // 获取短信的内容
  13. String messageBody = sms.getMessageBody();
  14. System.out.println("广播接收者收到短信:(" + originatingAddress + "," + messageBody + ")");
  15. }
  16. }
  17. }

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

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

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

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

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

也是个非常easy的案例,依照上边的步骤创建并声明、加入过滤器就能够了 ,这里主要演示一下几个API的使用。

  1. <!-- 监听外拨电话的权限 -->
  2. <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
  3. <!-- 声明广播接收者 -->
  4. <receiver android:name="com.bzh.ip.OutCallReceiver" >
  5. <!-- 接收外拨电话广播须要加入的过滤器 -->
  6. <intent-filter>
  7. <action android:name="android.intent.action.NEW_OUTGOING_CALL" >
  8. </action>
  9. </intent-filter>
  10. </receiver>

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

  1. public class OutCallReceiver extends BroadcastReceiver {
  2. @Override
  3. public void onReceive(Context context, Intent intent) {
  4. String resultData = getResultData();
  5. System.out.println("未加拨区号前:" + resultData);
  6. setResultData("010" + resultData);
  7. }
  8. }

请看一下測试图:

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

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

案例-SD卡状态监听

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

  1. <receiver android:name="com.bzh.sdcard.SDCardReceiver" >
  2. <intent-filter>
  3. <action android:name="android.intent.action.MEDIA_UNMOUNTED" />
  4. <data android:scheme="file" />
  5. </intent-filter>
  6. </receiver>

再看下onReceiver()中的代码

  1. @Override
  2. public void onReceive(Context context, Intent intent) {
  3. // 获取到触发广播的动作
  4. String action = intent.getAction();
  5. if ("android.intent.action.MEDIA_UNMOUNTED".equals(action)) {
  6. System.out.println("SD卡被卸载了");
  7. }
  8. }

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

介绍一些经常使用的广播

开机自己主动启动广播

Android3.0曾经不须要加权限, 3.0版本号以后添加了安全性, 假设应用程序没有被开启过, 是不能够接收到系统启动完毕的广播的.

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

拦截动作:

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

指定scheme: package

拦截接收的短信广播

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

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

发送自己定义广播

发送自定的广播也非常easy,依据Google的Api发现能够使用sendBroadcast(intent)方法,把一个意图作为广播发送出去。

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

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

  1. public void click(View v) {
  2. Intent intent = new Intent();
  3. intent.setAction("com.bzh.biezhihua");
  4. intent.putExtra("name", "别志华");
  5. // Broadcast the given intent to all interested BroadcastReceivers.
  6. sendBroadcast(intent);
  7. }

在还有一个project中,我们创建广播接收者并设置意图过滤器(指定关心的动作)。就能够得到数据了;

以下是清单文件里广播接收者的配置。

  1. <receiver android:name="com.bzh.receiverbroadcast.BiezhihuaReceiver" >
  2. <intent-filter>
  3. <!-- 接收感兴趣的广播事件 -->
  4. <action android:name="com.bzh.biezhihua" />
  5. </intent-filter>
  6. </receiver>

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

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

有序广播和无序广播

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

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

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

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

① 首先,创建发送有序广播project,并发送一个有序广播。有序广播有非常多參数,在代码中已经给出了凝视。

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

  1. public void click(View v) {
  2. // 被发送的广播
  3. Intent intent = new Intent();
  4. intent.setAction("com.bzh.sendorder");// 设置动作
  5. // 接收广播须要的权限;一般填入null
  6. String receiverPermission = null;
  7. // 有序广播的监听者。会在最后接收到发送出的广播
  8. BroadcastReceiver resultReceiver = new FinalReceiver();
  9. Handler scheduler = null;
  10. // 广播的发送码
  11. int initialCode = 200;
  12. // 广播的内容,能够使用getResultDataa()方法获取
  13. String initialData = "我是广播发送者";
  14. // 广播携带的数据
  15. Bundle initialExtras = new Bundle();
  16. initialExtras.putString("name", "别志华");
  17. sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler, initialCode, initialData, initialExtras);
  18. System.out.println("发送了有序广播");
  19. }

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

相同是继承BroadcastReceiver可是却不须要在清单文件里声明。

以下是FinalReceiver监察者的代码。

  1. @Override
  2. public void onReceive(Context context, Intent intent) {
  3. int resultCode = getResultCode();
  4. String resultData = getResultData();
  5. Bundle resultExtras = getResultExtras(true);
  6. String name = resultExtras.getString("name");
  7. System.out.println("我是有序广播最后的监听者-结果码:" + resultCode + ",内容:" + resultData + "。携带的数据:" + name);
  8. }

② 然后。创建有序广播接收者project,并创建FirstReceiverSecondReceiver两个广播接收者。

以下是清单文件里的声明和代码;

  1. <receiver android:name="com.bzh.receiverorder.FirstReceiver" >
  2. <intent-filter android:priority="1000" >
  3. <action android:name="com.bzh.sendorder" />
  4. </intent-filter>
  5. </receiver>
  6. <receiver android:name="com.bzh.receiverorder.SecondReceiver" >
  7. <intent-filter android:priority="900" >
  8. <action android:name="com.bzh.sendorder" />
  9. </intent-filter>
  10. </receiver>

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

  1. @Override
  2. public void onReceive(Context context, Intent intent) {
  3. // 拿到广播发送的结果码
  4. int resultCode = getResultCode();
  5. // 拿到广播发送的内容
  6. String resultData = getResultData();
  7. // 拿到广播携带的数据
  8. Bundle resultExtras = getResultExtras(true);
  9. String name = resultExtras.getString("name");
  10. System.out.println("第一个接收者-结果码:" + resultCode + ",内容:" + resultData + ",携带的数据:" + name);
  11. // 改动携带的数据
  12. resultExtras.putString("name", "胡玉琼");
  13. // 继续传播广播
  14. setResult(300, "我是第一个接收者", resultExtras);
  15. }

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

  1. @Override
  2. public void onReceive(Context context, Intent intent) {
  3. int resultCode = getResultCode();
  4. String resultData = getResultData();
  5. Bundle resultExtras = getResultExtras(true);
  6. String name = resultExtras.getString("name");
  7. System.out.println("第二个接收者-结果码:" + resultCode + "。内容:" + resultData + ",携带的数据:" + name);
  8. resultExtras.putString("name", "我爱大家");
  9. setResult(400, "我是第二个接收者", resultExtras);
  10. }

最后,看一下測试的结果:

能够清楚的看到。结果依照我们代码写的顺序发生。

结合工作和面试

请描写叙述一下广播?
广播是Android系统的一个事件,他通过广播的机制去分发这个事件,系统已经实现了非常多广播接收者。

像:低电量,手机重新启动,接收短信,拨打电话,sd卡挂载,一个apk的成功安装…,系统都会通过广播给这些事件分发出去。

这个广播被分发出去之后呢,假设有人想接收到这个广播事件,就须要用这个广播接收者了。

粘性广播?
Sticky:粘性 开发非常少用到。可是面试有可能会问到:

sendStickyBroadcast(intent) // 阴魂不散的广播 (粘性的广播)

粘性广播,会一直等待intent指定的事件处理完毕,才会消失。

广播接受者的生命周期都是比較短的。一般接受到广播之后10s左右就会结束,可是有一些广播事件是比較耗时的。比方WIFI状态改变。

Wifi设置:发送wifi状态改变的广播,系统就是通过sendStickyBroadcast来实现的,由于获取wifi状态改变是一个非常耗时的操作(获取手机的SSID,而且会获取IP地址等等一系列操作),假设用一般发送广播方式,还没等wifi状态获取完。广播就结束了。

Android基础笔记(九)- 广播的更多相关文章

  1. Android 学习笔记 BroadcastReceiver广播...

    PS:不断提升自己,是件好事... 学习内容: 1.BroadcastReceiver的使用.. 2.通过BroadcastReceiver去启动Service... 1.BroadcastRecei ...

  2. Android学习笔记(广播机制)

    1.Android的广播机制介绍 收听收音机也是一种广播,在收音机中有很多个广播电台,每个广播电台播放的内容都不相同.接受广播时广播(发送方)并不在意我们(接收方)接收到广播时如何处理.好比我们收听交 ...

  3. Android学习笔记九:Service

    一:Service是什么 Service,服务.一般用于提供需要在后台长期运行的服务(如复杂计算.下载等等耗时任务),其特点是长生命周期的.没有用户界面.在后台运行的. 二:Service的生命周期方 ...

  4. Android学习笔记_19_广播接收者 BroadcastReceiver及其应用_窃听短信_拦截外拨电话

    一.广播接收者类型: 广播被分为两种不同的类型:“普通广播(Normal broadcasts)”和“有序广播(Ordered broadcasts)”. 普通广播是完全异步的,可以在同一时刻(逻辑上 ...

  5. Android基础笔记(十八)- Fragment

    博客的感悟终点-開始 什么是Fragment 加入fragment到Activity的两种方式 Fragment的生命周期 Fragment的向下兼容 Fragment之间的通信 博客的感悟,终点-開 ...

  6. android学习笔记九——RatingBar

    RatingBar==>星级评分条 RatingBar和SeekBar十分相似,它们甚至有相同的父类:AbsSeekBar.两者都允许用户通过拖动来改变进度: 两者最大的区别在于RatingBa ...

  7. Android基础笔记(十四)- 内容提供者读取联系人

    利用内容提供者读取联系人 利用内容提供者插入联系人 内容观察者的原理 利用内容观察者监听系统应用数据库或者自己应用数据库的变化 利用内容提供者读取联系人 读取联系人相对于读取短信来说就复杂非常多了,我 ...

  8. Android基础笔记(十)- 帧动画、补间动画具体解释、对话框

    帧动画 补间动画Tween Animation 对话框以及面试中的注意点 帧动画 帧动画非常easy,我们首先看一下Google官方解释This is a traditional animation ...

  9. <Android 基础(九)> Ndk配置与Demo

    介绍 The NDK is a toolset that allows you to implement parts of your app using native-code languages s ...

随机推荐

  1. Java 8 lambda表达式示例

    例1.用lambda表达式实现Runnable 我开始使用Java 8时,首先做的就是使用lambda表达式替换匿名类,而实现Runnable接口是匿名类的最好示例.看一下Java 8之前的runna ...

  2. requireJS2

    requireJS的初步掌握(二) 前面我们讲述了requireJS的一些认知和优点,==>http://www.cnblogs.com/wymbk/p/6366113.html 这章我们主要描 ...

  3. bzoj 1150

    思路:写的时候感觉是贪心但是没有什么思路... 看了题解,原来有一个选了能反悔的贪心思路, 如果最优那么每个城市只能和旁边的相邻 城市连边,所以问题变成了由n个数,不能取相邻的两个数,取k个最小是多少 ...

  4. bzoj 1143

    求最长反链裸题 补充一点知识.. 链                  :    D 中的一个子集 C   满足 C 是全序集  及C中所有元素都可以比较大小 反链              :   ...

  5. Go语言 IDE之Gogland配置使用

    Gogland 是 JetBrains 公司推出的 Go 语言集成开发环境.Gogland 同样基于 IntelliJ 平台开发,支持 JetBrains 的插件体系.目前正式版尚未发布.官方:htt ...

  6. CentOS 7.4 系统安装 git

    CentOS 7.4 系统安装 git 一.使用 yum 安装 1.查看系统是否已经安装 git [root@localhost ~]# git --version 2.yum 安装 git [roo ...

  7. 子组件通过 $emit 触发父组件的自定义事件

    子组件: <template> <div class="train-city"> <h3>父组件传给子组件的toCity:{{sendData} ...

  8. javascript编写带阴历的黄历

    最近在做一个黄历的快应用(quickapp),需要涉及到公历转阴历,效果如下: 快应用(https://www.quickapp.cn/): 快应用是基于手机硬件平台的新型应用形态:标准是由主流手机厂 ...

  9. 【教程】使用gitee搭建免费的图床

    前几天七牛云的免费图床测试域名回收,导致我上传的图片都不能访问!要配置自定义域名,域名还要绑定主机.没有云主机的我开始想你们搞一个免费的图床,并且数据也不会丢失呢 ? ​ 想到之前自己在GitHub上 ...

  10. 自己的reset.css

    复制.粘贴 /* http://www.cnblogs.com/ele-cat Reset Stylesheet v1.0.1 2018-05-08 Author: Ele-cat - http:// ...