一、广播机制简介

  Android提供了一套完整的API,允许应用程序自由的发送和接受广播,发送广播借助于我们之前学过的:Intent,而接收广播需要借助于广播接收器(Broadcast Receiver)

  广播的类型主要分为两种:标准广播和有序广播。

  标准广播:一种完全异步执行的广播,在广播发出之后,所有接收器几乎在同一时刻接收到这条广播消息,因此它们之间没有任何的先后顺序可言,这种广播的效率会比较高,但是同时也意味着它无法被截断的。标准广播的工作流程图如图所示:

  有序广播:一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够接收到这条广播,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递,所以这种广播接收器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了。有序广播的工作流程如图所示:

二、接收系统广播

  Android内置了很多的系统级别的广播,我们可以在应用程序中提通过监听这些广播来得到各种系统的状态信息。比如手机开机、电池的电量、时间或时区发生改变等情况下发出一条广播,要接受这些广播,就需要使用广播接收器。

  广播接收器可以自由的对自己感兴趣的广播进行注册,注册广播的方式一般有两种,在代码中注册称为动态注册,在AndroidManifest.xml中注册称为静态注册。

2.1  动态注册监听网络变化

第一步:声明网络权限。Android系统为了保护用户设备的安全和隐私,做了严格的规定:如果程序需要进行一些对用户来说比较敏感的操纵,就必须在配置文件中声明权限才可以,否则程序将会直接崩溃。这里访问的是系统的网络状态,所以需要进行以下权限声明。

第二步:

在MainActivity活动中创建广播接收器,并进行注册

第三步:运行程序,会弹出:network is available的提示(左),接着点击Home键,不要点击Back键,回到主界面后,进入设置,打开手机的飞行模式,会弹出:network is unavailable(右)

     

 2.2  静态注册广播接收器

  动态注册的广播接收器可以自由的控制注册与注销,在灵活性方面有很大的优势,但是它有一个缺点,就是必须要在程序启动之后才能接收到广播,因为注册的逻辑是写在onCreate()方法中的。为了让程序在未启动的情况下就能收到广播,就需要使用到静态注册方式了。

第一步:先创建一个广播接收器BroadCompleteReceiver,New--->Other--->Broadcast Receiver.

  Exported:表示是否允许这个广播接收器接收本程序以外的广播

  Enabled:表示是否启用这个广播接收器。

第二步:在创建的广播接收器中设置一个Toast显示,表示当这个广播接收器接收到消息后弹出一个提示信息。

第三步:在AndroidManifest.xml中对创建的广播接收器添加想要监听的action,并进行权限声明,注意:我们在创建BroadCompleteReceiver广播接收器的时候,系统就已经自动在AndroidManifest.xml中注册了。

  Android系统启动完成后会发出一条值为:android.intent.action.BOOT_COMPLETED  的广播,因此我们在<Intent-filter>标签中添加相应的action。然后使用<user-permission>标签中又添加一条:android.permission.RECEIVE_BOOT_COMPLETED权限。

第四步:关闭模拟器再打开,就会收到一个开机广播

三、发送自定义广播

  前面我们提到广播有两种类型:标准广播和有序广播

3.1  发送标准广播

第一步:创建一个自定义广播接收器,用于接收到广播后执行的操作

第二步:在AndroidManifest.xml中注册:MyReceiver广播接收器(已自动注册),给发送的广播自定义一个值:

<action android:name="com.workspace.hh.broadcasttest.MY_RECEIVER"/>

第三步:在activity_main.xml中设置一个按钮,通过点击按钮来发送自定义的广播

第四步:在MainActivity的:onCreate()方法中为按钮设置监听事件:

  发送广播时,先创建一个Intent对象,把需要发送的广播的值传入,然后调用:context的sendBroadcast()方法,把广播发送出去。这样所有监听:com.workspace.hh.broadcasttest.MY_RECEICER 这条广播的广播接收器就会收到消息。

第五步:运行程序,点击按钮发送广播

3.2  广播跨进程通信

   广播时一种可以跨进程的通信方式,因此我们在应用程序内发出的广播,在其他应用程序也能收到,下面我们就来看一下效果:

第一步:新建一个项目:BroadcastTest2,并自定义一个广播接收器:AnotherBroadcastReceiver,然后在AndroidManifest.xml中添加要监听的广播的值:com.workspace.hh.broadcasttest.MY_RECEIVER

第二步:运行项目BroadcastTest2,然后在BroadcastTest项目程序中点击按钮,可以看到先后弹出来两个提示信息,这说明两个应用程序都接收到了广播

    

3.3  发送有序广播

  发送有序只需要修改一个地方就行了:将:sendBroadcast()改为:sendOrderedBroadcast().

  sendOrderedBroadcast()方法接收两个参数:一个是Intent,另一个是与权限相关的字符串,这里传入null就行了。

  修改这个地方过后,虽然发送的广播已经是有序广播了,但是效果还是与标准广播一样会弹出两个提示信息,下面我们来通过截断广播看效果:

第一步:给:MyReceiver广播接收器设置优先级,使得:MyReceiver比其他广播接收器先接收到广播,在AndroidManifest.xml中通过:android:priority  属性给广播接收器设置优先级

第二步:在MyReceiver广播接收器中截断广播,及后面的接收器就接收不到广播了,在Toast提示信息下面添加:abortBroadcast()方法,该方法表示在此截断广播,后面的广播接收器就再也接收不到该广播了。

第四步:重新运行BroadcastTest和BroadcastTest2这两个程序,然后点击BroadcastTest程序中的按钮,我们看到只有一条提示信息弹出来:received in myReceiver

四、 使用本地广播

  前面我们发送和接收的广播都是属于系统全局广播,即发出的广播可以被其他应用程序接收到,并且我们也可以接收来自于其他应用程序的广播。这样就很容易引起安全性问题,比如说

我们发送的一些携带关键性数据的广播有可能被其他应用程序截获,或者其他应用程序不停的向我们的广播接收器发送各种垃圾广播。

  为了解决广播的安全性问题,Android提供了一套本地的广播机制,使用这个机制发出的广播只能在应用程序的内部传递,并且广播接收器也只能接收来自本应用程序发出的广播,这样所有的安全性问题就不存在了。

第一步:修改MainActivity活动中的代码:

第二步:运行程序,点击按钮,就会弹出:received local Broadcast  的提示信息。如果我们在BroadcastTest2这个应用程序中也去接收这条广播,很明显是接收不到的,因为这条广播只在BroadcastTest程序中传播。

本地广播的注意事项:

  本地广播是无法通过静态注册的方式来接收的,因为静态注册主要是为了让程序在未启动的情况下也能接收到广播,而发送本地广播时,我们的程序肯定是已经启动了,因此完全不需要使用静态注册的功能。

本地广播的几点优势:

  1、可以明确地知道正在发送的广播不会离开我们的应用程序,因此不必担心机密数据泄漏

  2、其他程序无法将广播发送到我们程序的内部,因此不需要担心会有安全漏洞的隐患

  3、发送本地广播比发送系统全局广播将会更加高效

