Android 面试题总结之Android 基础(三)

在上一章节Android 面试题总结之Android 基础ContentProvider(二) 我们讲的ContentProvider和Intent基础知识。本节主要讲解Broadcast Receiver相关基础知识。

在阅读过程中有任何问题,请及时联系。 
本章系《Android 之美 从0到1 – 高手之路》Android基础Broadcast Receiver 总结了Android 开发者面试比较常见的Broadcast Receiver相关面试问题以及关于Broadcast Receiver优化性能问题。希望对广大Android 开发者,有所帮助。

Broadcast Receiver 常见面试题

  1. BroadcastReceiver 简介

    BroadCastReceiver 是 Android 四大组件之一,主要用于接收系统或者 app 发 送的广播事件。 
    广播分两种:有序广播和无序广播。 
    内部通信实现机制:通过 Android 系统的 Binder 机制实现通信。 无序广播:完全异步,逻辑上可以被任何广播接收者接收到。优点是效率较高。 缺点是一个接收者不能将处理结果传递给下一个接收者,并无法终止广播 intent 的传播。 有序广播:按照被接收者的优先级顺序,在被接收者中依次传播。比如有三个广 播接收者 A,B,C,优先级是 A > B > C。那这个消息先传给 A,再传给 B,最 后传给 C。每个接收者有权终止广播,比如 B 终止广播,C 就无法接收到。此外 A 接收到广播后可以对结果对象进行操作,当广播传给 B 时,B 可以从结果对象 
    中取得 A 存入的数据。

    在通过 Context.sendOrderedBroadcast(intent, receiverPermission, resultReceiver, scheduler, initialCode, initialData, initialExtras)时我们可以 指定 resultReceiver 广播接收者,这个接收者我们可以认为是最终接收者,通 常情况下如果比他优先级更高的接收者如果没有终止广播,那么他的 onReceive 会被执行两次,第一次是正常的按照优先级顺序执行,第二次是作为最终接收者 接收。如果比他优先级高的接收者终止了广播,那么他依然能接收到广播。 在我们的项目中经常使用广播接收者接收系统通知,比如开机启动、sd 挂载、 低电量、外播电话、锁屏等。 如果我们做的是播放器,那么监听到用户锁屏后我们应该将我们的播放之暂停 等。

    Android 4.0之后,如果系统自动关闭广播接收者所在进程,在广播中的action跟广播接收者的action匹配时,系统会启动该广播所在的进程,但是如果是用户手动关闭该进程,则不会自启动,只有等用户手动开启,广播接收者所在进程如果从来没有启动过,那么广播接收者不会生效

  2. 在 manifest 和代码中如何注册和使用 BroadcastReceiver 
    在清单文件中注册广播接收者称为静态注册,在代码中注册称为动态注册。 静态注册的广播接收者只要 app 在系统中运行则一直可以接收到广播消息,动 态注册的广播接收者当注册的 Activity 或者 Service 销毁了那么就接收不到广播 了。

    静态注册:在清单文件中进行如下配置

    <receiver android:name=".BroadcastReceiver1" > <intent-filter>
    <action android:name="android.intent.action.CALL" >
                </action>
            </intent-filter>
    </receiver> 
       
       
    • 1
    • 2
    • 3
    • 4
    • 5

    动态注册:在代码中进行如下注册

    receiver = new BroadcastReceiver();
    IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(CALL_ACTION); context.registerReceiver(receiver, intentFilter);
       
       
    • 1
    • 2

    两种注册类型的区别是:

    • 第一种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行(跟系统版本关系,也可能不自动运行)

    • 第二种不是常驻型广播,也就是说广播跟随程序的组件(比如Activity)生命周期。

