广播接收者BroadcastReceiver-程序员宅基地

技术标签: java  apache  android  

Android广播机制概述

Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器)。广播作为Android组件间的通信方式,可以使用的场景如下:

1.同一app内部的同一组件内的消息通信(单个或多个线程之间);

2.同一app内部的不同组件之间的消息通信(单个进程);

3.同一app具有多个进程的不同组件之间的消息通信;

4.不同app之间的组件之间消息通信;

5.Android系统在特定情况下与App之间的消息通信。

从实现原理看上,Android中的广播使用了观察者模式,基于消息的发布/订阅事件模型。因此,从实现的角度来看,Android中的广播将广播的发送者和接受者极大程度上解耦,使得系统能够方便集成,更易扩展。具体实现流程要点粗略概括如下:

1.广播接收者BroadcastReceiver通过Binder机制向AMS(Activity Manager Service)进行注册;

2.广播发送者通过binder机制向AMS发送广播;

3.AMS查找符合相应条件(IntentFilter/Permission等)的BroadcastReceiver,将广播发送到BroadcastReceiver(一般情况下是Activity)相应的消息循环队列中;

4.消息循环执行拿到此广播,回调BroadcastReceiver中的onReceive()方法。

广播发送者和广播接收者分别属于观察者模式中的消息发布和订阅两端,AMS属于中间的处理中心。广播发送者和广播接收者的执行是异步的,发出去的广播不会关心有无接收者接收,也不确定接收者到底是何时才能接收到。显然,整体流程与EventBus非常类似。

写一个广播接收者

   注册:动态、静态

发送广播

    普通广播、有序广播、延时广播

接收系统的广播

短信监听器、隐私短信

闹钟

1、自定义BroadcastReceiver 

自定义广播接收器需要继承基类BroadcastReceiver,并实现抽象方法onReceive(context, intent)方法。广播接收器接收到相应广播后,会自动回到onReceive(..)方法。默认情况下,广播接收器也是运行在UI线程,因此,onReceive方法中不能执行太耗时的操作。否则将因此ANR。一般情况下,根据实际业务需求,onReceive方法中都会涉及到与其他组件之间的交互,如发送Notification、启动service等。

注册:

静态注册

<receiver android:name=".MyBroadcastReceiver" >

    <intent-filter>

        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />

    </intent-filter>

    <intent-filter>

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

    </intent-filter>

</receiver>

1、继承BroadcastReceiver

2、注册

3、发送广播

需要注意的属性

android:exported  ——此broadcastReceiver能否接收其他App的发出的广播,这个属性默认值有点意思,其默认值是由receiver中有无intent-filter决定的,如果有intent-filter,默认值为true,否则为false。(同样的,activity/service中的此属性默认值一样遵循此规则)同时,需要注意的是,这个值的设定是以application或者application user id为界的,而非进程为界(一个应用中可能含有多个进程);

android:name  —— 此broadcastReceiver类名;

android:permission  ——如果设置,具有相应权限的广播发送方发送的广播才能被此broadcastReceiver所接收;

android:process  ——broadcastReceiver运行所处的进程。默认为app的进程。可以指定独立的进程(Android四大基本组件都可以通过此属性指定自己的独立进程)

动态注册

最好在成对的生命周期里面写注册和取消注册

比如在onstart写注册,那就最好在onstop里面取消注册

registerReceiver(BroadcastReceiver receiver, IntentFilter filter)

registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler)

当此Activity实例化时,会动态将MyBroadcastReceiver注册到系统中。当此Activity销毁时,动态注册的MyBroadcastReceiver将不再接收到相应的广播。

public class MainActivity extends Activity {

    public static final String BROADCAST_ACTION = "com.example.corn";

    private BroadcastReceiver mBroadcastReceiver;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        mBroadcastReceiver = new MyBroadcastReceiver();

        IntentFilter intentFilter = new IntentFilter();

        intentFilter.addAction(BROADCAST_ACTION);

