前些天把四大组件之一的Service扯了一遍,今天就要开始谈谈它的弟兄BroadcastReceiver了。写到这里我挺纠结的,因为广播接收者确实比较简单,但是各位就不要以为简单的就不内涵,也许我们慢慢探讨一下还能有另外一片天地。

  惯例还是先会介绍一下基础的知识,后面会说说关于BroadcastReceiver的接收顺序还有其他的一些小知识。

BroadcastReceiver的概念

  BroadcastReceiver的作用主要是用来监听系统或者应用发出的广播信息,然后根据广播信息作为相应的逻辑处理;说通俗点其实上就是一种全局监听器,要来实现系统中不同组件之间的通信。有时候也会用来作为传输少量而且发送频率低的数据,但是如果数据的发送频率比较高或者数量比较大就不建议用广播接收者来接收了,因为这样的效率很不好,因为BroadcastReceiver接收数据的开销还是比较大的。

BroadcastReceiver的基础使用

  我们先来看看广播接收者的代码,如下:

 public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context arg0, Intent arg1) {
// 用来实现广播接受者接收到广播后执行的代码逻辑
}
}

  简单而完美,实现一个广播接受者仅仅需要我们重写一个函数onReceiver(),如果广播接受者接收到广播后将会执行该函数;但是这个前提是需要将这个广播接收者进行注册,一般来说,BroadcastReceiver的注册方式有且只有两种,一种是静态注册,另外一种是动态注册,广播接收者在注册后就开始监听系统或者应用之间发送的广播消息。

静态注册的方式:打开AndroidManifest清单文件中,像Activity、Service那种添加一个数据项进行注册,如下:

<receiver android:name=".MyBroadcastReceiver">
  <intent-filter>
    <!-- action的命名规则一般建议为:包名.intent.类名 -->
    <action android:name="com.net168.testBcr.intent.mybroadcastreceiver"/>
  </intent-filter>
</receiver>

  静态注册的广播接收者就是一个常驻在系统中的全局监听器,也就是说如果你应用中配置了一个静态的BroadcastReceiver,而且你安装了应用而无论应用是否处于运行状态,广播接收者都是已经常驻在系统中了。但是有些人会很郁闷怎么销毁掉这个广播接收者,其实只要调用PackageManager将Receiver禁用就行了,简单实用吧?

动态注册的方式:使用registerReceiver(receiver, filter)进行广播接收者的注册,代码如下:

//filter是设置receiver的拦截器
IntentFilter filter = new IntentFilter("com.net168.testBcr.intent.mybroadcastreceiver");
MyBroadcastReceiver receiver = new MyBroadcastReceiver();
//动态注册广播接收者
registerReceiver(receiver, filter);

动态注册的广播接收者只有执行了registerReceiver(receiver, filter)才会开始监听广播消息,并对广播消息作为相应的处理。

销毁一个动态注册的BroadcastReceiver如下:

//撤销广播接受者的动态注册
unregisterReceiver(receiver);

撤销注册后广播接收者将不会再监听系统的广播消息。

静态注册的BroadcastReceiver和动态注册的BroadcastReceiver的一些区别

1、静态注册的广播接收者一经安装就常驻在系统之中,不需要重新启动唤醒接收者;动态注册的广播接收者随着应用的生命周期,由registerReceiver开始监听,由unregisterReceiver撤销监听,另外需要注意的一点就是如果应用退出后,没有撤销已经注册的接收者应用应用将会报错。

2、当广播接收者通过intent启动一个activity或者service时,如果intent中无法匹配到相应的组件。动态注册的广播接收者将会导致应用报错,而静态注册的广播接收者将不会有任何报错,因为自从应用安装完成后,广播接收者跟应用已经脱离了关系。

广播接收者机制

  当系统或应用发出广播时,将会扫描系统中的所有广播接收者,通过action匹配将广播发送给相应的接收者,接收者收到广播后将会产生一个广播接收者的实例,执行其中的onReceiver()这个方法;特别需要注意的是这个实例的生命周期只有10秒,如果10秒内没执行结束onReceiver(),系统将会报错。另外在onReceiver()执行完毕之后,该实例将会被销毁,所以不要在onReceiver()中执行耗时操作,也不会在里面创建子线程处理业务(因为可能子线程没处理完,接收者就被回收了);正确的处理方法就是通过intent调用activity或者service处理业务。

