在前边几篇关于Android系统两个重要组件的介绍中,界面Activity负责应用程序与用户的交互,服务Service负责应用程序内部线程间的交互或两个应用程序进程之间的数据交互。看上去这两大组件就能满足日常应用程序的开发需求了,可是应用程序之间的交互,如果都使用服务Service中的AIDL规范,那每个应用程序本身岂不是要声明其他应用程序中的一些接口?这对两个属于不同开发者的应用程序来说很不友好。所以Android系统还提供了称为广播接收者BoradcastReceiver的组件,采用广播机制,以在两个或多个未知应用程序间传递并处理通知。

Android系统的广播机制,作为进程间通信的一种方式,同样可分为通信消息内容、发送方、接收方三个方面。而广播接收者BroadcastReceiver组件,只是在接收方所使用的。为了更好的理解广播接收者的使用方式,下面将按照进程间通信的三个方面分别介绍。

完整的通信消息内容

与界面Activity或者服务Service类似,广播间的通信消息内容也是以android.content.Intent意图对象封装起来的数据。在界面间交互中有对Intent对象的使用说明。

随意的广播发送方

只要在任何有上下文环境android.content.Context对象的地方,都可以调用该对象的sendBroadcast()系列方法发送一条广播,其使用方式也与启动界面的startActivity()系列方法或启动服务的startService()系列方法类似。

最常用的context.sendBroadcast(Intent intent)方法,可以发送一条随机通知,在已经注册的与其对应的广播接收者中会收到当前通知发送的 intent 内容。这里如果有多个对应的广播接收者,将会以随机顺序接收当前消息内容。 其中 intent 参数就是对通信的消息内容封装的实例化对象,其中必须调用intent.setAction(String action)方法设置要发送广播的唯一标识行为,此处的 action 必须是系统内的唯一字符串,以此作为接收该广播的标志,在下文的广播接收者中同样声明相同字符串的 action 来接收当前广播内容。

也可以使用context.sendOrderedBroadcast (Intent intent, String receiverPermission)方法,发送一条按顺序接收的通知,同样在已经注册的与其对应的广播接收者中收到消息内容,只不过当有多个对应的广播接收者时,将会按照广播接收者在注册时的优先之 priority 属性值的从大到小的顺序依次接收,只有当两个广播接收者有相同大小的 priority 时才会随机顺序接收消息内容。由于多个广播接收者们是按顺序接收的广播,所以可以在其中某个广播接收者中调用abortBroadcast()中断当前广播,使其不会继续向后面的广播接收者传递。

另外,在官方推荐的androidx库中,可以借助androidx.localbroadcastmanager.content.LocalBroadcastManager本地广播管理类,调用LocalBroadcastManager.getInstance(Context context).sendBroadcast(Intent intent)系列方法,发送一条只在当前应用程序进程中接收的广播。这种广播只是在同一个进程中使用,避免了多个进程间接收的冗余冲突。

Android系统已经提供了一些 action 值标记的广播,在一些常用的系统操作之后会发送广播以通知其他应用程序。这些系统广播以静态常量的形式定义在android.content.Intent类中。例如当用户修改飞行模式状态时,系统会发送Intent.ACTION_AIRPLANE_MODE_CHANGED值作为 action 的广播;当用户点亮屏幕时,系统会发送Intent.ACTION_SCREEN_ON值作为 action 的广播;当有新的应用程序被安装后,系统会发送Intent.ACTION_PACKAGE_ADDED值作为 action 的广播 。。。

自定义的广播接收者

作为广播消息接收并处理的主要组件,广播接收者必须继承自android.content.BroadcastReceiver类,同时实现该类的抽象方法onReceive (Context context, Intent intent)。在onReceive()方法中接收广播消息,其中的参数 context 是当前广播接收者所在的上下文环境,参数 intent 则是接收到的广播消息的内容。

与界面Activity和服务Service的回调方法一样,广播接收者BroadcastReceiver中的onReceive()方法同样是在系统UI主线程中被调用,因此该方法中同样不能执行耗时操作。

如果其他应用程序所在进程每发送一条广播都回调广播接收者的onReceive()方法,对每一个广播接收者来说都是繁琐的处理过程。所以发送的广播 intent 中指定的 action 参数必须指定唯一标志值,只有已经注册过该 action 的广播接收者,才会回调onReceive()方法。

