文章目录

  • 五 广播 (Broadcasts)
    • 5.1 广播的应用(通信)
    • 5.2 常用广播事件
    • 5.3 广播分类
    • 5.4 动态注册广播
      • 5.6.1 ConnectivityManager
      • 5.6.2 自定义广播
      • 5.6.3 授权与测试
    • 5.5 静态注册广播
    • 5.6 自定义广播
    • 5.7 使用本地广播

五 广播 (Broadcasts)

学习过Java的观察者模式,对于这一块可能好理解一点

5.1 广播的应用(通信)

  • 同一app内部的同一组件内的消息通信(单个或多个线程之间)
  • 同一app内部的不同组件之间的消息通信(单个进程)
  • 同一app具有多个进程的不同组件之间的消息通信
  • 不同app之间的组件之间消息通信
  • Android系统在特定情况下与App之间的消息通信

5.2 常用广播事件

  • Intent.ACTION_AIRPLANE_MODE_CHANGED:关闭或打开飞行模式时的广播
  • Intent.ACTION_BATTERY_CHANGED:充电状态,或者电池的电量发生变化
  • Intent.ACTION_BATTERY_LOW:表示电池电量低
  • Intent.ACTION_BATTERY_OKAY:表示电池电量充足,即从电池电量低变化到饱满时会发出广播
  • Intent.ACTION_BOOT_COMPLETED:在系统启动完成后,这个动作被广播一次(只有一次)
  • Intent.ACTION_CAMERA_BUTTON:按下照相时的拍照按键(硬件按键)时发出的广播
  • Intent.ACTION_CLOSE_SYSTEM_DIALOGS:当屏幕超时进行锁屏时,当用户按下电源按钮,长按或短按(不管有没跳出话框),进行锁屏时,android系统都会广播此Action消息
  • Intent.ACTION_HEADSET_PLUG:在耳机口上插入耳机时发出的广播
  • ntent.ACTION_PACKAGE_ADDED:成功的安装APK之后
  • Intent.ACTION_PACKAGE_INSTALL:触发一个下载并且完成安装时发出的广播,比如在电子市场里下载应用?
  • Intent.ACTION_PACKAGE_REMOVED:成功的删除某个APK之后发出的广播

5.3 广播分类

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

  • 标准广播:是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序可言。这种广播的效率会比较高,
  • **有序广播:**则是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。当然我们可以设置广播的优先级,优先执行某广播

5.4 动态注册广播

实现案例:完成对网络状态的监听,监听当前网络处于什么状态。

5.6.1 ConnectivityManager

ConnectivityManager是网络连接相关的管理器,它主要用于查询网络状态并在网络发生改变时发出状态变化通知。这个类主要负责的下列四个方面:

 1.  监控网络状态(包括WiFi, GPRS, UMTS等)。2.  当网络连接改变时发送广播Intent。3.  当一种网络断开时,试图连接到另一种网络进行故障处理。4.  提供一系列接口让应用程序查询可获得的网络的粗粒度和细粒度状态。

重要的类常量

  • TYPE_BLUETOOTH The Bluetooth data connection. 蓝牙数据连接
  • TYPE_ETHERNET The Ethernet data connection. 以太网数据连接
  • TYPE_MOBILE The Mobile data connection. 移动数据链接
  • TYPE_WIFI The WIFI data connection. wifi链接
  • CONNECTIVITY_ACTION 网络连接发生改变
  • iDEFAULT_NETWORK_PREFERENCE 默认网络连接偏好,建议在config.xml中进行配置.并通过调用 getNetworkPreference() 获取应用的当前设置值。
  • EXTRA_EXTRA_INFO The lookup key for a string that provides optionally supplied extra information about the network state.
  • EXTRA_NETWORK_INFO 建议使用getActiveNetworkInfo() or getAllNetworkInfo()获取网络连接信息
  • EXTRA_NETWORK_TYPE 触发 CONNECTIVITY_ACTION广播的网络类型