发送广播

  广播有三种类型:普通广播和有序广播,还有另外一种不怎么常用的粘性广播

  Android为了满足各种应用要求,设置了两个发送广播的方式,各有特点。一般普通广播可以应用在需要通知各个广播接收者的情况下如开机启动结束发送的广播;而有序广播则应用在需要有特定拦截的场景下如黑名单短信、电话拦截。

普通广播:普通广播是完全异步的,可以在同一时刻(逻辑上)被所有接收者接收到,消息传递的效率比较高,并且无法中断广播的传播。

Intent intent = new Intent();
intent.setAction("com.net168.testBcr.intent.mybroadcastreceiver");
intent.putExtra("data", "hello");
//发送普通广播
sendBroadcast(intent);

通过sendBroad(intent)来发送普通的广播消息。

有序广播:发送有序广播后,广播接收者将按预先声明的优先级依次接收Broadcast。优先级高的优先接收到广播,而在其onReceiver()执行过程中,广播不会传播到下一个接收者,此时当前的广播接收者可以终止广播继续向下传播,也可以将intent中的数据进行修改设置,然后将其传播到下一个广播接收者。

通过sendOrderedBroadcast()来发送有序广播。

//发送有序广播
sendOrderedBroadcast(intent, null);

对于有序广播接收者,我们可以再onReceiver中进行一些操作

public void onReceive(Context arg0, Intent intent) {
  //获取上一个广播的bundle数据
  Bundle bundle = getResultExtras(true);//true:前一个广播没有结果时创建新的Bundle;false:不创建Bundle
  bundle.putString("key", "168168");
  //将bundle数据放入广播中传给下一个广播接收者
  setResultExtras(bundle);
  //终止广播传给下一个广播接收者
  abortBroadcast();
}

在有序广播中,我们可以在前一个广播接收者将处理好的数据传送给后面的广播接收者,也可以调用abortBroadcast()来终结广播的传播。

粘性广播:该广播比较不常用,我们可以通过sendStickyBroadcast()来发送该类型的广播信息,这种的广播的最大特点是,当粘性广播发送后,最后的一个粘性广播会滞留在操作系统中。如果在粘性广播发送后的一段时间里,如果有新的符合广播的动态注册的广播接收者注册,将会收到这个广播消息,虽然这个广播是在广播接收者注册之前发送的,另外一点,对于静态注册的广播接收者来说,这个等同于普通广播。

广播接收者接收广播的次序

注意一点:广播接收者的优先级范围谷歌文档上标示的最大级为1000,但是实际上最大的级数是Integer.MAX(即2147483647)。

  静态广播接收的处理器是由PackageManagerService负责,当手机启动或者新安装了应用的时候,PackageManagerService会扫描手机中所有已安装的APP应用,将AndroidManifest.xml中有关注册广播的信息解析出来,存储至一个全局静态变量当中。需要注意的是:

1、PackageManagerService扫描目录的顺序如下:

  system/framework  ->  system/app  ->  vendor/app  ->  data/app  -> drm/app-private

2、当处于同一目录下时:按照file.list()的返回顺序。(题外话:因为在data/app下的应用都是用户安装的,并且都是以com.xxx.xxx-1.apk 的形式出现,所以如果打算做手机管家之类的应用,需要好好的研究下包名,争取在file.list()的独木桥下抢的头筹---优先接收开机启动完成的广播。)

动态广播接收的处理器是由ActivityManagerService负责,当APP的服务或者进程起来之后,执行了注册广播接收的代码逻辑,即进行加载,最后会存储在一个另外的全局静态变量中。需要注意的是:

1、 这个并非是一成不变的,当程序被杀死之后,已注册的动态广播接收器也会被移出全局变量,直到下次程序启动,再进行动态广播的注册,当然这里面的顺序也已经变更了一次。

2、这里也并没完整的进行广播的排序,只记录的注册的先后顺序,并未有结合优先级的处理。

广播发出的时候,广播接收者接收的顺序如下:

如果广播为有序广播,那么会将动态广播处理器和静态广播处理器合并在一起处理广播的消息,最终确定广播接收的顺序:

1、优先级高的先接收
2、同优先级的动静态广播接收器,动态优先于静态
3、同优先级的动态广播接收器或者同优先级的静态广播接收器;分静态:先扫描的大于后扫描的,动态:先注册的大于后注册的。
 
当广播为普通广播时,有如下的接收顺序:
1、无视优先级,动态广播接收器优先于静态广播接收器
2、同优先级的动态广播接收器或者同优先级的静态广播接收器;分静态:先扫描的大于后扫描的,动态:先注册的大于后注册的。
 
 
作者:enjoy风铃
出处:http://www.cnblogs.com/net168/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则下次不给你转载了。