        registerReceiver(mBroadcastReceiver, intentFilter);

    }

    @Override

    protected void onDestroy() {

        super.onDestroy();

        unregisterReceiver(mBroadcastReceiver);

    }

}

发送广播

Intent intent = new Intent();

2 intent.setAction(BROADCAST_ACTION);

3 intent.putExtra("name", "qqyumidi");

4 sendBroadcast(intent);

根据广播的发送方式,可以将其分为以下几种类型:

1.Normal Broadcast:普通广播

2.System Broadcast: 系统广播

3.Ordered broadcast:有序广播

4.Sticky Broadcast:粘性广播(在 android 5.0/api 21中deprecated,不再推荐使用,相应的还有粘性有序广播,同样已经deprecated)

5.Local Broadcast:App应用内广播

下面分别总结下各种类型的发送方式及其特点。

1).Normal Broadcast:普通广播

此处将普通广播界定为:开发者自己定义的intent,以context.sendBroadcast_"AsUser"(intent, ...)形式。具体可以使用的方法有:

sendBroadcast(intent)/sendBroadcast(intent, receiverPermission)/sendBroadcastAsUser(intent, userHandler)/sendBroadcastAsUser(intent, userHandler,receiverPermission)。

普通广播会被注册了的相应的(intent-filter匹配)接收,且顺序是无序的。如果发送广播时有相应的权限要求,BroadCastReceiver如果想要接收此广播,也需要有相应的权限。

2).System Broadcast: 系统广播

Android系统中内置了多个系统广播,只要涉及到手机的基本操作,基本上都会发出相应的系统广播。如:开启启动,网络状态改变,拍照,屏幕关闭与开启,点亮不足等等。每个系统广播都具有特定的intent-filter,其中主要包括具体的action,系统广播发出后,将被相应的BroadcastReceiver接收。系统广播在系统内部当特定事件发生时,有系统自动发出。

3)Ordered broadcast:有序广播

有序广播的有序广播中的“有序”是针对广播接收者而言的,指的是发送出去的广播被BroadcastReceiver按照先后循序接收。有序广播的定义过程与普通广播无异,只是其的主要发送方式变为:sendOrderedBroadcast(intent, receiverPermission, ...)。

对于有序广播,其主要特点总结如下:

1>多个具当前已经注册且有效的BroadcastReceiver接收有序广播时,是按照先后顺序接收的,先后顺序判定标准遵循为:将当前系统中所有有效的动态注册和静态注册的BroadcastReceiver按照priority属性值从大到小排序,对于具有相同的priority的动态广播和静态广播,动态广播会排在前面。

2>先接收的BroadcastReceiver可以对此有序广播进行截断,使后面的BroadcastReceiver不再接收到此广播,也可以对广播进行修改,使后面的BroadcastReceiver接收到广播后解析得到错误的参数值。当然,一般情况下,不建议对有序广播进行此类操作,尤其是针对系统中的有序广播。

4)Sticky Broadcast:粘性广播(在 android 5.0/api 21中deprecated,不再推荐使用,相应的还有粘性有序广播,同样已经deprecated)。

既然已经deprecated,此处不再多做总结。

5)Local Broadcast:App应用内广播(此处的App应用以App应用进程为界)

由前文阐述可知,Android中的广播可以跨进程甚至跨App直接通信,且注册是exported对于有intent-filter的情况下默认值是true,由此将可能出现安全隐患如下:

1.其他App可能会针对性的发出与当前App intent-filter相匹配的广播,由此导致当前App不断接收到广播并处理;

2.其他App可以注册与当前App一致的intent-filter用于接收广播,获取广播具体信息。

无论哪种情形,这些安全隐患都确实是存在的。由此,最常见的增加安全性的方案是:

1.对于同一App内部发送和接收广播,将exported属性人为设置成false,使得非本App内部发出的此广播不被接收;

2.在广播发送和接收时,都增加上相应的permission,用于权限验证;

3.发送广播时,指定特定广播接收器所在的包名,具体是通过intent.setPackage(packageName)指定在,这样此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中。