重要的方法

  • getActiveNetworkInfo() 获取当前连接可用的网络
  • getAllNetworkInfo() 获取设备支持的所有网络类型的链接状态信息。
  • getNetworkInfo(int networkType) 获取特定网络类型的链接状态信息
  • getNetworkPreference() 获取当前偏好的网络类型。
  • isActiveNetworkMetered()
  • isNetworkTypeValid(int networkType) 判断给定的数值是否表示一种网络

5.6.2 自定义广播

package com.shu.Utils;import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;import java.io.IOException;/*** @author shu* @date 2022/3/28* @description 网络变化工具类
/*tag:获取并判断网络状态*/
public class NetUtil {private static final int NETWORK_NONE = -1;// 没有连网private static final int NETWORK_MOBILE = 0;// 移动网络private static final int NETWORK_WIFI = 1;// 无线网络public static int getNetWorkState(Context context) {// 获取连接管理器对象ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);//获取额外的网络信息NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();//判断网络处于连接状态if (activeNetworkInfo != null && activeNetworkInfo.isConnected()) {//获取网络的类型if (activeNetworkInfo.getType() == (ConnectivityManager.TYPE_WIFI)) {Log.i("通知" , "当前网络处于WiFi状态");//是否可上网return NETWORK_WIFI;} else if (activeNetworkInfo.getType() == (ConnectivityManager.TYPE_MOBILE)) {Log.i("通知" , "当前网络处于移动网状态");return NETWORK_MOBILE;}} else {return NETWORK_NONE;}return NETWORK_NONE;}//判断当前网络是否能连同外网public static boolean isNetworkOnline() {Runtime runtime = Runtime.getRuntime();try {Process ipProcess = runtime.exec("ping -c 3 www.baidu.com");int exitValue = ipProcess.waitFor();Log.i("Avalible", "Process:"+exitValue);//wifi不可用或未连接,返回2;WiFi需要认证,返回1;WiFi可用,返回0;return (exitValue == 0);} catch (IOException | InterruptedException e) {e.printStackTrace();}return false;}
}
package com.shu.Broadcast;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.view.View;
import android.widget.Toast;import com.shu.Utils.NetUtil;/*** @author shu* @date 2022/3/28* @description 网络变化广播*/
public class NetworkChangeBroadcast extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {//判断广播的类型为网络action后if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {//获取当前网络状态,并将结果发送给广播接受者int netWrokState = NetUtil.getNetWorkState(context);isNetConnect(netWrokState,context);}}private void isNetConnect(int netMobile,Context context) {switch (netMobile) {case 1:// wifiToast.makeText(context,"当前网络处于Wifi状态",Toast.LENGTH_SHORT).show();break;case 0:// 移动数据Toast.makeText(context,"当前网络处于移动数据状态",Toast.LENGTH_SHORT).show();break;case -1:// 移动数据Toast.makeText(context,"当前网络无数据状态",Toast.LENGTH_SHORT).show();break;}}
}

5.6.3 授权与测试

  • 配置清单中授权
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  • 活动中注册动态注册广播
package com.shu;import androidx.appcompat.app.AppCompatActivity;import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.os.Bundle;import com.shu.Broadcast.NetworkChangeBroadcast;public class MainActivity extends AppCompatActivity{private NetworkChangeBroadcast netBroadcastReceiver;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_main);if (netBroadcastReceiver == null) {//实例化网络接收器netBroadcastReceiver = new NetworkChangeBroadcast();//实例化意图IntentFilter filter = new IntentFilter();//设置广播的类型filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);//注册广播,有网络变化的时候会触发onReceiveregisterReceiver(netBroadcastReceiver, filter);}}//    在页面销毁的时候,取消注册的广播@Overridepublic void onDestroy() {super.onDestroy();if (netBroadcastReceiver != null) {unregisterReceiver(netBroadcastReceiver);}}
}
  • 注意点:动态注册的广播接收器一定都要取消注册才行,这里我们是在onDestroy()方法中通过调用unregisterReceiver()方法来实现的。