不同注册方式广播接收器回调onReceive(context, intent)中context类型不一致?

  • manifest静态注册的ContextReceiver,回调onReceive(context, intent)中的context是ReceiverRestrictedContext;

  • 代码动态注册的ContextReceiver,回调onReceive(context, intent)中的context是Activity Context;

  • 使用LocalBroadcastManager动态注册的ContextReceiver,回调onReceive(context, intent)中的context是Application Context。

    1. BroadCastReceiver 的生命周期 
      a. 广播接收者的生命周期非常短暂的,在接收到广播的时候创建, onReceive()方法结束之后销毁; 
      b. 广播接收者中不要做一些耗时的工作,否则会弹出 Application No Response 错误对话框; 
      c. 最好也不要在广播接收者中创建子线程做耗时的工作,因为广播接收者被 销毁后进程就成为了空进程,很容易被系统杀掉; 
      d. 耗时的较长的工作最好放在服务中完成;

    2. Android 引入广播机制的用意

    a. 从 MVC 的角度考虑(应用程序内) 其实回答这个问题的时候还可以这样问, 
    android 为什么要有那 4 大组件,现在的移动开发模型基本上也是照搬的 web 那一套 MVC 架构,只不过是改了点嫁妆而已。android 的四大组件本 质上就是为了实现移动或者说嵌入式设备上的 MVC 架构,它们之间有时候 是一种相互依存的关系,有时候又是一种补充关系,引入广播机制可以方便 几大组件的信息和数据交互。 
    b. 程序间互通消息(例如在自己的应用程序内监听系统来电) 
    c. 效率上(参考 UDP 的广播协议在局域网的方便性) 
    d. 设计模式上(反转控制的一种应用,类似监听者模式)

    1. 如何让自己的广播只让指定的 app 接收? 
      通过自定义广播权限来保护自己发出的广播。 
      在清单文件里receiver必须有这个权限才能收到广播。 
      首先,需要定义权限: 
      然后,声明权限: 
      这时接收者就能收到发送的广播。

    2. 广播的优先级对无序广播生效吗? 
      生效的

    3. 动态注册的广播优先级谁高? 
      谁先注册谁优先级高。

    4. 如何判断当前 BroadcastReceiver 接收到的是有序广播还是无序广播? 
      在 BroadcastReceiver 类中 onReceive()方法中,可以调用 boolean b = isOrderedBroadcast();判断接收到的广播是否为有序广播。

    5. 粘性广播有什么作用?怎么使用? 
      粘性广播主要为了解决,在发送完广播之后,动态注册的接收者,也能够收到广播。举个例子首先发送一广播,我的接收者是通过程序中的某个按钮动态注册的。如果不是粘性广播,我注册完接收者肯定无法收到广播了。这是通过发送粘性广播就能够在我动态注册接收者后也能收到广播。

    //发送粘性广播 
    Public void sendStickyBroadCast(){ 
              Intent intent=new Intent(); 
               intent.setAction(“com.example.receiver.action”); 
               intent.putExtra(“name”,”tom”); 
               this.sendStickyBroadCast(intent); 
         } 
       
       
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    发送粘性广播还需要发送粘性广播的权限:

    <uses-permission android:name="android.permission.BROADCAST_STICKY" />

    在 android 5.0/api 21中deprecated,不再推荐使用,包括粘性有序广播

    1. 什么是最终广播接收者? 
      即使前边拦截了广播,还是会收到广播 
      最终广播是我们自己应用发送有序广播时通过 ContextWrapper.sendOrderedBroadcast()方法指定的当前应用 下的广播,该广播可能会被执行两次,第一次是作为普通广播按照优先级接收广播,第二次是作为 final receiver 必须 接收一次。

LocalBroadcastManager (局部通知管理器)

在android-support-v4.jar中引入了LocalBroadcastManager

LocalBroadcastManager除了能解决BroadcastReceiver进程间安全性问题外,相对Context操作的BroadcastReceiver而言还具有更高的运行效率。 
本地广播通过LocalBroadcastManager.getInstance(context).sendBroadcast(intent)发送广播, 
LocalBroadcastManager.getInstance(context).registerReceiver注册服务,通过LocalBroadcastManager.getInstance(context).unregisterReceiver取消注册服务,其他同普通广播。 
BroadcastReceiver的通信是走 Binder 机制的,LocalBroadcastManager 的核心实现实际还是 Handler,只是利用到了 IntentFilter 的 match 功能,因为是 Handler 实现的应用内的通信,自然安全性更好,效率更高。

通常使用BroadcastReceiver进行工作线程的任务结果通知也好,还是进程间安全性问题,容易引起性能问题,那么使用LocalBroadcastManager.getInstance有效提高了安全性和性能。

注意:LocalBroadcastManager方式发送的应用内广播,只能通过LocalBroadcastManager动态注册的ContextReceiver才有可能接收到(静态注册或其他方式动态注册的ContextReceiver是接收不到的)。