在应用程序的目标版本为Android 8.0即API为26以前,广播接收者的注册方式有静态注册和动态注册两种,而从Android 8.0版本开始,除部分例外的广播行为外,都只能采取动态注册一种方式。

静态注册

广播接收者BroadcastReceiver的静态注册方式与界面Activity、服务Service的注册方式类似,都是需要在清单文件的<application></application>标签中声明当前组件信息。

广播接收者的声明使用<receiver></receiver>标签,在标签下有android:name属性绑定自定义的广播接收者.

而在<receiver></receiver>标签里边,同样可以使用<intent-filter></intent-filter>标签作为意图过滤。

在意图过滤标签中嵌入<action android:name=""/>标签以标记当前广播接收者所绑定的系统唯一的 action 属性值,该<action />标签可以有多个,只要发送的 action 参数中有一个与其对应,就会调用当前广播接收者的onReceiver()方法。

对于静态注册的广播接收者,系统在应用程序安装之后就遍历其注册的广播 action 值,从而当其他应用程序发送对应 action 的广播后,与之匹配,若匹配一致,则创建该广播接收者的实例化对象,之后再调用广播接收者的onReceiver()方法,该方法执行结束后,当前的广播接收者对象也就被销毁了。当其他应用程序再次发送对应的广播后,同样要再次创建新的广播接收者的实例化对象并调用其onReceiver()方法。这是广播接收者BroadcastReceiver与其他组件所不同的地方。

动态注册

对于动态注册的广播接收者BroadcastReceiver,可以在有上下文环境Context对象的地方,通常是在界面Activity或服务Service中注册的。

首先要调用自定义广播接收者BroadcastReceiver的构造方法创建其实例化对象。

其次还要借助android.content.IntentFilter意图过滤类创建其实例化对象。

通过IntentFilter类的一参构造方法或该对象的setAction(String action)方法,可以设置其 action 参数。

在需要注册的位置,调用上下文环境Context对象的registerReceiver(BroadcastReceiver receiver, IntentFilter filter)系列方法,可以将创建的自定义广播接收者BroadcastReceiver与设置了 action 参数的IntentFilter对象绑定注册。在该注册逻辑之后,其他进程发送的 action 广播,才能在绑定的自定义广播接收者中接收并调用其onReceiver()方法。

在于注册位置同级下不需要在处理接收广播的位置,需要解除注册,以降低系统消耗,调用上下文环境Context对象的unregisterReceiver(BroadcastReceiver receiver)方法,传入之前注册过的BroadcastReceiver对象即可。

对于动态注册的广播接收者,通常需要在组件配对的生命周期方法中注册与解除注册,因此其生命周期也必然要小于注册所在的组件。


Android系统提供的广播机制,只需要知道广播的 action 属性值,就可以发送或处理该条广播。这不仅在不同进程之间,在同一个进程内使用也很方便,但是官方建议不要滥用广播接收者,否则会导致系统变慢。一般开发过程中常用以创建系统广播的广播接收者BroadcastReceiver为主,辅助以自定义广播的广播接收者BroadcastReceiver在进程间使用。

