• 【Android 四大组件之Content Provider】一文吃透 BroadcastReceiver 广播接收器


    作者:半身风雪
    上一节:一文吃透Content Provider 内容提供者
    简介:在Android组件中最基本也是最为常见的四大组件:

    • Activity
    • Service服务
    • Content Provider内容提供者
    • BroadcastReceiver广播接收器


    一、什么是BroadcastReceiver

    BroadcastReceiver 是安卓系统中四大组件之一,在Android开发中,BroadcastReceiver的应用场景非常多,Android 广播分为两个角色:广播发送者、广播接收者。

    1.1、作用

    广播接收器用于响应来自其他应用程序或者系统的广播消息。

    • 不同组件之间通信(包括应用内 / 不同应用之间)
    • 与 Android 系统在特定情况下的通信(如当电话呼入时、网络可用时)
    • 多线程通信

    1.2、实现原理

    Android中的广播使用了设计模式中的观察者模式:基于消息的发布/订阅事件模型。

    模型中有3个角色:

    • 消息订阅者(广播接收者)

    • 消息发布者(广播发布者)

    • 消息中心(AMS,即Activity Manager Service)

    广播接收者通过 Binder机制在AMS注册
    广播发送者通过 Binder 机制向AMS发送广播
    AMS根据广播发送者要求,在已注册列表中,寻找合适的广播接收者(寻找依据:IntentFilter / Permission)
    AMS将广播发送到合适的广播接收者相应的消息循环队列中;
    广播接收者通过消息循环拿到此广播,并回调 onReceive()

    二、创建广播接收器

    广播接收器需要实现为BroadcastReceiver类的子类,并重写onReceive()方法来接收以Intent对象为参数的消息。

    public class MyReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            System.out.println("我是创建好的通知");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    三、注册广播接收器

    广播接收器的注册分为两种:

    • 静态注册
    • 动态注册

    3.1、静态注册

    应用程序通过在AndroidManifest.xml中注册广播接收器来监听制定的广播意图。

    广播接收器(Broadcast Receivers)

    3.1.1 注册

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    
    <receiver android:name=".MyReceiver"
        android:exported="true">
        <intent-filter>
            <action android:name="com.tiger_test"
                tools:ignore="BatteryLife" />
        </intent-filter>
    </receiver>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.1.2、发送通知

    在Activity 中新增一个发送通知的点击事件

        public void onClickStatic(View view) {
    
            System.out.println("MainActivity2.onClickStatic");
    //        com.tiger_test 必须和清单文件中注册的保持一致
            Intent intent = new Intent();
            intent.setAction("com.tiger_test");
            intent.setPackage("com.traveleasy.activitydemo");
            sendBroadcast(intent);
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    当点击通知发送按钮时,系统会自动实例化MyReceiver类,并注册到系统中。

    在这里插入图片描述

    静态注册是常驻广播,不受任何组件生命周期的影响

    注意:由于自8.0以后隐式广播不能进行静态注册了,所以这里通过setPackage()指定应用程序响应广播。

    3.2、动态注册

    通过registerReceiver()注册广播监听

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main2);
    
    //        在onCreate 中注册广播
            MyReceiver myReceiver = new MyReceiver();
            IntentFilter filter = new IntentFilter();
            filter.addAction("com.tiger_test");
            registerReceiver(myReceiver, filter);
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    触发通知

    public void onClickStatic(View view) {
        //        com.tiger_test 必须和注册的保持一致
        Intent intent = new Intent();
        intent.setAction("com.tiger_test");
        sendBroadcast(intent);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在页面关闭时记得通过unregisterReceiver()注销广播监听,否则会因广播持有Activity引用导致内存泄露。

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(myReceiver);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    运行结果

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DOkCU3so-1656405787660)(/Users/tiger/Library/Application%20Support/typora-user-images/image-20220628163533806.png)]

    需要注意,在onReceive()不能执行耗时操作,onReceive()默认是在主线程中,进行耗时会阻塞主线程,如果非要执行耗时操作最好开启一个服务在服务中进行耗时操作,不建议开启线程来处理耗时操作,因为BroadCastReceiver的生命周期很短,可能在子线程结束前BroadCastReceiver已经退出,如果当BroadCastReceiver所在的进程结束,虽然该进程中可能有用户启动的新线程,但是由于该进程内没有活动的组件,系统会在内存紧张的时候,优先结束掉该进程,这就会导致BroadCastReceiver启动的子线程不能执行完。

    四、系统广播

    上面我们一起学习了自定义广播,下面我们一起来看一下Android 系统主要的系统广播类型。

    事件常量描述
    android.intent.action.BATTERY_CHANGED持久的广播,包含电池的充电状态,级别和其他信息。
    android.intent.action.BATTERY_LOW标识设备的低电量条件。
    android.intent.action.BATTERY_OKAY标识电池在电量低之后,现在已经好了。
    android.intent.action.BOOT_COMPLETED在系统完成启动后广播一次。
    android.intent.action.BUG_REPORT显示报告bug的活动。
    android.intent.action.CALL执行呼叫数据指定的某人。
    android.intent.action.CALL_BUTTON用户点击"呼叫"按钮打开拨号器或者其他拨号的合适界面。
    android.intent.action.DATE_CHANGED日期发生改变。
    android.intent.action.REBOOT设备重启。

    总结

    在BroadcastReceiver 中,广播的类型主要分为两大类

    • 标注广播
    • 有序广播

    标准广播

    标准广播是一种完全异步执行的广播,在广播发出之后,所有的BroadcastReceiver几乎在同一时刻收到这个广播消息,它们之间没有先后顺序,这种广播的效率较高,并且不能被拦截。

    有序广播

    有序广播是一种完全同步的广播,在广播发出后只能有一个BroadcastReceiver能接收到这个广播消息,当这个BroadcastReceiver中的逻辑执行完毕后,广播才能继续向下传递。所以这个广播是有顺序的,所以这种广播也是可以被拦截的,如果被拦截了后面的BroadCastReceiver则不能收到广播消息了。

  • 相关阅读:
    新手学习 python 的好工具:PyScripter
    Linux无文件木马程序渗透测试复现
    面向JS程序员的TypeScript
    恒运资本:存储市场有望触底反弹 电子竞技迎催化
    猿创征文|OpenCV-像素值读写(java版)
    ES6中const注意点
    我一个测试仔,做了20多天开发的感受......
    Vulnhub靶场之matrix-breakout-2-morpheus
    一张张截图教你使用gitee
    Python基础(一)
  • 原文地址:https://blog.csdn.net/u010755471/article/details/125505476