展开说说:Android之广播接收者

1、是什么:

BroadcastReceiver是Android四大组件之一的消息型组件;只有一个生命周期onReceiver但不可以进行耗时操作。可以代码动态注册也可清单文件静态注册;

2、啥原理:

广播分为广播发送者和广播接收者,发送者可以自定义也可以是系统固有的我们只需要接收即可。
广播使用了观察者设计模式和消息的发布/订阅模型。它包括:订阅者(广播接收者)、发布者(广播发送者)、消息中心(ActivityServiceManager,下文简称AMS)
广播接收者通过Binder先在AMS注册;广播发送者通过Binder向AMS发送广播;AMS根据广播发送者要求,在已注册的广播中选择匹配的广播接收者(依据:IntentFilter和Permission);AMS将广播发送到合适的广播接收者相应的消息循环队列中;广播接收者通过消息循环拿到此广播并回调onReceiver,他是广播接收者唯一生命周期方法,任务执行10s以上会出现ANR,如果有耗时操作需要开启service再子线程执行。
静态广播调用sendBroadcast方法时,系统自动实例化对应的广播并将它注册到AMS。

广播作用范围:不同组件之间(应用内和应用外);与Android在特定情况下的通信(比如电话呼入、网络可用、开屏/锁屏);多线程通信

3、有什么:

注册方式:静态注册、动态注册;

传递方式:有序广播、无序广播;

范围:全局广播BroadcastReceiver、本地广播:LocalBroadcastReceiver、带权限广播、接收系统固有的广播(此处以锁屏/开屏为例)

4、下面跑一下代码看看:

第一步先注册两个广播接收者用来接收广播,可以动态注册直接new也可以再清单文件静态注册,静态广播在清单文件比较简单,此处动态注册举例

定义两个广播接收者并进行注册:

广播接收者:

public class MyReceiver extends BroadcastReceiver {
    public static final String TAG = MyReceiver.class.getName();
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.e(TAG, "onReceive:   action="+intent.getAction() );

//根据action做一些不同处理
        if ("short".equals(intent.getAction())){
            Toast.makeText(context,"闹钟",Toast.LENGTH_SHORT).show();
        }else {
            String key = intent.getStringExtra("key");
            Log.e(TAG, "onReceive:   key="+key );
        }

    }
}

广播接收者2:

public class MyReceiver2 extends BroadcastReceiver {
    public static final String TAG = MyReceiver2.class.getName();
    @Override
    public void onReceive(Context context, Intent intent) {
        String key = intent.getStringExtra("key");
        Log.e(TAG, "onReceive:   key="+key );
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

//注册标准动态广播
myReceiver = new MyReceiver();
IntentFilter intentFilter = new IntentFilter("com.MyReceiver.rust.MY_BROADCAST");
registerReceiver(myReceiver,intentFilter);


//注册标准动态广播-实现有序广播2
myReceiver2 = new MyReceiver2();
IntentFilter intentFilter2 = new IntentFilter("com.MyReceiver.rust.MY_BROADCAST");
registerReceiver(myReceiver2,intentFilter2);

4.1动态注册-分为有序广播和无序广播:

动态注册的在registerReceiver之后别忘了在使用结束以后进行unregisterReceiver(myReceiver);要判断当前receiver对象非空再反注册。动态广播如果注册了不反注册会引起内存泄漏,还有个更严重的如果没有注册直接去做反注册会报错IllegalArgumentException:Receiver not registed引发程序闪退(这里要注意使用非当时的注册的context反注册就等于使用没注册的)。

4.1.1 有序广播-发消息  

在manifest注册intentFilter通过priority标签可设置有序广播的优先级,有序广播两个接收器action一样正常都会收到消息,按自身设置的priority优先级接收,高的可以阻断让低的收不到

                Intent intent = new Intent("com.MyReceiver.rust.MY_BROADCAST");
                intent.putExtra("key","动态广播-有序");
                sendOrderedBroadcast(intent,null);

// TODO: 有序广播一定是体现在同一个action且只发一次
                //MyReceiver2
                Intent intent2 = new Intent("com.MyReceiver.rust.MY_BROADCAST");
                intent2.putExtra("key","静态广播-有序-2");
    ComponentName component2 =  new ComponentName(ReceiverActivity.this, MyReceiver2.class);
                intent2.setComponent(component2);
                sendOrderedBroadcast(intent2,null);

4.1.2无序广播-发消息:

Intent intent = new Intent("com.MyReceiver.rust.MY_BROADCAST");
intent.putExtra("key","动态广播-无序");
sendBroadcast(intent);

4.2静态注册:

可跨进程通讯分为有序广播和无序广播;需要注意Android系统8.1及以上设备无法接收,要么换动态注册要么使用setComponent参数

                Intent intent = new Intent("com.MyReceiver.rust.MY_BROADCAST");
                intent.putExtra("key","静态广播");
                // android系统8.0以后隐士广播不能注册为静态广播,因此大于8.0的必须制定应用程序。这一步是精髓,静态广播没有Action也可以;因为静态显示广播根据类名.class启动因此好像无法实现静态显示的有序广播
                ComponentName component =  new ComponentName(ReceiverActivity.this,MyReceiver.class);
                //这样设置无效,不报错但也收不到消息
//                ComponentName component =  new ComponentName(getPackageName(),getPackageName()+"activity.MyReceiver");
                intent.setComponent(component);
                sendBroadcast(intent);

无序广播两个接收器action一样都会收到消息,几乎同时;

有序广播两个接收器action一样正常都会收到消息,按自身设置的priority优先级接收,高的可以阻断让低的收不到也可以修改后在发出让优先级低的收到。

4.3本地广播:

LocalBroadcastManager.getInstance();  localbroadcast.sendBroadCast(intent)依赖LocalBroadcastManager实例,只能在本应用内部接收消息 不能跨应用:

代码-注册本地广播的广播接收者:

broadcastManager = LocalBroadcastManager.getInstance(ReceiverActivity.this);        broadcastManager.registerReceiver(myReceiver,intentFilter);

注意:注册本地广播 (****和标准动态广播注册的接收器不能交叉同时,否则收不到消息)

代码-发送本地广播:
Intent intent = new Intent("com.MyReceiver.rust.MY_BROADCAST");
intent.putExtra("key","本地广播");
broadcastManager.sendBroadcast(intent);

4.4带权限广播  

接收器所在APP必须申请了对应权限,否则接收不到消息。如自定义权限,在Manifest中先permission标签后uses-permission标签即可

                Intent intent = new Intent("com.MyReceiver.rust.MY_BROADCAST");
                intent.putExtra("key","动态广播-无序");
//发送权限广播,接收器所在APP必须申请了这个权限,否则收不到
//                sendBroadcast(intent, Manifest.permission.INTERNET);

//自定义权限
                sendBroadcast(intent, "com.example.testdemo3.BROADPERMISSION");

自定义权限需要在清单文件中声明

<!--    自定义权限,先permission标签后uses-permission标签即可-->
    <permission android:name="com.example.testdemo3.BROADPERMISSION"/>
    <uses-permission android:name="com.example.testdemo3.BROADPERMISSION"/>

4.5接收系统固有的广播(此处以锁屏/开屏为例)

定义广播接收者:

public class DeviceStatusReceiver extends BroadcastReceiver {
    public static final String TAG = DeviceStatusReceiver.class.getName();
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        switch (action){
            case Intent.ACTION_SCREEN_ON:
                Log.e(TAG, "onReceive: 开屏" );
                break;
            case Intent.ACTION_SCREEN_OFF:
                Log.e(TAG, "onReceive: 锁屏" );
                break;
            default:
                Log.e(TAG, "onReceive: 其他 ="+action );
                break;
        }

    }
}

//注册广播接收者

        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_SCREEN_ON);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        DeviceStatusReceiver deviceStatusReceiver = new DeviceStatusReceiver();
        registerReceiver(deviceStatusReceiver, filter);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/193993.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