Android学习之基础知识八—Android广播机制的更多相关文章

  1. Android学习之基础知识八—Android广播机制实践(实现强制下线功能)

    强制下线功能算是比较常见的了,很多的应用程序都具备这个功能,比如你的QQ号在别处登录了,就会将你强制挤下线.实现强制下线功能的思路比较简单,只需要在界面上弹出一个对话框,让用户无法进行任何操作,必须要 ...

  2. Android学习之基础知识五—Android常用的七大控件

    一.TextView控件:在界面上显示一段文本信息 先看XML代码和执行效果:         代码分析: 1.android:id属性,给当前控件定义了一个唯一的标识符 2.android:layo ...

  3. Android学习之基础知识六—Android四种布局详解

    一.Android基本布局 布局是一种可以放置多个控件的容器,它可以按照一定规律调整内部控件的位置,而且布局内部除了可以放置控件外,还可以放置布局,实现多层布局嵌套.布局和控件.布局和布局之间的关系如 ...

  4. Android学习之基础知识十四 — Android特色开发之基于位置的服务

    一.基于位置的服务简介 LBS:基于位置的服务.随着移动互联网的兴起,这个技术在最近的几年里十分火爆.其实它本身并不是什么时髦的技术,主要的工作原理就是利用无线电通讯网络或GPS等定位方式来确定出移动 ...

  5. Android学习之基础知识十六 — Android开发高级技巧的掌握

    一.全局获取Context的技巧 前面我们很多地方都使用到了Context,弹出Toast的时候.启动活动的时候.发送广播的时候.操作数据库的时候.使用通知的时候等等.或许目前来说我们并没有为得不到C ...

  6. Android学习之基础知识十三 — 四大组件之服务详解第一讲

    一.服务是什么 服务(Service)是Android中实现程序后台运行的解决方案,它非常适合去执行那些不需要和用户交互而且还要求长期运行的任务.服务的运行不依赖于任何用户界面,即使程序被切换到后台, ...

  7. Android学习之基础知识五—ListView控件(最常用和最难用的控件)

    ListView控件允许用户通过上下滑动来将屏幕外的数据拉到屏幕内,把屏幕内的数据拉到屏幕外. 一.ListView的简单用法第一步:先创建一个ListViewTest项目,在activity_mia ...

  8. Android学习之基础知识四-Activity活动6讲(体验Activity的生命周期)

    一.体验活动的生命周期的执行 代码组成: 1.三个Java类:MainActivity.java.NormalActivity.java.DialogActivity.java 2.三个布局文件:ac ...

  9. Android学习之基础知识四-Activity活动1讲

    一.活动(Activity)的基本用法: 1.手动创建活动FirstActivity(java源码): A.Android Studio在一个工作区间只允许打开一个项目,点击:File--->C ...

随机推荐

  1. 基于mave的dubbo分别架构

    开始前,先看一下demo项目工程结构: 1.抽离接口 dubbo-api工程,根据业务抽离接口,deploy到mave nexus. public interface TestService { /* ...

  2. 修改 this 指向

    封装函数 f,使 f 的 this 指向指定的对象 function bindThis(f, oTarget) { if(f.bind){ return f.bind(oTarget); }else{ ...

  3. 探讨PHP页面跳转几种实现技巧 转自# 作者:佚名 来源:百度博客 #

    Web系统中,从一个网页跳转到另一个网页,是LAMP项目中最常用的技术之一.页面跳转可能是由于用户单击链接.按钮等引发的,也可能是系统自动产生的. 此处介绍PHP中常用的实现页面自动跳转的方法. PH ...

  4. SSM 开发 Tars

    目录结构 tars生成的文件当成 controller 来调用 service ,service 调用 mapper POM 注意如果 mybatis是3.4.1 spring 是4.1.14的话, ...

  5. Flume组件汇总2

    Component Interface Type Alias Implementation Class org.apache.flume.Channel memory org.apache.flume ...

  6. iframe在iphone中滚动条无效

    在iphone(ios11)中(其他苹果设备未尝试),不论是在微信的浏览器中,还是在其他浏览器中,iframe的滚动条怎么设置都没有效果,页面内容都无法进行滚动; 解决方法: 将iframe包裹在di ...

  7. sleep和Sleep区别

    windows Sleep 单位是毫秒 linux sleep 单位是秒

  8. centos7搭建SVN+Apache+IF.svnadmin支持https实现web管理SVN

    阅读目录 1. 介绍 2. 软件准备 3. 建立SVN Server仓库 4. 配置安装PHP&IF.SVNadmin 5. 启动服务 1.介绍 公司最近想把Windows server平台的 ...

  9. 浅谈tidb事务与MySQL事务之间的区别

    MySQL是我们日常生活中常见的数据库,他的innodb存储引擎尤为常见,在事务方面使用的是扁平事务,即要么都执行,要么都回滚.而tidb数据库则使用的是分布式事务.两者都能保证数据的高一致性,但是在 ...

  10. U890采购入库单修改供应商

    采购入库单表头 SELECT *FROM RdRecordWHERE (cCode = '0000051801') 采购入库单表体 SELECT *FROM RdRecordsWHERE (cPOID ...