当前位置: 首页 > news >正文

【Android面试|华为|广播类】-Local Broaddcasts 能接收到系统广播么?

华为面试官问了其中一个问题

Q: Local Broaddcasts 能接收到系统广播么?
A: 本地广播(Local Broaddcasts) 只在本App发送和接收的广播。注册为本地广播的接收器无法收到标准广播。

Android应用可以通过广播从系统或其他App接收或发送消息。类似于订阅-发布设计模式。当某些事件发生时,可以发出广播。 系统在某些状态改变时会发出广播,例如开机、充电。App也可发送自定义广播。广播可用于应用间的通讯,是IPC的一种方式。

广播的种类

广播的种类或属性列举:

标准广播(Normal Broadcasts)
完全异步的广播。广播发出后,所有的广播接收器几乎同时接收到这条广播。 不同的App可以注册并接到标准广播。例如系统广播。
有序广播(Ordered Broadcasts)
同步广播。同一时刻只有一个广播接收器能接收到这条广播。这个接收器处理完后,广播才会继续传递。 有序广播是全局的广播。
本地广播(Local Broaddcasts)
只在本App发送和接收的广播。注册为本地广播的接收器无法收到标准广播。
带权限的广播
发送广播时可以带上相关权限,申请了权限的 App 或广播接收器才能收到相应的带权限的广播。 如果在 manifest 中申请了相应权限,接收器可以不用再申请一次权限即可接到相应广播。

注册广播

代码中注册称为动态注册。在AndroidManifest.xml中注册称为静态注册。动态注册的刚波接收器一定要取消注册。在onDestroy()方法中调用unregisterReceiver()方法来取消注册。

不要在onReceive()方法中添加过多的逻辑操作或耗时的操作。因为在广播接收器中不允许开启线程,当onReceive()方法运行较长时间而没结束时,程序会报错。因此广播接收器一般用来打开其他组件,比如创建一条状态栏通知或启动一个服务。

新建一个MyExampleReceiver继承自BroadcastReceiver。

public class MyExampleReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {Toast.makeText(context,"Got it",Toast.LENGTH_SHORT).show();//abortBroadcast();//abortBroadcast()可以截断有序广播}
}

在AndroidManifest.xml中注册广播接收器;android:name里填接收器的名字。 可以设置广播接收器优先级:

<intent-filter android:priority="100">
<receiver android:name=".MyExampleReceiver"><intent-filter><action android:name="com.rust.broadcasttest.MY_BROADCAST"/></intent-filter>
</receiver>
//让接收器接收到一条"com.rust.broadcasttest.MY_BROADCAST"广播。 发送自定义广播(标准广播)时,要传送这个值。例如:Intent intent = new Intent("com.rust.broadcasttest.MY_BROADCAST");
sendBroadcast(intent);//发送有序广播,应当调用sendOrderedBroadcast()Intent intent = new Intent("com.rust.broadcasttest.MY_BROADCAST");
sendOrderedBroadcast(intent,null);

发送广播

App有3种发送广播的方式。发送广播需要使用Intent类。

sendOrderedBroadcast(Intent, String)

发送有序广播。每次只有1个广播接收器能接到广播。 接收器接到有序广播后,可以完全地截断广播,或者传递一些信息给下一个接收器。 有序广播的顺序可受android:priority标签影响。同等级的接收器收到广播的顺序是随机的。

sendBroadcast(Intent)

以一个未定义的顺序向所有接收器发送广播。也称作普通广播。 这种方式更高效,但是接收器不能给下一个接收器传递消息。这类广播也无法截断。

**LocalBroadcastManager.sendBroadcast 广播只能在应用程序内部进行传递,并且广播接收器也只能接收到来自本应用程序发出的广播。 这个方法比全局广播更高效(不需要Interprocess communication,IPC),而且不需要担心其它App会收到你的广播以及其他安全问题。

广播与权限

发送带着权限的广播

当你调用sendBroadcast(Intent, String)或sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)时,你可以指定一个权限。 接收器在manifest中申请了相应权限时才能收到这个广播。

例如发送一个带着权限的广播

sendBroadcast(new Intent(“com.example.NOTIFY”), Manifest.permission.SEND_SMS);

接收广播的app必须注册相应的权限

当然也可以使用自定义。在 manifest 中使用 permission 标签

添加后编译一下。即可调用Manifest.permission.custom_permission

接收带权限的广播
若注册广播接收器时申明了权限,那么只会接收到带着相应权限的广播。