栈和队列OJ题——15.循环队列

15.循环队列 622. 设计循环队列 - 力扣&#xff08;LeetCode&#xff09; * 解题思路&#xff1a; 通过一个定长数组实现循环队列 入队&#xff1a;首先要判断队列是否已满&#xff0c;再进行入队的操作&#xff0c;入队操作需要考虑索引循环的问题&#xff0c;当索引越界&…

网络接口规范

1、基本物理层: a) RJ45接口作为最基本的网络接口之一有两种形式&#xff1a;对于百兆网口有4条线&#xff0c;2对差分线&#xff1b;对于千兆网口有4对差分线。RJ45水晶头是有8个凹槽和8个触点&#xff08;8p8c&#xff09;的接头&#xff0c;分为集成网络变压器和非集成网络变…

使用进程池/线程池 加速 Python数据处理

使用进程池/线程池 加速 Python数据处理 目标简单模式多进程模式 参考 Python 是一种出色的编程语言&#xff0c;可用于处理数据和自动执行重复任务。尽管 Python 使编码变得有趣&#xff0c;但它并不总是运行速度最快的。默认情况下&#xff0c;Python 程序使用单个 CPU 作为单…

2022年9月8日 Go生态洞察:Go Developer Survey 2022 Q2 结果分析

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

物奇平台电容触摸功能调试

是否需要申请加入数字音频系统研究开发交流答疑群(课题组)?可加我微信hezkz17, 本群提供音频技术答疑服务,+群赠送语音信号处理降噪算法,蓝牙耳机音频,DSP音频项目核心开发资料, 物奇平台电容触摸功能调试 1 修改按键驱动宏 2 编译生成wpk 文件,import 导入烧录文件。…

水果编曲软件fl studio手机版下载

fl studio mobile手机版中文名水果编曲软件&#xff0c;它是一款非常不错的音乐编曲软件&#xff0c;凭借简单易上手的操作方式&#xff0c;强悍且实用的功能&#xff0c;深受到了音乐创作者的喜爱&#xff0c;不仅仅提供了广阔的音乐创作空间&#xff0c;可以让用户对舞曲、轻…

工具网站:随机生成图片的网站

一个随机生成图片的网站&#xff1a;Lorem Picsum。 有时候&#xff0c;我们做静态页面需要大量图片去填充内容&#xff0c;以使用该网站去生成指定尺寸的图片。每次打开页面都会获取不同的图片&#xff0c;就不用我们做静态页面开发的时候&#xff0c;绞尽脑汁去找图片了。 …

原型设计模式

4. 原型设计模式 4.1 浅拷贝 在Java编程中&#xff0c;浅拷贝是指在复制对象时&#xff0c;只复制对象的基本数据类型的值和引用类型的地址&#xff0c;不复制引用类型指向的对象本身。浅拷贝可以用于一些简单的场景&#xff0c;例如对象的基本属性不包含其他对象的引用类型&…

振南技术干货集:ChatGPT,现在我做单片机/嵌入式开发已经离不开它了!(2)

注解目录 &#xff08;此文部分内客由 ChatGPT 生成&#xff0c;你分得出来哪些是人写的&#xff0c;哪些是 ChatGPT 生成的吗?&#xff09; 20.1 恐怖的 ChatGPT 2023年ChatGPT有多火?比 TikTok火4 倍都不止!什么是“范式革命”?从石器时代到飞机大炮就是范式革命。AI绘…

C语言速通笔记(1-40)

1&#xff0e;一个 C 语言程序有且只有一个 main 函数&#xff0c;是程序运行的起点。 2&#xff0e;每个 C 语言程序写完后&#xff0c;都是先编译&#xff0e; c 后链接&#xff0e; obj 最后运行&#xff0e;. exe 3.c和&#xff0e; obj 文件是无法运行的&#xff0c;只有…

Python读取栅格遥感影像并加以辐射校正后导出为Excel的一列数据

