BroadcastReceiver

2019-11-12  本文已影响0人  Demon鑫

零、资料

一、简介

Android 四大组件中的全局的监听器,BroadcastReceiver (广播接收器)。常用作监听/接收App发出的广播消息,并做出响应。常用如网络变化,强制下线等。

二、原理

1.设计模式

广播中使用观察者模式(消息的订阅、发布)。

2.组成

3.流程

流程

4.说明

  1. 接收器通过Binder机制在AMS注册。
  2. 发送者通过Binder机制向AMS发送广播。
  3. AMS根据发送者要求,在已注册列表中,寻找符合IntentFilter/Permission的接收器。
  4. AMS将发送到符合的接收器相应的消息循环队列中。
  5. 接收器通过消息循环拿到此广播,并回调onReceive()

注意:广播发送者和广播接收器的执行是异步的,既广播发送者不会关心接收器是否收到。

三、生命周期

1.动态注册

2.静态注册

四、使用

1.流程

流程

2.接收器定义

  1. 继承 BroadcastReceiver 并重写 onReceive()
  2. 注意
    • 接收器接收到广播后会自动调用 onReceive()
    • onReceive()一般会涉及与其他组件交互,如发送Notification、启动Service等。
    • 接收器默认为UI线程,所以onReceive()方法不能执行耗时操作,易将导致ANR

3.接收器注册

1.静态注册

2.动态注册

4.发送广播

sendBroadcast(intent)

五、类型

1.标准广播 Normal Broadcast

一种完全异步执行的广播,广播发出之后,所有的广播接收器几乎都会在同一时刻收到,无先后顺序。效率会比较高,但无法被截断。

2.系统广播 System Broadcast

Android 系统内置广播,无需发送广播,仅接收就可以。

系统操作 action
监听网络变化 android.net.conn.CONNECTIVITY_CHANGE
关闭或打开飞行模式 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
设备当前设置被改变时(界面语言、设备方向等) Intent.ACTION_CONFIGURATION_CHANGED
插入耳机时 Intent.ACTION_HEADSET_PLUG
未正确移除SD卡但已取出来时(正确移除方法:设置--SD卡和设备内存--卸载SD卡) Intent.ACTION_MEDIA_BAD_REMOVAL
插入外部储存装置(如SD卡) Intent.ACTION_MEDIA_CHECKING
成功安装APK Intent.ACTION_PACKAGE_ADDED
成功删除APK Intent.ACTION_PACKAGE_REMOVED
重启设备 Intent.ACTION_REBOOT
屏幕被关闭 Intent.ACTION_SCREEN_OFF
屏幕被打开 Intent.ACTION_SCREEN_ON
关闭系统时 Intent.ACTION_SHUTDOWN
重启设备 Intent.ACTION_REBOOT

3.有序广播 Ordered Broadcast

一种同步执行的广播,同一时刻只会有一个接收器收到广播,执行完毕后向下传递加工后的广播(或不传递,后面接收器收不到广播)。有先后顺序,可截断。

4.本地广播 Local Broadcast

方法一

  1. android:exported="false",仅接收当前应用的广播。
  2. 在广播发送和接收时,增设相应权限permission,用于权限验证。
  3. 发送广播时指定该广播接收器所在的包名intent.setPackage(packageName),此广播将只会发送到此包中的App内与之相匹配的有效广播接收器中。

方法二

使用LocalBroadcastManager,只支持动态注册。

// 注册应用内广播接收器
// 1.实例化 IntentFilter & BroadcastReceiver 
xxBroadcastReceiver = new xxBroadcastReceiver(); 
IntentFilter intentFilter = new IntentFilter(); 
  
// 2.实例化 LocalBroadcastManager 的实例
localBroadcastManager = LocalBroadcastManager.getInstance(this);
  
// 3.设置接收广播的类型 
intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);
  
// 4.调用 LocalBroadcastManager 单一实例的 registerReceiver() 进行动态注册 
localBroadcastManager.registerReceiver(xxBroadcastReceiver, intentFilter);
  

// 5.取消注册应用内广播接收器
localBroadcastManager.unregisterReceiver(xxBroadcastReceiver);
  

// 6.发送应用内广播
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION);
localBroadcastManager.sendBroadcast(intent);

注意

对于不同注册方式的广播接收器的OnReceive(Context context, Intent intent)中的context返回值是不一样的。

六、Android O(8.0)

Android8.0后优化了电量,当App targetSDK >= 26,几乎禁止了所有的隐式广播静态注册监听

1.赦免清单

// Android 8.0 上不限制的隐式广播
/**
开机广播
 Intent.ACTION_LOCKED_BOOT_COMPLETED
 Intent.ACTION_BOOT_COMPLETED
*/
"保留原因:这些广播只在首次启动时发送一次,并且许多应用都需要接收此广播以便进行作业、闹铃等事项的安排。"

