【安卓开发】安卓广播机制

news2024/12/22 11:45:48

读书笔记系列(第一行代码)

5.1 广播机制简介

  • 标准广播:完全异步执行,广播发出后,所有广播接收器几乎都同一时刻收到这条广播(无法被截断)
  • 有序广播:同步执行,广播发出后同一时刻只会有一个广播接收器能收到这条广播消息,前面的接收器可以截断正在传递的广播
    有序广播工作示意图

5.2 接收系统广播

广播接收器可在代码中注册和AndroidManifest.xml中注册,前者为动态注册,后者被称为静态注册。

5.2.1 动态注册监听网络变化

示例代码:

public class MainActivity extends AppCompatActivity {

    private IntentFilter intentFilter;
    private NetworkChangeReceiver networkChangeReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView((R.layout.activity_main));
        intentFilter= new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_VHANGE");
        networkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(networkChangeReceiver, intentFilter);
    }

    @Override
    protected void onDestroy(){
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
    }

    class NetworkChangeReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent){
            ConnectivityManager connectionManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connectionManager.getActiveNetworkInfo();
            if(networkInfo != null && networkInfo.isAvailable()){
                Toast.makeText(context, "network is available", Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(context, "network is unavailable", Toast.LENGTH_SHORT).show();
            }

            Toast.makeText(context, "network changes", Toast.LENGTH_SHORT).show();
        }
    }
}

静态注册实现开机启动

<receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true"></receiver>

Export属性表示是否允许这个广播接收器接收本程序以外的广播,enable表示是否使用这个广播接收器。

<receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>

添加了filter就可以过滤了
可以通过左键新建-》其它来新建静态注册广播
广播接收器中不允许开线程,当onReceive方法运行较长时间而没结束时,程序就会报错,所以其中不能添加过多的逻辑或任何耗时操作。

5.3 发送自定义广播

5.3.1 发送标准广播

@Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView((R.layout.activity_main));
        Button button = (Button)findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
                sendBroadcast(intent);
            }
        });
    }

通过点击按钮发送广播

public class myBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "receiverd in myBroadcastReceiver", Toast.LENGTH_SHORT).show();
    }
}

这里是自定义的接收器

<receiver
            android:name=".myBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>

在xml中定义过滤的广播类型

5.3.2 发送有序广播

广播是一种跨进程的通信方式

protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView((R.layout.activity_main));
        Button button = (Button)findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
                sendOrderedBroadcast(intent, null);
            }
        });
    }

只需要修改一行代码 sendOrederedBroadcast即可发送有序广播,同时在接收器的xml文件中可以设置优先级

<receiver
            android:name=".myBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
<!--            在这里设置优先级-->
            <intent-filter android:priority="100">
                <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>

如果想要在接收到广播之后就让广播停止继续传递呢,修改onReceive的代码即可

public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "receiverd in myBroadcastReceiver", Toast.LENGTH_SHORT).show();
//        停止继续传递
        abortBroadcast();
    }

5.4 使用本地广播

前面我们发送和接收的广播全部属于系统全局广播,即发出的广播可以被其他任何应用程序接收到,并且我们也可以接收来自于其他任何应用程序的广播。这样就很容易引起安全性的问题,比如说我们发送的一些携带关键性数据的广播有可能被其他的应用程序截获,或者其他的程序不停地向我们的广播接收器里发送各种垃圾广播。
使用本地广播则发出的广播只能在应用程序内部传递,并且接收器也只能接收来自本应用程序发出的广播。

public class MainActivity extends AppCompatActivity {

    private IntentFilter intentFilter;
    private LocalReceiver localReceiver;
    private LocalBroadcastManager localBroadcastManger;

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView((R.layout.activity_main));
        localBroadcastManger = LocalBroadcastManager.getInstance(this); //获取实例
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent("com.example.broadcasttest.LOCAL_BROADCAST");
                localBroadcastManger.sendBroadcast(intent); //发送本地广播
            }
        });
        intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
        localReceiver = new LocalReceiver();
        localBroadcastManger.registerReceiver(localReceiver, intentFilter); //注册本地广播监听器
    }

    @Override
    protected void onDestroy(){
        super.onDestroy();
        localBroadcastManger.unregisterReceiver(localReceiver);
    }

    class LocalReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent){
            Toast.makeText(context, "received local broadcast", Toast.LENGTH_SHORT).show();
        }
    }
}