本文介绍基于Python语言中的gdal模块&#xff0c;读取一景.tif格式的栅格遥感影像文件&#xff0c;提取其中每一个像元的像素数值&#xff0c;对像素值加以计算&#xff08;辐射定标&#xff09;后&#xff0c;再以一列数据的形式将计算后的各像元像素数据保存在一个.csv格式文…

Redis基础知识

目录 一、为什么要用到Redis? 二、Redis 为什么运行比较快&#xff1f; 三、Redis的数据结构 四、Redis可以实现什么功能&#xff1f; 五、Redis 保证数据持久化方式 1、持久化方式主要有2种&#xff1a;RDB 和 AOF 2、RDB和AOF区别&#xff1f; 六、Redis 中的过期删…

IDA常用操作、快捷键总结以及使用技巧

先贴一张官方的图&#xff0c;然后我再总结一下&#xff0c;用的频率比较高的会做一些简单标注 快捷键 F系列【主要是调试状态的处理】 F2 添加/删除断点F4 运行到光标所在位置F5 反汇编F7 单步步入F8 单步跳过F9 持续运行直到输入/断点/结束 shift系列【主要是调出对应的页…

洛谷 P9389 烂柯杯 C++代码

目录 前言 思路点拨 AC代码 结尾 前言 今天我们来做洛谷上的一道题目。 网址&#xff1a;[THUPC 2023 决赛] 烂柯杯 - 洛谷 题目&#xff1a; 乱七八糟一堆文字&#xff0c;展示不下。 思路点拨 思路1&#xff1a;和围棋有关的人&#xff0c;很容易想到柯洁。 思路2&…

【RotorS仿真系列】Ardrone模型介绍

ardrone是rotors仿真框架提供的一款机型&#xff0c;因为该机型与我们实际使用的机型参数相近&#xff0c;所以这里对它的参数做特别整理和记录。 一、模型参数总结 ardrone的gazebo模型如下图所示&#xff1a; 根据ardrone.yaml&#xff0c;其关键参数如下所示&#xff1a…

Project 1: The Game of Hog(CS61A)

&#xff08;第一阶段&#xff09;问题 5a&#xff08;3 分&#xff09; 实现该函数&#xff0c;该函数模拟了完整的 Hog 游戏。球员 交替轮流掷骰子&#xff0c;直到其中一名玩家达到分数。playgoal 您现在可以忽略 Feral Hogs 规则和论点; 您将在问题 5b 中实现它。feral_h…

UC++中的头文件和宏的那些事儿

假定有如下继承自AActor类的.h文件&#xff1a; #pragma once#include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "MoveRandom.generated.h"UCLASS() class DEMO01_API AMoveRandom : public AActor {GENERATED_BODY()public…

车联网架构设计(一)_消息平台的搭建

车联网是物联网的一个主要应用方向&#xff0c;车辆通过连接车联网平台&#xff0c;实时进行消息的交互&#xff0c;平台可以提供车辆远程控制&#xff0c;故障检测&#xff0c;车路协同等各方面的功能。 我在车联网行业从事了很长时间的技术工作&#xff0c;参与了整个车联网…

树莓派多串口通信

树莓派多串口通信 串口配置串口通信函数分析串口通信示例代码 参考博文1&#xff1a;树莓派 4 UART 多串口配置通信参考博文2&#xff1a;树莓派wiringPi库详解关于树莓派相关其他环境配置可参考&#xff1a;快速上手树莓派关于wiringPi库初始化与IO口开发可参考&#xff1a;树…

深入探索FastAPI单元测试:使用TestClient轻松测试你的API

原文&#xff1a;深入探索FastAPI单元测试&#xff1a;使用TestClient轻松测试你的API-51CTO.COM 当使用FastAPI进行单元测试时&#xff0c;一个重要的工具是TestClient类。TestClient类允许我们模拟对FastAPI应用程序的HTTP请求&#xff0c;并测试应用程序的响应。这使我们能…