5.5 静态注册广播

  • 动态注册的广播接收器可以自由地控制注册与注销,在灵活性方面有很大的优势,但是它也存在着一个缺点,即必须要在程序启动之后才能接收到广播,因为注册的逻辑是写在onCreate()方法中的。

需求:我们需要通过点击来打开或关闭系统的蓝牙

分析:我们要用广播就离不开广播接收器

  • 首先,我们在初始化到时候,创建一个IntentFiltert监听器实例,完成对系统广播的监听
  • 为监听器实例添加需要监听的广播事件
  • 当系统发生变化,广播接收器会接受到广播事件,从而完成相应的逻辑编写
  • 页面构建
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"android:orientation="vertical"><Buttonandroid:id="@+id/open_ble"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="打开蓝牙"/><Buttonandroid:id="@+id/close_ble"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="关闭蓝牙"/><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="20dp"android:text="蓝牙设备的连接状态,可以使用两部手机进行试验,先对两部手机进行配对,然后再
进行手动连接,就会显示连接状态!"/>
</LinearLayout>
  • 蓝牙广播
package com.shu;import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;/*** @author shu* @date 2021/7/19* @description 蓝牙广播接收器*/
public class BluetoothMonitorReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if(action != null){switch (action) {case BluetoothAdapter.ACTION_STATE_CHANGED:int blueState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);switch (blueState) {case BluetoothAdapter.STATE_TURNING_ON:Toast.makeText(context,"蓝牙正在打开", Toast.LENGTH_SHORT).show();break;case BluetoothAdapter.STATE_ON:Toast.makeText(context,"蓝牙已经打开",Toast.LENGTH_SHORT).show();break;case BluetoothAdapter.STATE_TURNING_OFF:Toast.makeText(context,"蓝牙正在关闭",Toast.LENGTH_SHORT).show();break;case BluetoothAdapter.STATE_OFF:Toast.makeText(context,"蓝牙已经关闭",Toast.LENGTH_SHORT).show();break;}break;case BluetoothDevice.ACTION_ACL_CONNECTED:Toast.makeText(context,"蓝牙设备已连接",Toast.LENGTH_SHORT).show();break;case BluetoothDevice.ACTION_ACL_DISCONNECTED:Toast.makeText(context,"蓝牙设备已断开",Toast.LENGTH_SHORT).show();break;}}}
}
  • 主界面
package com.shu;import androidx.appcompat.app.AppCompatActivity;import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.provider.Settings;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;/*** 动态注册*/
public class MainActivity extends AppCompatActivity {private IntentFilter intentFilter;private Button openBle = null;private Button closeBle = null;private BluetoothMonitorReceiver bleListenerReceiver = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//初始化广播this.bleListenerReceiver = new BluetoothMonitorReceiver();IntentFilter intentFilter = new IntentFilter();// 监视蓝牙关闭和打开的状态intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);// 监视蓝牙设备与APP连接的状态intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);// 注册广播registerReceiver(this.bleListenerReceiver, intentFilter);// 初始化控件this.closeBle = findViewById(R.id.close_ble);this.openBle = findViewById(R.id.open_ble);// 关闭蓝牙this.closeBle.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//隐式关闭蓝牙BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();bluetoothAdapter.disable();}});// 打开蓝牙this.openBle.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {// 隐式打开蓝牙BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();bluetoothAdapter.enable();}});}@Overrideprotected void onDestroy() {super.onDestroy();unregisterReceiver(this.bleListenerReceiver);}}
  • 权限开启
 <uses-permission android:name="android.permission.BLUETOOTH" /><uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
  • 真机调试

注意:动态注册的广播接收器一定都要取消注册才行,这里我们是在onDestroy()方法中通过调用unregisterReceiver()方法来实现的。

5.6 自定义广播

  • 自定义广播就是继承广播,重写里面的方法,完成自己的逻辑代码编写
package com.shu;import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;/*** @author shu* @date 2021/7/19* @description 自定义广播*/
public class MyMonitorReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {Toast.makeText(context,"收到消息",Toast.LENGTH_LONG).show();}
}
  • 清单文件中注册
<receiverandroid:name=".MyMonitorReceiver"//是否启用android:enabled="true"//是否对外访问android:exported="true"><intent-filter><action android:name="com.shu.MyMonitorReceiver" /></intent-filter></receiver>
  • 主页面
package com.shu;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;public class MyActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_my);Button button = (Button) findViewById(R.id.button2);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent=new Intent("com.shu.MyMonitorReceiver");//标准广播sendBroadcast(intent);//发送有序广播//有序广播可以设置广播的权重,来优先启动android:priority="100"sendOrderedBroadcast(intent,null);}});}
}

5.7 使用本地广播

  • 我们发送和接收的广播全部属于系统全局广播,即发出的广播可以被其他任何应用程序接收到,并且我们也可以接收来自于其他任何应用程序的广播。这样就很容易引起安全性的问题,比如说我们发送的一些携带关键性数据的广播有可能被其他的应用程序截获,或者其他的程序不停地向我们的广播接收器里发送各种垃圾广播。
  • 为了能够简单地解决广播的安全性问题,Android引入了一套本地广播机制,使用这个机制发出的广播只能够在应用程序的内部进行传递,并且广播接收器也只能接收来自本应用程序发出的广播,这样所有的安全性问题就都不存在了。
  • 本地广播的用法并不复杂,主要就是使用了一个LocalBroadcastManager来对广播进行管理,并提供了发送广播和注册广播接收器的方法。
package com.shu;import androidx.appcompat.app.AppCompatActivity;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;import com.shu.Broadcast.LocalBroadcast;
import com.shu.Broadcast.NetworkChangeBroadcast;public class LocalBroadcastActivity extends AppCompatActivity {private IntentFilter intentFilter;private LocalBroadcast localBroadcast;private LocalBroadcastManager localBroadcastManager;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_local_broadcast);localBroadcastManager=LocalBroadcastManager.getInstance(LocalBroadcastActivity.this);Button button=findViewById(R.id.button);// 添加监听事件button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent("com.example.broadcasttest.LOCAL");localBroadcastManager.sendBroadcast(intent);}});localBroadcast=new LocalBroadcast();//实例化意图intentFilter = new IntentFilter();//设置广播的类型intentFilter.addAction("com.example.broadcasttest.LOCAL BROADCAST");//注册广播,有网络变化的时候会触发onReceivelocalBroadcastManager.registerReceiver(localBroadcast, intentFilter);}//    在页面销毁的时候,取消注册的广播@Overridepublic void onDestroy() {super.onDestroy();if (localBroadcastManager != null) {localBroadcastManager.unregisterReceiver(localBroadcast);}}
}