解析BroadcastReceiver之你需要了解的一些东东的更多相关文章

  1. 解析Service之你需要了解的一些东东

    何为Service Service,俗名服务.在Android系统中,Service与Activity就像一个妈生的,不仅长得像,而且行为(生命周期)也有一些类似.对于Activity来说大家肯定不会 ...

  2. 基于 Asp.Net的 Comet 技术解析

    Comet技术原理 来自维基百科:Comet是一种用于web的技术,能使服务器能实时地将更新的信息传送到客户端,而无须客户端发出请求,目前有两种实现方式,长轮询和iframe流. 简单的说是一种基于现 ...

  3. jQuery 2.0.3 源码分析Sizzle引擎 - 解析原理

    声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 先来回答博友的提问: 如何解析 div > p + div.aaron input[type="checkb ...

  4. EventBus源码解析 源码阅读记录

    EventBus源码阅读记录 repo地址: greenrobot/EventBus EventBus的构造 双重加锁的单例. static volatile EventBus defaultInst ...

  5. EventBus3.0源码解析

    本文主要介绍EventBus3.0的源码 EventBus是一个Android事件发布/订阅框架,通过解耦发布者和订阅者简化 Android 事件传递. EventBus使用简单,并将事件发布和订阅充 ...

  6. Delphi用QJSON解析JSON格式的数据

    本来用superobject来解析JSON已经够用了,可惜这个东东不能在移动端使用,于是找到QJSON来处理. 这是一个国内高手写开源免费的东西,赞一个. 假入数据如下: {"message ...

  7. 读 《.Net 之美》解析.Net Remoting (应用程序域)-- Part.1

    读 <.Net 之美>解析.Net Remoting (应用程序域)-Part1 理解 .Net Remoting 前言: 看张子阳老师的文章,总是给自己很大的信心,这个专题基本上以张老师 ...

  8. JSON解析实例——使用Json-lib

    JSON解析实例——使用Json-lib Json-lib下载及使用 本文介绍用一个类库进行JSON解析. 工具下载地址:http://sourceforge.net/projects/json-li ...

  9. 解决Android解析图片的OOM问题!!!(转)

    大家好,今天给大家分享的是解决解析图片的出现oom的问题,我们可以用BitmapFactory这里的各种Decode方法,如果图片很小的话,不会出现oom,但是当图片很大的时候 就要用BitmapFa ...

随机推荐

  1. Tensflow预测股票实例

    import pandas as pd import numpy as np import matplotlib.pyplot as plt import tensorflow as tf #———— ...

  2. Effective C++ 随笔(2)

    条款5 了解c++默默编写并调用哪些函数 编译器自动生成的copy 构造函数,copy赋值操作符,析构函数,构造函数,这些都是public和inline的,此处inline的意思是他们的定义都是在头文 ...

  3. js格式化文件大小, 输出成带单位的字符串工具

    /** * 格式化文件大小, 输出成带单位的字符串 * @method formatSize * @grammar formatSize( size ) => String * @grammar ...

  4. c3p0使用

    c3p0-config.xml <?xml version="1.0" encoding="UTF-8"?> <c3p0-config> ...

  5. 【王者荣耀之IT大神版】比赛制度说明(匹配赛、排位赛、赏金赛)

    匹配赛(30分钟): 所得金币=6金币/分钟 经验(挂机:玩手机超过30秒): 名次 经验值 胜利条件 失败条件 1 5 提前10min 超出1min 2 4 提前8min 超出3min 3 4 提前 ...

  6. MFC载入JPG图片

    ## 1.定义画图函数 HRESULT CIPCamDlg::draw(char *lpImageFile, HWND hWnd, int nScrWidth, int nScrHeight) { H ...

  7. Visual Studio 2017快捷键

    作者:tongqingliu 转载请注明出处:http://www.cnblogs.com/liutongqing/p/7048639.html Visual Studio 2017快捷键 Ctrl+ ...

  8. Page页面生命周期——微信小程序

    onLoad:function (options) {     //页面初始化     console.log('index Load') }, onShow:function () {     // ...

  9. (转)JDK安装配置教程

    转自:http://jingyan.baidu.com/article/bea41d435bc695b4c41be648.html JDK作为JAVA开发的环境,不管是做JAVA开发的学生,还是做安卓 ...

  10. hibernate之helloword(环境搭建)

    环境搭建 hibernate.cfg.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ...