【精华】Android面试精华总结——BroadcastReceiver组件

一、广播机制与BroadcastReceiver

  广播作为Android组件间的通信方式,可以使用在如下场景:

  • APP内部的消息通信。
  • 不同APP之间的消息通信。
  • Android系统在特定情况下与APP之间的消息通信。

  广播使用了观察者模式,基于消息的发布/订阅事件模型。广播将广播的发送者和接受者极大程度上解耦,使得系统能够方便集成,更易扩展。

  BroadcastReceiver本质是一个全局监听器,用于监听系统全局的广播消息,方便实现系统中不同组件间的通信。
  自定义广播接收器需要继承基类BroadcastReceiver,并实现抽象方法onReceive(context,intent)。默认情况下,广播接收器也是运行在主线程,因此onReceiver()中不能执行太耗时的操作(不超过10s),否则将会产生ANR问题。onReceiver()方法中涉及与其他组件之间的交互时,可以使用发送Notification、启动Service等方式,最好不要启动Activity。

二、BroadcastReceiver类型

1.无序广播

  也叫标准广播,是一种完全异步执行的广播。在广播发出之后,所有广播接收器几乎都会在同一时刻接收到这条广播消息,它们之间没有任何先后顺序,广播的效率较高。
  调用SendBroadcast()方法发送广播。无序广播不可以被拦截,若被拦截则会报错。
  无序广播与广播接收器之间不能互传数据 。

2.有序广播

  是一种同步执行的广播,在广播发出之后,同一时刻只有一个广播接收器能够收到这条广播消息,当其逻辑执行完后该广播接收器才会继续传递。
  调用SendOrderedBroadcast()方法来发送广播,同时也可调用abortBroadcast()方法拦截该广播。可通过<intent-filter>标签中设置android:property属性来设置优先级,未设置时按照注册的顺序接收广播。
  有序广播接受器间可以互传数据。
  当广播接收器收到广播后,当前广播也可以使用setResultData方法提奶家数据传给下一个接收器。使用getStringExtra函数获取广播的原始数据,通过getResultData方法取得上个广播接收器自己添加的数据,并可用abortBroadcast方法丢弃该广播,使该广播不再被别的接收器接收到。
  

3.粘性广播

调用SendStickyBroadcast()方法发送广播,使用时需要权限。特定是Intent会一直保留到广播事件结束,没有10s限制。一般用来确保重要的状态改变后的信息被持久保存,并且能随广播给新的BroadcastReceiver,比如电源的改变。

三、注册方式

1.静态注册

AndroidManifest.xml文件中配置。

<receiver android:name=".MyReceiver" android:exported="true">
	<intent-filter>
		<!-- 指定该BroadcastReceiver所响应的Intent的Action -->
        <action android:name="android.intent.action.INPUT_METHOD_CHANGED"
		 <action android:name="android.intent.action.BOOT_COMPLETED" />
	</intent-filter>
</receiver>

两个重要属性需要关注:
(1)android:exported
  其作用是设置此BroadcastReceiver能否接受其他APP发出的广播 ,当设为false时,只能接受同一应用的的组件或具有相同user ID的应用发送的消息。这个属性的默认值是由BroadcastReceiver中有无Intent-filter决定的,如果有Intent-filter,默认值为true,否则为false。
(2)android:permission
  如果设置此属性,具有相应权限的广播发送方发送的广播才能被此BroadcastReceiver所接受;如果没有设置,这个值赋予整个应用所申请的权限。

2.动态注册

调用Context的registerReceiver(BroadcastReceiver receiver, IntentFilter filter)方法指定。