App应用内广播可以理解成一种局部广播的形式,广播的发送者和接收者都同属于一个App。实际的业务需求中,App应用内广播确实可能需要用到。同时,之所以使用应用内广播时,而不是使用全局广播的形式,更多的考虑到的是Android广播机制中的安全性问题。

相比于全局广播,App应用内广播优势体现在:

1.安全性更高;

2.更加高效。

为此,Android v4兼容包中给出了封装好的LocalBroadcastManager类,用于统一处理App应用内的广播问题,使用方式上与通常的全局广播几乎相同,只是注册/取消注册广播接收器和发送广播时将主调context变成了LocalBroadcastManager的单一实例。

//registerReceiver(mBroadcastReceiver, intentFilter);

//注册应用内广播接收器

localBroadcastManager = LocalBroadcastManager.getInstance(this);

localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);

//unregisterReceiver(mBroadcastReceiver);

//取消注册应用内广播接收器

localBroadcastManager.unregisterReceiver(mBroadcastReceiver);

Intent intent = new Intent();

intent.setAction(BROADCAST_ACTION);

intent.putExtra("name", "qqyumidi");

//sendBroadcast(intent);

//发送应用内广播

localBroadcastManager.sendBroadcast(intent);

系统广播

//关闭或打开飞行模式时的广播

Intent.ACTION_AIRPLANE_M;

//充电状态,或者电池的电量发生变化;//电池的充电状态、电荷级别改变,不能通过组建声;

Intent.ACTION_BATTERY_CH;

//表示电池电量低

Intent.ACTION_BATTERY_LO;

//表示电池电量充足

Intent.ACTION_BATTERY_OK;

//关闭或打开飞行模式时的广播

Intent.ACTION_AIRPLANE_MODE_CHANGED;

//充电状态,或者电池的电量发生变化//电池的充电状态、电荷级别改变,不能通过组建声明接收这个广播,只有通过Context.registerReceiver()注册

Intent.ACTION_BATTERY_CHANGED;

//表示电池电量低

Intent.ACTION_BATTERY_LOW;

//表示电池电量充足,即从电池电量低变化到饱满时会发出广播

Intent.ACTION_BATTERY_OKAY;

//在系统启动完成后,这个动作被广播一次(只有一次)。

Intent.ACTION_BOOT_COMPLETED;

//按下照相时的拍照按键(硬件按键)时发出的广播

Intent.ACTION_CAMERA_BUTTON;

//当屏幕超时进行锁屏时,当用户按下电源按钮,长按或短按(不管有没跳出话框),进行锁屏时,android系统都会广播此Action消息

Intent.ACTION_CLOSE_SYSTEM_DIALOGS;

//设备当前设置被改变时发出的广播(包括的改变:界面语言,设备方向,等,请参考Configuration.java)

Intent.ACTION_CONFIGURATION_CHANGED;

//设备日期发生改变时会发出此广播

Intent.ACTION_DATE_CHANGED;

//设备内存不足时发出的广播,此广播只能由系统使用,其它APP不可用

Intent.ACTION_DEVICE_STORAGE_LOW;

//设备内存从不足到充足时发出的广播,此广播只能由系统使用,其它APP不可用

Intent.ACTION_DEVICE_STORAGE_OK;

//发出此广播的地方frameworks\base\services\java\com\android\server\DockObserver.java

Intent.ACTION_DOCK_EVENT;

//移动APP完成之后,发出的广播(移动是指:APP2SD)

Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE;

//正在移动APP时,发出的广播(移动是指:APP2SD)

Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;

//Gtalk已建立连接时发出的广播

Intent.ACTION_GTALK_SERVICE_CONNECTED;

//Gtalk已断开连接时发出的广播

Intent.ACTION_GTALK_SERVICE_DISCONNECTED;

//在耳机口上插入耳机时发出的广播

Intent.ACTION_HEADSET_PLUG;

//改变输入法时发出的广播

Intent.ACTION_INPUT_METHOD_CHANGED;

//设备当前区域设置已更改时发出的广播

Intent.ACTION_LOCALE_CHANGED;

//表示用户和包管理所承认的低内存状态通知应该开始。

Intent.ACTION_MANAGE_PACKAGE_STORAGE;

//未正确移除SD卡(正确移除SD卡的方法:设置--SD卡和设备内存--卸载SD卡),但已把SD卡取出来时发出的广播 ,扩展介质(扩展卡)已经从 SD 卡插槽拔出,但是挂载点 (mount point) 还没解除 (unmount)

Intent.ACTION_MEDIA_BAD_REMOVAL;

//按下"Media Button" 按键时发出的广播,假如有"Media Button" 按键的话(硬件按键)

Intent.ACTION_MEDIA_BUTTON;

//插入外部储存装置,比如SD卡时,系统会检验SD卡,此时发出的广播?

Intent.ACTION_MEDIA_CHECKING;

//已拔掉外部大容量储存设备发出的广播(比如SD卡,或移动硬盘),不管有没有正确卸载都会发出此广播, 用户想要移除扩展介质(拔掉扩展卡)。

Intent.ACTION_MEDIA_EJECT;

//插入SD卡并且已正确安装(识别)时发出的广播, 扩展介质被插入,而且已经被挂载。

Intent.ACTION_MEDIA_MOUNTED;

//拓展介质存在,但使用不兼容FS(或为空)的路径安装点检查介质包含在Intent.mData领域。

Intent.ACTION_MEDIA_NOFS;

//外部储存设备已被移除,不管有没正确卸载,都会发出此广播, 扩展介质被移除。

Intent.ACTION_MEDIA_REMOVED;

//广播:已经扫描完介质的一个目录

Intent.ACTION_MEDIA_SCANNER_FINISHED;

//请求媒体扫描仪扫描文件并将其添加到媒体数据库。

Intent.ACTION_MEDIA_SCANNER_SCAN_FILE;

//广播:开始扫描介质的一个目录

Intent.ACTION_MEDIA_SCANNER_STARTED;

// 广播:扩展介质的挂载被解除 (unmount),因为它已经作为 USB 大容量存储被共享。

Intent.ACTION_MEDIA_SHARED;

Intent.ACTION_MEDIA_UNMOUNTABLE;//

// 广播:扩展介质存在,但是还没有被挂载 (mount)

Intent.ACTION_MEDIA_UNMOUNTED

Intent.ACTION_NEW_OUTGOING_CALL;

//成功的安装APK之后//广播:设备上新安装了一个应用程序包。//一个新应用包已经安装在设备上,数据包括包名(最新安装的包程序不能接收到这个广播)

Intent.ACTION_PACKAGE_ADDED;

//一个已存在的应用程序包已经改变,包括包名

Intent.ACTION_PACKAGE_CHANGED;

//清除一个应用程序的数据时发出的广播(在设置--应用管理--选中某个应用,之后点清除数据时?)//用户已经清除一个包的数据,包括包名(清除包程序不能接收到这个广播)

Intent.ACTION_PACKAGE_DATA_CLEARED;

//触发一个下载并且完成安装时发出的广播,比如在电子市场里下载应用?

Intent.ACTION_PACKAGE_INSTALL;

//成功的删除某个APK之后发出的广播, 一个已存在的应用程序包已经从设备上移除,包括包名(正在被安装的包程序不能接收到这个广播)

Intent.ACTION_PACKAGE_REMOVED;

//替换一个现有的安装包时发出的广播(不管现在安装的APP比之前的新还是旧,都会发出此广播?)

Intent.ACTION_PACKAGE_REPLACED;

//用户重新开始一个包,包的所有进程将被杀死,所有与其联系的运行时间状态应该被移除,包括包名(重新开始包程序不能接收到这个广播)

Intent.ACTION_PACKAGE_RESTARTED;

//插上外部电源时发出的广播

Intent.ACTION_POWER_CONNECTED;

//已断开外部电源连接时发出的广播

Intent.ACTION_POWER_DISCONNECTED;

Intent.ACTION_PROVIDER_CHANGED;//

//重启设备时的广播

Intent.ACTION_REBOOT;

//屏幕被关闭之后的广播

Intent.ACTION_SCREEN_OFF;

//屏幕被打开之后的广播

Intent.ACTION_SCREEN_ON;

//关闭系统时发出的广播

Intent.ACTION_SHUTDOWN;

//时区发生改变时发出的广播

Intent.ACTION_TIMEZONE_CHANGED;

//时间被设置时发出的广播

Intent.ACTION_TIME_CHANGED;

//广播:当前时间已经变化(正常的时间流逝), 当前时间改变,每分钟都发送,不能通过组件声明来接收

,只有通过Context.registerReceiver()方法来注册

Intent.ACTION_TIME_TICK;

//一个用户ID已经从系统中移除发出的广播

Intent.ACTION_UID_REMOVED;

//设备已进入USB大容量储存状态时发出的广播?

Intent.ACTION_UMS_CONNECTED;

//设备已从USB大容量储存状态转为正常状态时发出的广播?

Intent.ACTION_UMS_DISCONNECTED;

Intent.ACTION_USER_PRESENT;//

//设备墙纸已改变时发出的广播

Intent.ACTION_WALLPAPER_CHANGED;

短信监听器

1、写一个广播类

2、注册

 <receiver android:name="com.bwf.a70.MyBroadcastReceiver">

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

        </receiver>

3、加权限

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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u010845516/article/details/122552596

智能推荐

国内计算机论文期刊,国内都有哪些计算机领域的投稿期刊-程序员宅基地

文章浏览阅读1.2k次。国内都有哪些计算机领域的投稿期刊发布时间:2019-01-14 15:11浏览: 次计算机在各行各业都得到了广泛的应用,而这一方向的从业人员也越来越多,他们也是可以评定计算机工程师职称的,但也需要发表计算机方向的论文,最近就有作者咨询我们的老师,关于国内计算机领域的投稿期刊,小编在此介绍:计算机专业领域的刊物有很多,也分计算机在各行各业都得到了广泛的应用,而这一方向的从业人员也越来越多,他们也是可..._计算机专业普刊

计算机设备管理使用实施细则,办公电脑及相关设备管理工作细则.doc-程序员宅基地

文章浏览阅读286次。乌蒙科技制度编号:E3055KY制度页数:共12页办公电脑及相关设备管理细则编 制 人:审 核 人:批 准 人:主办单位:总经理室公布日期:20XX年12月30日生效日期:20XX年 1 月 1日第一章 总 则目标为规范办公电脑及相关设备使用、维护、维修,依据集团[办公电脑及相关设备管理措施]之要求制订本细则。适用范围本细则适适用于矿业本部及所属子企业办公电脑及相关设备管理。办公电脑及相关设备分...

python数据结构与算法分析_Python数据结构与算法--算法分析-程序员宅基地

文章浏览阅读202次。在计算机科学中,算法分析(Analysis of algorithm)是分析执行一个给定算法需要消耗的计算资源数量(例如计算时间,存储器使用等)的过程。算法的效率或复杂度在理论上表示为一个函数。其定义域是输入数据的长度,值域通常是执行步骤数量(时间复杂度)或者存储器位置数量(空间复杂度)。算法分析是计算复杂度理论的重要组成部分。一个有趣的问题经常出现,那就是两个看似不同的程序,到底哪个更好呢?要回..._energy+=list1[a]*list1[a-1]*list1[(a+1)%(n-i)]

linux6.4发送日志,RHEL6.4 搭建 Rsyslog 日志服务 Rsyslog+MySQL+Loganalyzer-程序员宅基地

文章浏览阅读67次。rsyslog 建立:安装rsyslog服务包,rsyslog-mysql的rpm包需要装上去,是日志和数据库结合的包配置/etc/rsyslog.conf文件vi/etc/rsyslog.confSYSLOGD_OPTIONS="-c2-r-x-m180" ##添加,KLOGD_OPTIONS="-x" ##添加,$ModLoadimm...

android的drawrect透明图层,android – 在活动上创建一个黑色透明的图层-程序员宅基地

文章浏览阅读279次。以编程方式,您可以使用Canvas创建图层.用你的颜色填充整个东西并切出一个洞.public class DrawView extends View {Paint paint = new Paint();Paint transparentPaint = new Paint;public DrawView(Context context) {super(context);}@Overridepubl..._canvas drawrect 全透明

NLP练习之RNN,使用pytorch_pytorch nlp 例子“”-程序员宅基地

文章浏览阅读251次。import numpy as npimport torchimport torch.nn as nnimport torch.optim as optimfrom torch.autograd import Variabledtype = torch.FloatTensorsentences = [ "i like dog", "i love coffee", "i hate milk"]word_list = " ".join(sentences).split()word_list_pytorch nlp 例子“”

随便推点

linux smartctl 命令,Smartctl 命令查看硬盘详细信息-程序员宅基地

文章浏览阅读6.1k次。Smartctl命令查看硬盘详细信息(2011-08-30 14:21:41)标签:linux硬盘信息使用时间杂谈1.1什么是Smartmontools?Smartmontools是一种硬盘检测工具,通过控制和管理硬盘的SMART(Self Monitoring Analysis andReportingTechnology,自动检测分析及报告技术)技术来实现的,SMART技术可以对硬盘的磁头单..._smartctl查看硬盘信息

压力传感器实例编程与java,如何使用Arduino进行编程 通通过压力传感器控制电机转速...-程序员宅基地

文章浏览阅读804次。/** circuits4you.com* 2016 November 25* Load Cell HX711 Module Interface with Arduino to measure weight in KgsArduinopin2 -> HX711 CLK3 -> DOUT5V -> VCCGND -> GNDMost any pin on the Arduin...

python 数据恢复 编程_Python | 数据恢复实验室 Data Recovery Laboratory-程序员宅基地

文章浏览阅读1.1k次。最近使用Python为项目开发一款绘图工具(绘出 声场三维模型)。因为希望能把Python脚本发布为脱离Python平台运行的可执行程序,比如单个的exe文件。PyInstaller恰满足这个需求。本文PyInstaller的版本是2.0,支持Python2.7。下面讨论怎样安装,使用PyInstaller。PyInstaller本身并不属于Python包。在安装 pyinstaller 之前假设..._python恢复硬盘数据 csdn

windows服务器上无法运行bat文件,ad域用户bat脚本运行不了-程序员宅基地

文章浏览阅读1.8k次。发表于2017-2-22 10:20|来自51CTO网页引用:原帖由 wankily 于 2017-2-22 08:33 发表 域环境是server2008,做了一个bat脚本,内容很简单,echo %date%,%username%,%COMPUTERNAME% >>\\192.168.10.1\tools$\pc-imformation-collect.txt,就是收集一下域..._windows sever .bat文件无法运行

既然android service是运行在主线程中的,那service还有什么用?_每个线程都有一个messagequeue-程序员宅基地

文章浏览阅读4.9k次,点赞2次,收藏6次。既然android service是运行在主线程中的,那service还有什么用?对于Android,每一个进程都有一个主线程,四大组件的处理任务都是在这个线程中进行的。每个线程都有一个MessageQueue,里面用于存放Message,四大组件的处理工作是用Message来封装的。可以说Android应用层是消息驱动的。你的想法可能是,Service长期在后台工作,如果它是运行在主线程中的..._每个线程都有一个messagequeue

关于HTML5你需要了解的基础知识-程序员宅基地

文章浏览阅读75次。HTML5 是第五个且是当前的 HTML 版本,它是用于在万维网上构建和呈现内容的标记语言。本文将帮助读者了解它。HTML5 通过 W3C 和Web 超文本应用技术工作组Web Hypertext Application Technology Working Group之间的合作发展起来。它是一个更高版本的 HTML,它的许多新元素可以使你的页...