安卓开发(五)广播(Broadcasts)相关推荐

  1. 安卓开发学习日记第五天——奇怪的bug出现了(VT-x说没就没)_莫韵乐的欢乐日记

    安卓开发学习日记第五天--奇怪的bug出现了(VT-x说没就没) 前情提要: 安卓开发学习日记第一天_Android Studio3.6安装 安卓开发学习日记第二天_破坏陷阱卡之sync的坑 安卓开发 ...

  2. 14天学会安卓开发(附PDF文档和全部示例代码)

    前言: 本人也是菜鸟,老鸟看了此文有哪里不好之处敬请指点,本书是根据<<Android应用开发揭秘>>攒写的,如何把一本书读薄,是一件值得思考的问题.相信看过那本书的都知道有5 ...

  3. 【大疆DJI】安卓开发实习历程- 0.前期准备到面试(HR电话初面+技术一面+技术二面/终面+OC)

    目录 前言 实习选择 0. 腾讯云 1. 面试复盘 2. 海投简历 大疆HR电话初面 大疆技术一面 0. 面试形式 1. 问题准备 2. 面试经过(70 mins) 大疆技术二面(终面) 0. 面试形 ...

  4. 安卓开发-基础知识补习3

    听说点赞关注的人,身体健康,万事如意,工作顺利,爱情甜蜜,一夜暴富,升职加薪--最终迎娶白富美!!! 微信公众号:炜煜gzs 题目:安卓开发-基础知识补习3 内容简介:本文通过学习安卓零基础开发到入门 ...

  5. 如果成为一名高级安卓开发_什么是高级开发人员,我如何成为一名开发人员?

    如果成为一名高级安卓开发 Becoming a Senior Developer is something many of us strive for as we continue our code ...

  6. 安卓开发笔记(二十六):Splash实现首页快速开屏功能

    我们在进行安卓开发的时候,首页开有两种方式,一种是利用handler将一个活动进行延时,时间到达之后软件则会跳转到第二个活动当中.而另一种方法则是更加常用的方法,利用splash实现首页的快速开屏,这 ...

  7. 安卓开发之路-浅识Android

    1.首先从视觉上感受下安卓系统结构 可以发现安卓系统的底层是linux内核 依次往上分别是系统运行库层 应用框架层 应用层 蓝色的代表java程序,黄色的代码为运行JAVA程序而实现的虚拟机(这里是优 ...

  8. android关键应用程序,安卓开发:Android应用程序的四个关键点

    核心提示:本教程为大家介绍在安卓开发中我们应该关注那几点. 对于一个Android应用程序来说,是由四种关键构造块组织而成的,这四种构造块分别是:Activity.Intent Receiver.Se ...

  9. 为什么用java开发app_安卓开发为什么选择用Java语言

    最近几年,安卓应用开发一直处于长期增长的状态,安卓手机平台也是异军突起,甚至挑战了苹果在手机及平板系统的霸主地位,而今天安卓之所以能够有今天的成就,与之前选择用java语言开发有着莫大的关系.毕竟事实 ...

最新文章

  1. java提供两种处理异常的机制_浅析Java异常处理机制
  2. 如何将OutputStream转换为InputStream?
  3. hdu2962 二分 + spfa
  4. 贪心、递归、递推以及动态规划算法的分析与对比
  5. JPA入门简介与搭建HelloWorld(附代码下载)
  6. java怎么把system.out的东西输出到文件上
  7. Eclipse(STS 4)闪退导致EGit插件异常
  8. jupyter 功能插件
  9. http 性能测试 wrk使用教程
  10. NOIP2013普及组 车站分级
  11. 2020 mit6.s081 os Lab: xv6 traps
  12. 3ds Max 2014插件安装(插件无效的原因~)
  13. Codeforces 1092D1. Great Vova Wall (Version 1)
  14. 怎么裁剪PDF文件页面?一种方法轻松搞定
  15. 基于饥饿博弈搜索算法的函数寻优算法
  16. 《浣溪沙·一曲新词酒一杯》 晏殊
  17. UnityShader 简单护盾效果
  18. Java实践(五)仿照用户列表查询写查自己的库
  19. 【Linux内核】Linux软中断处理机制-ksoftirqd
  20. Spark:解析CSV文件并按列值分组

热门文章

  1. 防止私自接交换机_【s5700交换机】防止用户私设IP
  2. python ip反查询_python ip反查域名
  3. MIPS汇编二进制转10进制
  4. [STL]set存储pair并自定义排序
  5. flash 与html,Flash 与 html 的一些实用技巧
  6. 防晒隔离产品基础知识大全
  7. 【ToolBar】Android ToolBar之完全解析
  8. Xcode7.3.1中通过最新的CocoaPod安装pop动画引擎
  9. java计算机毕业设计河东街摊位管理系统源码+mysql数据库+系统+LW文档+部署
  10. Jupyter中的魔法函数