• Android的有序广播和无序广播(解决安卓8.0版本之后有序广播的接收问题)


    前言

    Google从Android8.0版本开始,对在清单文件中静态注册广播做了限制。


    特殊广播(动态注册广播接收者)

    说:有序广播和无序广播之前,咱们先来说下Android中一些特殊的广播如何接收呢?

    • 特殊的广播:指那些操作比较频繁的广播事件类型。如:屏幕的开、关广播,电量的变化广播等等
    • 这种特殊的广播事件在 AndroidManifest.xml 中注册是无效的
      因为这种特殊的广播如果在清单文件中注册,会浪费内存资源。你可以想象下,如果有100个应用在清单文件中注册了手机电量变化广播接收者,那当手机电量发生变化时,这100个应用的广播接收者就有可能都运行...那会造成什么结果...。所以:只能动态注册(在代码中注册)

    如何动态注册广播呢

    • 定义一个广播接收者(两种方式)
    //方式一:动态注册一个广播接受者
            BroadcastReceiver receiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    String action = intent.getAction();
                    if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                        Log.e("动态注册广播接收者", "屏幕 关闭 了");
                    } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
                        Log.e("动态注册广播接收者", "屏幕 开启 了");
                    }
                }
            };
    
    //方式二:单独定义一个 广播接收者
    public class TestReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //获取发送的广播
            String body = intent.getStringExtra("body");
            Log.e("广播接收者", "body:" + body);
        }
    }
    
    • 动态注册广播接收者(注册定义好的广播接收者)
    //注册:接收系统广播 的 广播接收者
            //创建一个意图过滤器
            IntentFilter filter = new IntentFilter();
            //为意图过滤器添加广播事件类型
            filter.addAction(Intent.ACTION_SCREEN_OFF);//关屏广播
            filter.addAction(Intent.ACTION_SCREEN_ON);//开屏广播
            //注册广播
            this.registerReceiver(receiver, filter);
    
    // 注册:自定义的广播接收者(action的添加有以下两种方式)
            //方式一:构造器传参
            IntentFilter filter = new IntentFilter("wo-shi-yi-ge-action");
            //方式二:使用addAction()方法添加
    //        IntentFilter filter = new IntentFilter();
    //        filter.addAction("wo.ye.shi.yi.ge.action");
            //filter.addCategory("");
            //filter.addDataType("");
            //filter.addDataScheme("");
            this.registerReceiver(receiver2, filter);
    
    • 发送一个广播(切记:广播发送之前要先注册广播接收者,否则接收者是接收不到消息的)。针对于自定义的广播事件。
      切记发送和接收的 action 要保持一致,不然是收不到消息的
            //注册成功之后,发送一个广播
            Intent intent = new Intent();
            intent.setAction("wo-shi-yi-ge-action");
            //intent.setAction("wo.ye.shi.yi.ge.action");
            intent.putExtra("body", "我是数据");
            this.sendBroadcast(intent);
    

    无序广播

    • 类似于新闻联播,不关心是否有人接收,都会发送。
    • 不可以中止
    • 特殊广播:也是一种无序广播。
    • 广播接收者的两种注册方式:静态注册 和 动态注册。动态注册上面已经叙述过了。下面咱们说说:静态注册(分:安卓8.0之前和安卓8.0之后)
    • 先在清单文件(AndroidManifest.xml)中,静态注册
            <!--在配置文件中:静态注册一个广播接收者-->
            <receiver android:name=".receiver.TestDemoReceiver">
                <!--定义一个意图过滤器来接收(监听)指定的action-->
                <intent-filter>
                    <!--可以配置系统的固定的时间类型。如:开关机广播、拨打电话广播等等-->
                    <!--<action android:name="android.intent.action.ACTION_CLOSE_SYSTEM_DIALOGS" />-->
                    <!--也可以配置自定义的 action(事件类型)-->
                    <action android:name="x.xx.xxx.无序" />
                </intent-filter>
            </receiver>
    
    • 发送一个无序广播(Android版本8.0之前 )
        Intent intent = new Intent();//获取 Intent 对象
        //使用隐式意图,为intent添加指定的广播事件类型
        intent.setAction("x.xx.xxx.无序");
        intent.putExtra("body", "我是数据");//封装数据
        this.sendBroadcast(intent);//发送广播
    
    • 发送一个无序广播(Android版本8.0之后 ,必须使用全类名方式)
            Intent intent = new Intent();
            intent.setAction("x.xx.xxx.无序");
            //该方式适用:给其他应用的广播接收者发送消息(指定应用的包名、指定类的全类名)
            //intent.setComponent(new ComponentName("包名", "包名.receiver.TestReceiver"));
            //intent.setClassName("包名", "包名.receiver.TestReceiver");
            //如果是给自身应用内广播接收者发送广播
            //intent.setComponent(new ComponentName(this, TestReceiver.class));
            intent.setClassName(this, "包名.receiver.TestReceiver");
            intent.putExtra("body", "我是数据");
            this.sendBroadcast(intent);
    

    有序广播

    • 类似于中央下发的红头文件,一级一级向下发送,中间如果接收失败,发送就会终止。
    • 发送过程中,可以终止。终止后,后续的接收者则无法接收(有一种特殊情况)。

    定义 4 个 广播接收者:模拟有序广播的接收

    //广播接收者:有序广播-1
    public class Test1Receiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String resultData = getResultData();
            //有序广播里终止广播
            //abortBroadcast();
            setResultData("国家发放补贴800");
            Toast.makeText(context, "省接收:"+resultData, Toast.LENGTH_SHORT).show();
        }
    }
    
    //广播接收者:有序广播-2
    public class Test2Receiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String resultData = getResultData();
            setResultData("国家发放补贴600");
            Toast.makeText(context, "市接收:"+resultData, Toast.LENGTH_SHORT).show();
        }
    }
    
    //广播接收者:有序广播-3
    public class Test3Receiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String resultData = getResultData();
            Toast.makeText(context, "县接收:"+resultData, Toast.LENGTH_SHORT).show();
        }
    }
    

    特殊的广播接收者:广播接收者(看成:监察者,用于模拟上述说的有序广播即便被中断,依然可以接收到广播消息的特例)

    //广播接收者:有序广播 最终接收者
    public class Test0Receiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String resultData = getResultData();
            Toast.makeText(context, "最终数据:"+resultData, Toast.LENGTH_SHORT).show();
        }
    }
    
    • 有序广播接收

    Android版本8.0之前(不包含android8.0版本),只需要在清单文件中静态配置就可以。

    • 在配置文件中(AndroidManifest.xml),如果没有设置优先级(android:priority="XXX"),那么接收到广播的先后顺序会根据配置文件中书写的顺序产生变化,接收顺序会由上而下。这种接收顺序不可取,所以,为了避免这种情况,有序广播的接收者必须配置优先级,防止接收顺序错乱。
    • priority 的优先级:最高1000 —— 最低 -1000

    静态注册代码如下:

            <receiver android:name=".receiver.Test1Receiver">
                <intent-filter android:priority="1000">
                    <action android:name="x.xx.xxx.有序" />
                </intent-filter>
            </receiver>
    
            <receiver android:name=".receiver.Test2Receiver">
                <intent-filter android:priority="999">
                    <action android:name="x.xx.xxx.有序" />
                </intent-filter>
            </receiver>
    
            <receiver android:name=".receiver.Test3Receiver">
                <intent-filter android:priority="998">
                    <action android:name="x.xx.xxx.有序" />
                </intent-filter>
            </receiver>
    

    从Android版本8.0开始,由于Google对清单文件中静态注册广播接收者做了限制,只能通过动态注册的方式,实现有序广播。

    动态注册代码如下:

            IntentFilter filter2 = new IntentFilter();
            filter2.addAction("x.xx.xxx.有序");
            filter2.setPriority(999);
            this.registerReceiver(new Test2Receiver(), filter2);
    
            IntentFilter filter1 = new IntentFilter();
            filter1.addAction("x.xx.xxx.有序");
            filter1.setPriority(1000);
            this.registerReceiver(new Test1Receiver(), filter1);
    
            IntentFilter filter3 = new IntentFilter();
            filter3.addAction("x.xx.xxx.有序");
            filter3.setPriority(998);
            this.registerReceiver(new Test3Receiver(), filter3);
    

    发送一个有序广播

    Test0Receiver:是定义的一个特殊的广播接收者,在发送有序广播的时候以参数的形式传递进去

    • 若在有序广播传递过程中,假如:A 中止了广播的传递。Test0Receiver 依然会接收到数据。接收到的是: A 发送的数据(如果 A 没有发送数据,那么Test0Receiver接收到的数据就和 A 接收到的数据相同)。
    • 若在有序广播传递过程中,假如:广播的传递没有被中止, C作为最后一个接收对象。如果 C没有继续发送数据,那么Test0Receiver 接收到的数据 和 C 接收到的数据一样。如果C有继续发送数据,那么Test0Receiver 接收到的数据就是C发送的数据
            Intent intent = new Intent();
            intent.setAction("x.xx.xxx.有序");
            //发送一个有序广播
            //sendOrderedBroadcast(Intent intent,  //发送广播的意图对象(可以携带数据)
            //          String receiverPermission, //接收权限(如果为空,则不需要权限)
            //          BroadcastReceiver resultReceiver, //广播接收者对象(自己创建的最终的广播接收者,可以无须在清单文件中配置,也会接收到广播 )
            //          Handler scheduler,         //若传null,则默认是在主线程中
            //          int initialCode,           //初始化的一个值。可默认:Activity.RESULT_OK
            //          String initialData,        //可发送的初始化数据(相当于一条广播数据)。可为null
            //          Bundle initialExtras)      //可绑定数据传递(Intent对象也可以,所以可为null)
            this.sendOrderedBroadcast(intent, null, new Test0Receiver(), null, Activity.RESULT_OK, "国家发放补贴1000", null);
    
  • 相关阅读:
    macOS 常用配置
    maven 常用配置
    log4j(1.x)最全配置!!!
    Python2 中 input() 和 raw_input() 的区别
    用 Maven 构建 Java-Scala 混合项目
    trim() 的秘密
    【目录】一起来学 Kafka 吧
    Spring in Action.4th
    Hibernate快速入门
    html2canvas 跨域图片无法正常加载问题解决办法
  • 原文地址:https://www.cnblogs.com/io1024/p/11558401.html
Copyright © 2020-2023  润新知