代码的不同主要在于需要首先获取实例,然后还要有注册。
需要注意的是,本地广播无法通过静态注册来接收。

5.5 使用广播实现强制下线功能

强制下线功能首先需要实现下关闭所有的活动的功能,新建一个ActivityCollector类管理所有的活动

public class ActivityCollector {
    public static List<Activity> activities = new ArrayList<>();

    public static void addActivity(Activity activity){
        activities.add(activity);
    }

    public static void removeActivity(Activity activity){
        activities.remove(activity);
    }

    public static void finishAll(){
        for(Activity activity:activities){
            if(!activity.isFinishing()){
                activity.finish();
            }
        }
    }
}

然后创建baseActivity类作为活动的父类,代码如下:

public class BaseActivity extends AppCompatActivity {
    private ForceOfflineReceiver receiver;

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        ActivityCollector.addActivity(this);
    }

    @Override
    protected void onResume(){
        super.onResume();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.broadcastbestpractice.FORCE_OFFLINE");
        receiver = new ForceOfflineReceiver();
        registerReceiver(receiver, intentFilter);
    }

    @Override
    protected void onPause(){
        super.onPause();
        if(receiver != null){
            unregisterReceiver(receiver);
            receiver = null;
        }
    }

    @Override
    protected void onDestroy(){
        super.onDestroy();
        ActivityCollector.removeActivity(this);
    }

    class ForceOfflineReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(final Context context, Intent intent){
            AlertDialog.Builder builder = new AlertDialog.Builder(context);
            builder.setTitle("warning");
            builder.setMessage("You are forced to be offline");
            builder.setCancelable(false);
            builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int which) {
                    ActivityCollector.finishAll(); //销毁所有活动
                    Intent intent = new Intent(context, LoginActivity.class);
                    context.startActivity(intent); //重新启动loginActivity
                }
            });
            builder.show();
        }
    }
}

我们可以注意到,之前编写注册和销毁接收器的时候是在onCreate和onDestroy这两个函数里的,但是上面代码中却写在了onResume和onPause里面,这是因为我们每次都只需要在栈顶的活动接收广播,非栈顶活动没必要接收这条广播。

除此之外,我们创建一个登陆的活动,在活动页面上放置输入框,并编写登录逻辑

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".ui.login.LoginActivity">

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        tools:ignore="MissingConstraints">
        <TextView
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:textSize="18sp"
            android:text="Account:"/>

        <EditText
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:id="@+id/account"
            android:layout_weight="1"
            android:layout_gravity="center_horizontal"/>
    </LinearLayout>

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        tools:ignore="MissingConstraints">
        <TextView
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:textSize="18sp"
            android:text="password:"/>

        <EditText
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:id="@+id/password"
            android:layout_weight="1"
            android:layout_gravity="center_horizontal"/>
    </LinearLayout>

    <Button
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:id="@+id/login"
        android:text="Login"
        tools:ignore="MissingConstraints"></Button>

</androidx.constraintlayout.widget.ConstraintLayout>
public class LoginActivity extends AppCompatActivity {
    private EditText accountEdit;
    private EditText passwordEdit;
    private Button login;

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        accountEdit = (EditText) findViewById(R.id.account);
        passwordEdit = (EditText) findViewById(R.id.password);
        login = (Button) findViewById(R.id.login);
        login.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String account = accountEdit.getText().toString();
                String password = passwordEdit.getText().toString();
                //如果账号是admin 且密码是123456则登录成功
                if(account.equals("admin") && password.equals("123456")){
                    Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                    startActivity(intent);
                    finish();
                }else {
                    Toast.makeText(LoginActivity.this, "account is invalid", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}

这样就模拟了登录的窗口,然后在mainActivity中加入触发强制下线的代码

public class MainActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button forceOffline = (Button) findViewById(R.id.force_offline);
        forceOffline.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.broadcastbestpractice.FROCE_OFFLINE");
                sendBroadcast(intent);
            }
        });
    }
}