/**
增删用户
Intent.ACTION_USER_INITIALIZE
"android.intent.action.USER_ADDED"
"android.intent.action.USER_REMOVED"
*/
"保留原因:这些广播只有拥有特定系统权限的app才能监听,因此大多数正常应用都无法接收它们。"
    
/**
时区、ALARM变化
"android.intent.action.TIME_SET"
Intent.ACTION_TIMEZONE_CHANGED
AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED
*/
"保留原因:时钟应用可能需要接收这些广播,以便在时间或时区变化时更新闹铃"

/**
语言区域变化
Intent.ACTION_LOCALE_CHANGED
*/
"保留原因:只在语言区域发生变化时发送,并不频繁。 应用可能需要在语言区域发生变化时更新其数据。"

/**
Usb相关
UsbManager.ACTION_USB_ACCESSORY_ATTACHED
UsbManager.ACTION_USB_ACCESSORY_DETACHED
UsbManager.ACTION_USB_DEVICE_ATTACHED
UsbManager.ACTION_USB_DEVICE_DETACHED
*/
"保留原因:如果应用需要了解这些 USB 相关事件的信息,目前尚未找到能够替代注册广播的可行方案"

/**
蓝牙状态相关
BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED
BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED
BluetoothDevice.ACTION_ACL_CONNECTED
BluetoothDevice.ACTION_ACL_DISCONNECTED
*/
"保留原因:应用接收这些蓝牙事件的广播时不太可能会影响用户体验"

/**
Telephony相关
CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED
TelephonyIntents.ACTION_*_SUBSCRIPTION_CHANGED
TelephonyIntents.SECRET_CODE_ACTION
TelephonyManager.ACTION_PHONE_STATE_CHANGED
TelecomManager.ACTION_PHONE_ACCOUNT_REGISTERED
TelecomManager.ACTION_PHONE_ACCOUNT_UNREGISTERED
*/
"保留原因:设备制造商 (OEM) 电话应用可能需要接收这些广播"

/**
账号相关
AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION
*/
"保留原因:一些应用需要了解登录帐号的变化,以便为新帐号和变化的帐号设置计划操作"

/**
应用数据清除
Intent.ACTION_PACKAGE_DATA_CLEARED
*/
"保留原因:只在用户显式地从 Settings 清除其数据时发送,因此广播接收器不太可能严重影响用户体验"
    
/**
软件包被移除
Intent.ACTION_PACKAGE_FULLY_REMOVED
*/
"保留原因:一些应用可能需要在另一软件包被移除时更新其存储的数据;对于这些应用,尚未找到能够替代注册此广播的可行方案"

/**
外拨电话
Intent.ACTION_NEW_OUTGOING_CALL
*/
"保留原因:执行操作来响应用户打电话行为的应用需要接收此广播"
    
/**
当设备所有者被设置、改变或清除时发出
DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED
*/
"保留原因:此广播发送得不是很频繁;一些应用需要接收它,以便知晓设备的安全状态发生了变化"
    
/**
日历相关
CalendarContract.ACTION_EVENT_REMINDER
*/
"保留原因:由日历provider发送,用于向日历应用发布事件提醒。因为日历provider不清楚日历应用是什么,所以此广播必须是隐式广播。"
    
/**
安装或移除存储相关广播
Intent.ACTION_MEDIA_MOUNTED
Intent.ACTION_MEDIA_CHECKING
Intent.ACTION_MEDIA_EJECT
Intent.ACTION_MEDIA_UNMOUNTED
Intent.ACTION_MEDIA_UNMOUNTABLE
Intent.ACTION_MEDIA_REMOVED
Intent.ACTION_MEDIA_BAD_REMOVAL
*/
"保留原因:这些广播是作为用户与设备进行物理交互的结果:安装或移除存储卷或当启动初始化时(当可用卷被装载)的一部分发送的,因此它们不是很常见,并且通常是在用户的掌控下"

/**
短信、WAP PUSH相关
Telephony.Sms.Intents.SMS_RECEIVED_ACTION
Telephony.Sms.Intents.WAP_PUSH_RECEIVED_ACTION

注意:需要申请以下权限才可以接收
"android.permission.RECEIVE_SMS"
"android.permission.RECEIVE_WAP_PUSH"
*/
"保留原因:SMS短信应用需要接收这些广播"

2.官方推荐

官方对于隐式广播推荐2种方法

3.Android O 隐式广播修改

对于隐式广播可以修改为显式广播

项目Demo

Demo地址 中的 Broadcast[module]

2019-11-12

上一篇 下一篇

猜你喜欢

热点阅读