关于BroadcastReceiver相关面试问题,本章节就先总结到这来。希望对大家有所帮助。

应用场景

  • App内各个组件通讯(单个或多个线程之间),局部刷新等;

  • 不同App之间的组件之间消息通信;

  • 接收系统广播等。

系统广播

在广播消息中,有一类特殊的广播消息,它们特殊在只能由Android系统发出,这类广播消息称为系统广播。 
ACTION_TIME_TICK 系统时间已经改变。该事件每分钟被广播一次,只能通过动态注册BroadcastReceiver来响应。 
ACTION_TIME_CHANGED 系统时间被设置 
ACTION_TIMEZONE_CHANGED 系统时区被改变 
ACTION_BOOT_COMPLETED 系统启动完成 
ACTION_PACKAGE_ADDED 新的应用程序被安装 
ACTION_PACKAGE_CHANGED 应用程序被改变 
ACTION_PACKAGE_REMOVED 应用程序被卸载 
ACTION_PACKAGE_RESTARTED 应用程序被重新启动 
ACTION_PACKAGE_DATA_CLEARED 应用程序数据被清空 
ACTION_UID_REMOVED 用户ID被删除 
ACTION_BATTERY_CHANGED 点量信息改变 
ACTION_POWER_CONNECTED 外接电源被连通 
ACTION_POWER_DISCONNECTED 外接电源被断开 
ACTION_SHUTDOWN 系统关闭

安全性

BroadcastReceiver可以方便应用程序和系统、应用程序之间、应用程序内的通信,所以对单个应用程序而言BroadcastReceiver是存在组件安全性问题的。 
这就让组件暴露在外,建议在开发客户端时不要暴露内部组件,如果有特殊需求也需进行权限控制,使用这些组件时需要申请相应权限。这样能有一定的防范。

  • 权限控制(permission)(发送某个广播时系统会将发送的Intent与系统中所有注册的BroadcastReceiver的IntentFilter进行匹配,若匹配成功则执行相应的onReceive函数。可以通过类似sendBroadcast(Intent, String)的接口在发送广播时指定接收者必须具备的permission。或通过Intent.setPackage设置广播仅对某个程序有效)
  • 声明android:exported=”false” 
    android:exported 是Android中的四大组件 Activity,Service,Provider,Receiver 四大组件中都会有的一个属性。 
    主要作用:是否支持其它应用调用当前组件,默认值:如果包含有intent-filter 默认值为true; 没有intent-filter默认值为false,如果组件无须跨进程交互,则不应设置exported属性为true, 
    当Activity中该属性用来标示:当前Activity是否可以被另一个Application的组件启动:true允许被启动;false不允许被启动 
    当MyService的exported属性为true时,将可以被其他应用调用,等其他组件类似。

  • LocalBroadcastManager 使用上面说的,LocalBroadcastManager只会将广播限定在当前应用程序中

  • 使用protectionLevel: 
    protectionLevel 有一下四类级别: 
    normal:低风险权限,只要申请了就可以使用(在AndroidManifest.xml中添加标签),安装时不需要用户确认 
    dangerous:高风险权限,安装时需要用户的确认才可使用 
    signature:只有当申请权限的应用程序的数字签名与声明此权限的应用程序的数字签名相同时(如果是申请系统权限,则需要与系统签名相同),才能将权限授给它 
    signatureOrSystem:签名相同,或者申请权限的应用为系统应用(在system image中)才能拥有 
    如果需要对自己的应用程序(或部分应用)进行访问控制,则可以通过在AndroidManifest.xml中添加标签,将其属性中的protectionLevel设置为上述四类级别中的某一种来实现。

总结

  • Android5.0 开始粘滞广播和有序粘滞广播过期,不再建议使用
  • Android N 后台优化——三个广播被禁止监听或发送 
    • CONNECTIVITY_CHANGE 广播 
      在后台时不再能接收到 CONNECTIVITY_CHANGE 广播,前台不影响。
    • ACTION_NEW_PICTURE 和 ACTION_NEW_VIDEO 广播 
      不能发送或是接收新增图片(ACTION_NEW_PICTURE)和新增视频(ACTION_NEW_VIDEO) 的广播。)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值