在配置文件中声明权限,程序才能访问一些关键信息。 例如允许查询系统网络状态。

如果没有申请权限,程序可能会意外关闭。

使用示例
发送和接收广播。分为发送和接收方2个App。

使用带权限的广播。系统权限与自定义权限。 使用权限需要在AndroidManifest.xml中声明。如果是自定义权限,需要先添加自定义权限。

<!-- 自定义的权限  给广播用 -->
<permission android:name="com.rust.permission_rust_1" />
<uses-permission android:name="com.rust.permission_rust_1" />

发送广播时带上权限声明。接收方(不论是否己方App)需要在AndroidManifest.xml中申请权限。 注册接收器时也需要声明权限。

发送不带权限的有序广播

Intent intent = new Intent(MSG_PHONE);
sendOrderedBroadcast(intent, null);
Log.d(TAG, "[RustFisher-App1] 发送不带权限的有序广播, " + intent.getAction());

发送方App1代码

private static final String TAG = "rustApp";public static final String MSG_PHONE = "msg_phone";public static final String PERMISSION_RUST_1 = "com.rust.permission_rust_1";// onCreate注册广播接收器registerReceiver(mStandardReceiver1, makeIF());registerReceiver(mStandardReceiver2, makeIF());registerReceiver(mStandardReceiver3, makeIF());registerReceiver(mStandardReceiverWithPermission, makeIF(),Manifest.permission.permission_rust_1, null);  // 带上权限LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(mLocalReceiver1, makeIF());LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(mLocalReceiver2, makeIF());LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(mLocalReceiver3, makeIF());// 解除接收器unregisterReceiver(mStandardReceiver1);unregisterReceiver(mStandardReceiver2);unregisterReceiver(mStandardReceiver3);unregisterReceiver(mStandardReceiverWithPermission);LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(mLocalReceiver1);LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(mLocalReceiver2);LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(mLocalReceiver3);// 发送标准广播private void sendStandardBroadcast() {Intent intent = new Intent(MSG_PHONE);sendBroadcast(intent);Log.d(TAG, "[RustFisher-App1] Dispatcher 发送标准广播");}// 发送带权限的标准广播private void sendStandardBroadcastWithPermission() {Intent intent = new Intent(MSG_PHONE);sendBroadcast(intent, PERMISSION_RUST_1);Log.d(TAG, "[RustFisher-App1] Dispatcher 发送带权限的标准广播");}// 发送本地广播private void sendAppLocalBroadcast() {Intent intent = new Intent(MSG_PHONE);LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);Log.d(TAG, "[RustFisher-App1] Dispatcher 发送本地广播");}private IntentFilter makeIF() {IntentFilter intentFilter = new IntentFilter(MSG_PHONE);intentFilter.addAction(Intent.ACTION_TIME_TICK);intentFilter.addAction(Intent.ACTION_TIME_CHANGED);return intentFilter;}// 标准接收器  用context来注册private BroadcastReceiver mStandardReceiver1 = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {Log.d(TAG, "[RustFisher-App1] 标准接收器1 收到: " + intent.getAction());}};// 标准接收器  用context来注册private BroadcastReceiver mStandardReceiver2 = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {Log.d(TAG, "[RustFisher-App1] 标准接收器2 收到: " + intent.getAction());if (intent.getAction().endsWith(MSG_PHONE)) {abortBroadcast(); // 截断有序广播Log.d(TAG, "[RustFisher-App1] 标准接收器2截断有序广播 " + intent.getAction());}}};// 标准接收器  用context来注册private BroadcastReceiver mStandardReceiver3 = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {Log.d(TAG, "[RustFisher-App1] 标准接收器3 收到: " + intent.getAction());}};// 注册的时候给它带权限  标准接收器private BroadcastReceiver mStandardReceiverWithPermission = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {Log.d(TAG, "[RustFisher-App1] 带权限的标准接收器收到: " + intent.getAction());}};/*** 用LocalBroadcastManager来注册成为本地接收器* 收不到标准广播 - 不论是本app发出的还是别的地方发出来的*/private BroadcastReceiver mLocalReceiver1 = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {Log.d(TAG, "[RustFisher-App1] 本地接收器1 收到: " + intent.getAction());}};private BroadcastReceiver mLocalReceiver2 = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {Log.d(TAG, "[RustFisher-App1] 本地接收器2 收到: " + intent.getAction());}};private BroadcastReceiver mLocalReceiver3 = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {Log.d(TAG, "[RustFisher-App1] 本地接收器3 收到: " + intent.getAction());}};

