01. 广播机制简介
- 在一个 IP 网络范围中,最大的 IP 地址是被保留作为广播地址来使用的。比如某个网络的 IP 范围是
192.168.0.xxxx
子网掩码是255.255.255.0
那么这个网络的广播地址就是192.168.0.255
了。广播数据包会被发送到同一网络上的所有端口,这样在该网络中的每台主机都将会收到这条广播。 - 在 Android 中每个应用可以对自己感兴趣的广播进行注册,这样该程序就只会接收到自己关心的广播。应用可以自由的发送和接收广播。
02. 广播分类
- 标准广播
- 一种完全异步执行的广播。广播发出后,所有接收器几乎同时接收到广播消息,因此没有先后顺序,效率高,无法被截断。
- 有序广播
- 一种同步执行的广播。广播发出后,同一时刻只有一个接收器接收到广播消息,这个接收器执行完毕广播才会继续传递,因此有先后顺序,优先级高的接收器先收到,并且前面的可以截断正在传递的广播,这样后面的就无法收到广播消息了。
03. 注册广播
- 动态注册
- 需要使用
IntentFilter
类指定相应的action
注册
与解注册
成对出现,在onCreate
中进行注册在onDestroy
中进行解注册
- 需要使用
- 静态注册
- 需要在功能清单中使用
intent-filter
及action
标签指定 - 注册之后为系统
全局
的广播接收器 - 程序进程
运行中
则可以接收
,程序进程完成退出
则无法接收
- 需要在功能清单中使用
04. 广播示例代码
动态注册-监听网络变化
继承 BroadcastReceiver
/** * 动态广播监听网络变化 * * @author JustDo23 */ public class NetworkChangeReceive extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { ToastUtil.showShortToast(context, "Network changes."); ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); if (networkInfo != null && networkInfo.isAvailable()) { ToastUtil.showShortToast(context, "Network is available."); } else { ToastUtil.showShortToast(context, "Network is unavailable."); } } }
在 Activity 中注册与解注册
/** * 动态广播监听网络变化 * * @author JustDo23 */ public class NetworkChangeActivity extends BaseActivity { private IntentFilter intentFilter; private NetworkChangeReceive networkChangeReceive; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_network_change); register();// 注册广播 } @Override protected void onDestroy() { super.onDestroy(); unRegister();// 解注册广播 } /** * 注册广播 */ private void register() { intentFilter = new IntentFilter(); intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); networkChangeReceive = new NetworkChangeReceive(); this.registerReceiver(networkChangeReceive, intentFilter); } /** * 解注册广播 */ private void unRegister() { unregisterReceiver(networkChangeReceive); } }
添加权限
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
静态注册-监听手机开机
使用 Android Studio 创建广播接收器
右击
选择New
选择Other
选择Broadcast Receiver
进行命名- 此操作与手动创建一致
功能清单新增
<receiver android:name=".chapter05.CustomReceiver" android:enabled="true" android:exported="true"> </receiver>
enabled
属性表示是否启用这个广播接收器exported
属性表示是否允许这个广播接收器接收本程序以外的广播
添加
<intent-filter>
标签并指定<action>
标签信息<receiver android:name=".chapter05.CustomReceiver" android:enabled="true" android:exported="true"> <intent-filter android:priority="100"> <action android:name="com.just.first.CUSTOM" /> </intent-filter> </receiver>
priority
指定了广播的优先级
添加权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
05. 发送自定义广播
发送标准广播
sendBroadcast(new Intent("com.just.first.CUSTOM"));// Intent 指定 action
发送有序广播
sendOrderedBroadcast(new Intent("com.just.first.CUSTOM"), null);// 第二参数是一个与权限相关的字符串
- 发送有序广播需要指定
优先级
,可以在功能清单中使用priority
指定优先级 - 前面的广播可以截断广播的传递,在
onReceive()
方法中调用abortBroadcast()
方法截断广播
- 发送有序广播需要指定
06. 本地广播
前面的广播都属于系统全局广播,即发出的广播可以被其他任何程序接收到,并且程序也可以接收来自其他任何应用的广播。这样存在安全问题。Android 引入了一套本地广播机制,使用本地广播机制广播只能在本应用内部进行发送和接收。主要是使用了一个 LocalBroadcastManager
来对广播进行管理。
本地广播注册
private LocalBroadcastReceiver localBroadcastReceiver; private LocalBroadcastManager localBroadcastManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_local_broadcast); localBroadcastManager = LocalBroadcastManager.getInstance(this);// 获取实例 IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction("com.just.first.LOCAL"); localBroadcastReceiver = new LocalBroadcastReceiver();// 实例化接收器 localBroadcastManager.registerReceiver(localBroadcastReceiver, intentFilter);// 注册本地广播 }
本地广播解注册
@Override protected void onDestroy() { super.onDestroy(); localBroadcastManager.unregisterReceiver(localBroadcastReceiver); }
本地广播发送
public void sendLocalBroadcast(View view) { Intent intent = new Intent("com.just.first.LOCAL"); localBroadcastManager.sendBroadcast(intent);// 发送本地广播 }
重要提示
- 本地广播是无法通过静态注册的方式来接收的。
- 静态注册主要就是为了让程序在未启动的情况下也能接收到广播。
本地广播优势
- 可以明确知道正在发送的广播不会离开我们的程序,不必担心机密数据泄露。
- 其他程序无法将广播发送到我们程序的内部,不必担心有安全漏洞隐患。
- 发送本地广播比发送系统全局广播更加高效。
07. 重点提示
注意:开发时不能在
onReceive()
方法中添加过多逻辑或者进行任何的耗时操作,因为在广播接收器中不允许开启线程的,当onReceive()
方法运行较长时间而没有结束,程序就会出现 ANR 错误。广播是一种可以跨进程的
通信
方式,例如我们可以接收系统广播。在静态广播接收器及本地广播接收器中是没有办法弹出对话框的。
android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
在动态广播接收器中是可以弹出对话框的。
当在
BaseActivity
中注册广播从而使得所有子类都动态注册该广播的操作中,需要将广播的注册
与解注册
分别放在生命周期的onResume()
与onPause()
中。这样可以保障只有处于栈顶的活动才能接收到广播信息。
08. 初识 Git
Git 是一个开源的分布式
版本控制
工具。配置身份
$ git config --global user.name "JustDo23" $ git config --global user.email "JustDo_23@163.com"
创建代码仓库
$ git init
添加与提交
$ git add . $ git commit -m "describe for commit"
09. 小结
- 广播的生命周期简单了解。
- 进一步了解广播的工作原理。