Android系统编程入门系列之广播接收者BroadcastReceiver实现进程间通信的更多相关文章

  1. Android系统编程入门系列之服务Service中的进程间通信

    在上篇文章以线程间的通信方式Handler类结尾,服务Service还支持的进程间通信,又是具体怎么实现的呢?这就要用到加载服务一文中提到的AIDL语言规范了. AIDL是 Android Inter ...

  2. Android系统编程入门系列之加载界面Activity

    上回说到应用初始化加载及其生命周期,在Android系统调用Applicaiton.onCreate()之后,继续创建并加载清单文件中注册的首个界面即主Activity,也可称之为入口界面.主Acti ...

  3. Android系统编程入门系列之应用环境及开发环境介绍

        作为移动端操作系统,目前最新的Android 11.0已经发展的比较完善了,现在也到了系统的整理一番的时间,接下来的系列文章将以Android开发者为中心,争取用归纳总结的态度对初级入门者所应 ...

  4. Android系统编程入门系列之应用间数据共享ContentProvider

    内容提供者ContentProvider与前文的界面Activity.服务Service.广播接收者BroadcastReveiver,并列称为Android的四大组件,均是需要自定义子类继承上述组件 ...

  5. Android系统编程入门系列之硬件交互——通信硬件Bluetooth

    通信硬件NFC的文章,虽然可以在Android系统中通过非直接接触的形式与支持NFC硬件的设备通信,但是也只能交互一些简短的标签内容,对大量的持续性数据,却并不能很好的支持.因此针对这个弊端,可以考虑 ...

  6. Android系统编程入门系列之硬件交互——无线通信WLAN

    Android系统的移动设备大多支持无线WLAN技术.利用该技术,不仅能实现互联网通信,还能实现无线定位,热点共享等远程通信功能.针对使用WLAN的不同功能,可能需要分别申请不同的权限声明,同时调用不 ...

  7. Android系统编程入门系列之应用初始化Application

    在上一篇文章中我们了解到Android系统启动应用的时候,会首先加载AndroidManifest.xml清单文件中的一系列信息,在清单文件中如果不指定<application></ ...

  8. Android系统编程入门系列之清单文件

    在上一篇文章中已经提到,Android系统加载应用程序之后,首先会读取该应用程序的AndroidManifest.xml清单文件,之后根据该清单文件加载后边的东西.所以要开发应用程序,自然要先知道清单 ...

  9. Android系统编程入门系列之界面Activity绘制展示

    上篇文章介绍了界面Activity的启动方式和生命周期,本篇将继续介绍在界面Activity中的内容是如何绘制展示给用户的. 在Android系统上运行新创建的界面Activtiy,给用户展示的是空白 ...

随机推荐

  1. 「CF85E」 Guard Towers

    「CF85E」 Guard Towers 模拟赛考了这题的加强版 然后我因为初值问题直接炸飞 题目大意: 给你二维平面上的 \(n\) 个整点,你需要将它们平均分成两组,使得每组内任意两点间的曼哈顿距 ...

  2. Linux云计算-07_Linux文件服务器之vsftpd服务器

    本章向读者介绍企业vsftpd服务器实战.匿名用户访问.系统用户访问及虚拟用户实战等. 1 vsftpd服务器企业实战 文件传输协议(File Transfer Protocol,FTP),基于该协议 ...

  3. C语言:字符编码

    C语言是 70 年代的产物,那个时候只有 ASCII,各个国家的字符编码都还未成熟,所以C语言不可能从底层支持 GB2312.GBK.Big5.Shift-JIS 等国家编码,也不可能支持 Unico ...

  4. M1卡分类

    M1卡复制前文说到,每一张M1卡的0扇区0块都是出厂时厂商赋予的绝对地址块,我们无法在M1卡内直接修改它. 说到这不得不提一下M1卡的复制子卡--UID卡,FUID卡,CUID卡. UID卡UID卡是 ...

  5. VisualEffectGraph基础操作 --创建VEG项目步骤讲解

    一:建立VEG项目步骤 首先打开Unity Hub,  使用unity2020.1 新建项目(本技术博客,默认使用unity2020.1 版本演示),选择HDRP 高清渲染管线,确定项目目录与名称. ...

  6. hapv-一个可以播放,下载国内主流视频的播放器

    electron 开发的一个可以播放,下载国内主流视频的播放器.A player developed by electron that can play and download domestic m ...

  7. ArrayList 深入浅出

    ArrayList 特点:按添加顺序排列.可重复.非线程安全: 底层实现:数组 扩容原理:初始化集合时,默认容量为 0,第一次添加元素时扩容为 10,容量不够时扩容为原来容量的 1.5 倍. 这里扩容 ...

  8. robotframework - PO设计

    1.添加新建好的资源 2.测试用例原始代码如下(未做任何分离的数据) *** Settings ***Library SeleniumLibraryResource UI分层一.txtResource ...

  9. 微信小程序云开发-数据库表创建和操作

    一.新建云数据库 进入[云开发]界面,点击[数据库]>添加>创建集合>确定. 二.向数据库中添加数据 选中[数据库],点击[添加记录],向数据库中添加记录 添加[字段]和[值],并选 ...

  10. odoo中Controller

    一:Controller 一般通过继承的形式来创建controller类,继承自odoo.http.Controller. 以route装饰器来装饰定义的方法,提供url路由访问路径: class M ...