四、本地广播

  本地广播机制使得发出的广播只能够在应用程序的内部进行传递,并且广播接收器也只能接受来自本应用程序发出的广播,则安全性得到了提高。本地广播主要是使用了一个LocalBroadcastManager来对广播进行管理,并提供了发送广播和注册广播接收器的方法。
  开发者只要实现自己的BroadcastReceiver子类,并重写onReceive(Context context, Intetn intent)方法即可。
  当其他组件通过sendBroadcast()、sendStickyBroadcast()、sendOrderBroadcast()方法发送广播消息时,如果该BroadcastReceiver也对该消息“感兴趣”,BroadcastReceiver的onReceive(Context context, Intetn intent)方法将会被触发。

  使用步骤:

1. 调用LocalBroadcastManager.getInstance()获得实例
2. 调用registerReceiver()方法注册广播
3. 调用sendBroadcast()方法发送广播
4. 调用unregisterReceiver()方法取消注册

  注意事项:

1.本地广播无法通过静态注册方式来接受,相比起系统全局广播更加高效。
2.在广播中启动Activity时,需要为Intent加入FLAG_ACTIVITY_NEW_TASK标记,否则会报错,因为需要一个栈来存放新打开的Activity。
3.广播中弹出Alertdialog时,需要设置对话框的类型为TYPE_SYSTEM_ALERT,否则无法弹出。
4.不要在onReceiver()方法中添加过多的逻辑或者进行任何的耗时操作,因为在广播接收器中是不允许开启线程的,当onReceiver()方法运行了较长时间而没有结束时,程序就会报错。

五、系统广播

  Android系统内置了多个系统广播,只要涉及手机的基本操作,基本上都会发出相应的系统广播,如开机启动、网络状态改变、拍照、屏幕关闭与开启、电量不足等。在系统内部当特定时间发生时,系统广播由系统自动发出。

常见系统广播的Intent的Action为如下值:

  • 短信提醒:android.provider.Telephony.SMS_RECEIVED
  • 电量过低:ACTION_BATIERY_LOW
  • 电量发生改变:ACTION_BATTERY_CHANGED
  • 连接电源:ACTION_POWER_CONNECTED
  • 系统被关闭:ACTION_SHUTDOWN
  • 系统启动完成:ACTION_BOOT_COMPLETED

  从Android 7.0开始,系统不会再发送广播ACTION_NEW_PICTUREACTION_NEW_VIDEO,对于广播CONNECTIVITY_ACTION必须在代码中使用registerReceiver方法注册接收器,在AndroidManifest文件中声明接收器不起作用。
  从Android 8.0开始,对于大多数隐式广播,不能在AndroidManifest文件中声明接收器。

六、局部广播

  局部广播的发送者和接受者都同属于一个APP,相比于全局广播具有以下优点:

  • 其他的APP不会受到局部广播,不用担心数据泄露的问题。
  • 其他APP不可能向当前的APP发送局部广播,不用担心有安全漏洞被其他APP利用。
  • 局部广播比通过系统传递的全局广播的传递效率更高。

  Android v4包中提供了LocalBroadcastManager类,用于统一处理APP局部广播,使用方式与全局广播几乎相同,只是调用注册/取消注册广播接收器和发送广播偶读方法时,需要通过LocalBroadcastManager类的getInstance()方法获取的实例调用。

七、广播的安全性

  Android系统中的广播可以跨进程直接通信,会产生以下两个问题:

  • 其他APP可以接收到当前APP发送的广播,导致数据外泄。
  • 其他APP可以向当前APP放广播消息,导致APP被非法控制。

(1)发送广播

  • 发送广播时,增加相应的permission,用于权限验证。
  • 在Android 4.0及以上系统中发送广播时,可以使用setPackage()方法设置接受广播的包名。
  • 使用局部广播。

(2)接受广播

  • 注册广播接收器时,增加相应的permission,用于权限验证。
  • 注册广播接收器时,设置android:exported的值为false。
  • 使用局部广播。

  发送广播时,如果增加了permission,那接受广播的APP必须申请相应权限,这样才能收到对应的广播,反之亦然。
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  

  
  
  
  
  
  
  
  
  
  
  
  

  
  
  
  

发布了123 篇原创文章 · 获赞 119 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/cbwem/article/details/89761824