接收方App2代码


<!-- 自定义的权限  给广播用 -->
<permission android:name="com.rust.permission_rust_1" />
<uses-permission android:name="com.rust.permission_rust_1" />public static final String MSG_PHONE = "msg_phone";// onCreate里注册接收器registerReceiver(mDefaultReceiver, makeIF());LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(mLocalReceiver, makeIF());unregisterReceiver(mDefaultReceiver);LocalBroadcastManager.getInstance(getApplicationContext()).unregisterReceiver(mLocalReceiver);private BroadcastReceiver mDefaultReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {Log.d(TAG, "[App2] standard receive: " + intent.getAction());}};private BroadcastReceiver mLocalReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {Log.d(TAG, "[App2] local receive: " + intent.getAction());}};private IntentFilter makeIF() {IntentFilter intentFilter = new IntentFilter(MSG_PHONE);intentFilter.addAction(Intent.ACTION_TIME_TICK);intentFilter.addAction(Intent.ACTION_TIME_CHANGED);return intentFilter;}

使用LocalBroadcastManager发出的本地广播,另一个App是接收不到的。 要收到本地广播,同样需要LocalBroadcastManager来注册接收器。

可以把本地广播看成是一个局部的,App内的广播体系。

实验中我们注意到,Intent.ACTION_TIME_TICK广播是可以截断的。

监听屏幕亮灭
使用广播监听设备屏幕亮灭状态。这个是系统发出来的广播。

使用的action是

Intent.ACTION_SCREEN_ON 亮屏
Intent.ACTION_SCREEN_OFF 灭屏private void registerScreenListener() {IntentFilter filter = new IntentFilter();filter.addAction(Intent.ACTION_SCREEN_ON);filter.addAction(Intent.ACTION_SCREEN_OFF);registerReceiver(mScreenReceiver, filter);}private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {final String action = intent.getAction();if (Intent.ACTION_SCREEN_ON.equals(action)) {// 屏幕亮} else if (Intent.ACTION_SCREEN_OFF.equals(action)) {// 屏幕灭}}};

Broadcast 相关面试题

1. 广播传输的数据是否有限制,是多少,为什么要限制?

广播是通过Intent携带需要传递的数据的
Intent是通过Binder机制实现的
Binder对数据大小有限制,不同room不一样,一般为1M

2.广播的分类?

标准广播:通过context. sendBroadcast或者context. sendBroadcastAsUser发送给当前系统中所有注册的接受者,也就是只要注册了就会接收到。应用在需要通知各个广播接收者的情况下使用,如开机启动。
有序广播:接收者按照优先级处理广播,并且前面处理广播的接受者可以中止广播的传递,一般通过context. sendOrderedBroadcast或者context.sendOrderedBroadcastAsUser,在需要有特定拦截的场景下使用,如黑名单短信、电话拦截。
粘性广播:可以发送给以后注册的接受者,意思是系统会将前面的粘性广播保存在AMS中,一旦注册了与以保存的粘性广播符合的广播,在注册结束后会立即收到广播,一般通过context. sendStickyBroadcast或context.sendStickyOrderedBroadcast来发送,从字面上看,可以看出来粘性广播也分为普通粘性广播和有序粘性广播。
本地广播:发出的广播只能在应用程序内部进行传递,广播接收器也只能接受来自本应用程序的广播。
全局广播:系统和广播,发出的广播可以被其他任何应用程序接收到,并且也可以接受到其他任何应用程序的广播。

3.广播的使用场景

使用方式 广播是一种广泛运用的在应用程序之间传输信息的机制,主要用来监听系统或者应用发出的广播信息,然后根据广播信息作为相应的逻辑处理,也可以用来传输少量、频率低的数据。

在实现开机启动服务和网络状态改变、电量变化、短信和来电时通过接收系统的广播让应用程序作出相应的处理。
使用:

//在AndroidManifest中静态注册
<receiverandroid:name=".MyBroadcastReceiver"android:enabled="true"android:exported="true"><intent-filter android:priority="100"><action android:name="com.example.hp.broadcasttest.MY_BROADCAST"/></intent-filter>
</receiver>//动态注册,在代码中注册
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mIntentFilter = new IntentFilter();//添加广播想要监听的类型,监听网络状态是否发生变化mIntentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");mNetworkChangeReceiver = new NetworkChangeReceiver();//注册广播registerReceiver(mNetworkChangeReceiver, mIntentFilter);
}@Override
protected void onDestroy() {super.onDestroy();//取消注册广播接收器unregisterReceiver(mNetworkChangeReceiver);
}//发送广播,同样通过Intent
Intent intent = new Intent("com.example.hp.broadcasttest.MY_BROADCAST");
//发送标准广播
sendBroadcast(intent);//接收广播
public class MyBroadcastReceiver extends BroadcastReceiver {public MyBroadcastReceiver() {}@Overridepublic void onReceive(Context context, Intent intent) {// TODO: This method is called when the BroadcastReceiver is receiving// an Intent broadcast.Toast.makeText(context, "received", Toast.LENGTH_SHORT).show();//将这条广播截断
//        abortBroadcast();}
}

4. BroadcastReceiver,LocalBroadcastReceiver 区别 广播接收者:

(1)用于应用间的传递消息
(2)由于跨应用,存在安全问题

本地广播接收者:

(1)广播数据在本应用范围内传播。
(2)不用担心别的应用伪造广播。
(3)比发送全局广播更高效、安全。
(4)无法使用静态注册

5. 在 manifest 和代码中如何注册和使用

BroadcastReceiver (1)在AndroidManifest中静态注册,然后直接使用。 (2)代码中,通过registerReceiver来注册。 (3)注册发送后,在BroadcastReceiver(自定义一个接收器继承自BroadcastReceiver)的onReceive中接收广播并处理广播。

6. 广播引起 anr 的时间限制

前台广播:BROADCAST_FG_TIMEOUT = 10s 后台广播:BROADCAST_BG_TIMEOUT = 60s

相关文章:

  • 智慧工地平台源码,支持多端展示:PC端、手机端、平板端,实现数据同步
  • matlab操作方法(二)——基本作图
  • nginx配置反向代理及负载均衡
  • 迭代器 iterator
  • 连接器信号完整性仿真教程 九
  • Linux Spug自动化运维平台本地部署与公网远程访问
  • vector是如何扩容的
  • flutter 自定义TabBar 【top 0 级别】
  • Selector SelectionKey基础学习
  • 【Excel/Matlab】绘x-y图并求切线和截距(详细图解)
  • C# IList 与List区别二叉树的层序遍历
  • C语言实现ARM MCU SWD离线调试器
  • cesium 融合视频
  • [Ubuntu 18.04] RK3399搭建SSH服务实现远程访问
  • 六、ZooKeeper Java API操作
  • 【跃迁之路】【669天】程序员高效学习方法论探索系列(实验阶段426-2018.12.13)...
  • axios请求、和返回数据拦截,统一请求报错提示_012
  • extract-text-webpack-plugin用法
  • IDEA 插件开发入门教程
  • spring + angular 实现导出excel
  • Spring技术内幕笔记(2):Spring MVC 与 Web
  • vue学习系列(二)vue-cli
  • 聚类分析——Kmeans
  • 前端工程化(Gulp、Webpack)-webpack
  • 日剧·日综资源集合(建议收藏)
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 协程
  • 硬币翻转问题,区间操作
  • PostgreSQL之连接数修改
  • TPG领衔财团投资轻奢珠宝品牌APM Monaco
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • 机器人开始自主学习,是人类福祉,还是定时炸弹? ...
  • ​软考-高级-系统架构设计师教程(清华第2版)【第12章 信息系统架构设计理论与实践(P420~465)-思维导图】​
  • #ifdef 的技巧用法
  • #NOIP 2014# day.1 T2 联合权值
  • #stm32驱动外设模块总结w5500模块
  • #前后端分离# 头条发布系统
  • $.ajax()参数及用法
  • (7)STL算法之交换赋值
  • (c语言版)滑动窗口 给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度
  • (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作...
  • (Java)【深基9.例1】选举学生会
  • (M)unity2D敌人的创建、人物属性设置,遇敌掉血
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (二)linux使用docker容器运行mysql
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (附源码)springboot人体健康检测微信小程序 毕业设计 012142
  • (没学懂,待填坑)【动态规划】数位动态规划
  • (三)终结任务
  • (学习日记)2024.01.09
  • ***利用Ms05002溢出找“肉鸡
  • .NET Core 中插件式开发实现
  • .NET Standard 支持的 .NET Framework 和 .NET Core
  • .net wcf memory gates checking failed
  • .NET 设计一套高性能的弱事件机制