这样逻辑就差不多了,下面去AndroidManifest.xml中修改下程序入口即可:

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

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

相关文章

优秀!19年后,它再次成为TIOBE年度编程语言

新年伊始&#xff0c;TIOBE发布了2022年度编程语言&#xff0c;C时隔19年再度登顶&#xff0c;成为2022年最受欢迎的编程语言。TIOBE在2003年首次统计编程语言的流行指数时&#xff0c;C便成为年度编程语言。2022年&#xff0c;C获得了最高的人气4.62%&#xff0c;紧随其后的是…

maven打包顺序与jvm类加载顺序

背景&#xff1a;一次dev测试过程中&#xff0c;发现代码中关于jsr303的校验失效&#xff0c;校验类如下&#xff0c;会报一个莫名其妙的运行时错误&#xff1b;遂进行排查。import javax.validation.constraints.NotBlank;Data Accessors(chain true) public class Demo {Not…

为什么会有跨域问题,代理是怎么解决的?

&#x1f4d6; 文章导航关于跨域问题同源策略跨域资源共享解决方案前端代理后端服务端代理关于跨域问题 同源策略 同源策略&#xff08;Same-origin policy&#xff09;是浏览器中一个重要的安全策略&#xff0c;它用于限制不同源之间的资源交互。其目的是为了帮助阻隔恶意文…

由浅入深,一起来刷Java高级开发岗面试指南,面试必定无忧!

前言 我只想面个CV工程师&#xff0c;面试官偏偏让我挑战造火箭工程师&#xff0c;加上今年这个情况更是前后两男&#xff0c;但再难苟且的生活还要继续&#xff0c;饭碗还是要继续找的。在最近的面试中我一直在总结&#xff0c;每次面试回来也都会复盘&#xff0c;下面是我根…

Dubbo之SpringBoot启动源码详解

需要前置知识&#xff0c;了解spring源码&#xff0c;springboot自动加载机制等 DubboBootstrap启动 详细信息可看 学习Dubbo源码需要了解的基础内容源码详解 DubboBootstrap 启动所需要的信息 添加应用程序配置添加注册中心配置添加协议配置添加服务配置启动 SpringBoot启…

广东MES系统实施过程中的要点和难点

MES系统已经成为企业目前实施的焦点。但是MES系统又分为很多的种类&#xff0c;对企业之间则是很难选择的&#xff0c;因为大部分的企业对MES系统的要点和难点并不清楚&#xff0c;而今天就让先达盈致的小编带大家了解一下广东MES系统实施过程中的要点和难点。MES系统是实现企业…

戴尔T5810电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。硬件型号驱动情况主板戴尔T5810&#xff0c;C610/612芯片处理器英特尔至强E5-2620 v3已驱动内存12 GB已驱动硬盘500GB WD Blue Solid State Drive & 2TB Seagate Mobile Hard Drive (Upgraded)已驱动显卡RX 570 4Gb已驱…

october-cms

环境准备 靶机链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;3e4s 虚拟机网络链接模式&#xff1a;桥接模式 攻击机系统&#xff1a;kali linux 2021.1 信息收集 1.探测目标靶机ip。 2.探测靶机开放端口和服务情况。 漏洞探测 1.访问网页 2.用dirsearch扫描…

用javascript分类刷leetcode15.链表(图文视频讲解)

链表操作如下图&#xff1a; 动画过大&#xff0c;点击查看 时间复杂度&#xff1a; prepend: O(1)append: 如果已知尾节点O(1)&#xff0c;否则需要遍历到尾节点&#xff0c;然后加入新节点O(n)insert: 插入到已知节点的后面O(1)&#xff0c;需要先查找后插入O(n)lookup: O…

【STM32笔记】__WFI();进入不了休眠的可能原因

【STM32笔记】__WFI();进入不了休眠的可能原因 【STM32笔记】低功耗模式配置及避坑汇总 前文&#xff1a; blog.csdn.net/weixin_53403301/article/details/128216064 【STM32笔记】HAL库低功耗模式配置&#xff08;ADC唤醒无法使用、低功耗模式无法烧录解决方案&#xff09;…

Outlook邮箱注册教程 不信你看完还不懂

Outlook作为Microsoft Office家族的办公软件套装之一&#xff0c;关联着很多微软的其他产品。而且Outlook是欧美地区认可度比较高的&#xff0c;不仅可以用于一些境外联络还可以拿来注册Instagram、Twitter、Facebook等各种社交媒体平台。龙哥在这里就给大家出一份详细的Outloo…

Python打包调试问题解决

使用pyinstaller打包&#xff0c;发现问题&#xff1a;代码运行时调试的结果不一致代码中设定的图标打包后没有显示出来打包代码程序test.py为入口函数main&#xff08;&#xff09;所在的文件pyinstaller -F -w -i test.ico test.py 不会出现控制台&#xff0c;图标为test.ic…

电源大事,阻抗二字

作者&#xff1a;一博科技高速先生成员 姜杰PCB设计时&#xff0c;我们通常会控制走线的特征阻抗&#xff1b;电源设计时&#xff0c;又会关注电源分配系统&#xff08;PDN&#xff09;的交流阻抗&#xff0c;虽然都是阻抗&#xff0c;一个是信号的通道要求&#xff0c;一个是电…

电子标签拣货系统——外接供电版

Power_DC24v 型号&#xff1a;Power_DC24v24V电源适配器级联线&#xff1a;长30cm直径&#xff1a;15mmCK_Wire_V1 型号&#xff1a;CK_Wire_V1连接电源适配器级联线&#xff1a;长30cm公线&#xff1a;长宽厚 14*11*9mm母线&#xff1a;长宽厚 13*5.5*3mmCK_Wire_V2 型号&…

安卓玩机搞机-----没有第三方包 刷写第三方各种GSI系统 体验非官方系统

很多安卓友友热衷与刷这些各种第三方包体验。但有个别机型第三方资源较少。而且有的机型要体验非官方系统却没有对应系统的第三方包。那可以体验下刷gsi系统来畅玩。今天的帖子就聊聊GSI系统的各种刷写操作和对应的故障解析、 &#x1f494;&#x1f494;&#x1f494;&#x…

spring cloud(二)----------------Eureka注册中心环境搭建

一、首先创建一个没有架骨的maven主项目 点击下一步创建 创建完成后在maven主项目下删除src并且创建四个maven副项目分别叫&#xff1a; demospringcloud-api--------连接实例 demospringcloud-cosumer---------消费类 demospringcloud-eureka---------注册类 demospringc…

机器学习:基于支持向量机(SVM)进行人脸识别预测

机器学习&#xff1a;基于支持向量机&#xff08;SVM&#xff09;进行人脸识别预测 文章目录机器学习&#xff1a;基于支持向量机&#xff08;SVM&#xff09;进行人脸识别预测一、实验目的二、实验原理三、实验环境四、实验内容五、实验步骤1.准备数据2.业务理解3.数据理解4.数…

java3月train笔记

java笔记 day01 一、jdk和idea下载及安装&#xff08;一般不建议装C盘&#xff09;&#xff1a; jdk&#xff1a;java开发环境 idea&#xff1a;开发工具&#xff08;软件&#xff09;&#xff0c;用来编写代码的 苍老师文档服务器&#xff1a;doc.canglaoshi.org jdk下载&…

JavaEE|网络编程之套接字 TCP

文章目录一、ServerSocket API构造方法常用方法二、Socket API构造方法常用方法注意事项三、TCP中的长短连接E1:一发一收&#xff08;短连接&#xff09;E2:请求响应&#xff08;短连接&#xff09;E3&#xff1a;多线程下的TCP回响服务器说明&#xff1a;这部分说实话有点懵&a…

SrpingBoot拦截器

一、拦截器原理 根据当前请求&#xff0c;进入到 HandlerExecutionChain(可以处理请求的 handler 以及 handler 的所有拦截器)根据顺序执行所有拦截器的 preHandle() 方法如果当前拦截器的 preHandler() 方法返回 true&#xff0c;则执行下一个拦截器的 preHandler() 方法如果当…