• 第五章 详解广播机制(Broadcast Receiver)


    一、广播机制简介

    发送广播:Intent

    接收广播:广播接收器(Broadcast Receiver)

    Android广播分为两种类型:标准广播和有序广播

    标准广播:异步执行的广播,所有的广播接收器会在同一时刻接收到的广播

    有序广播:同步执行的广播,优先级高的广播接收器先收到广播,并且可以截断广播

    二、接收系统广播

    注册广播的方式有两种:在代码中注册(动态注册)和在AndroidManifest.xml5中注册(静态注册)

    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_CHANGE");
            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) {
                Toast.makeText(context, "network changes", Toast.LENGTH_SHORT).show();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    在这里插入图片描述

    2.静态注册实现开机启动

    1. 创建一个xx类继承BroadCastReceiver

    2. 在AndroidManifest.xml注册静态的广播接收器

    3. 在AndroidManifest.xml添加响应广播的action,并且声明该广播的权限

    三、发送自定义广播

    1.发送标准广播

    1. 通过静态注册定义一个广播接收器用于接收自定义的广播

    2. 首先构建一个Intent对象,并把要发送的广播的值传入。再调用ContextWrapper的sendBroadcast()方法将广播发送出去

    3. 在 Android 8.0 之后,对于广播的发送与接收变严格了,需要加入Component参数

    4. 或者按照《第一行代码-第三版》的方法解决:在Android 8.0系统之后,静态注册的BroadcastReceiver是无法接收隐式广播的,而默认情况下我们发出 的自定义广播恰恰都是隐式广播。因此这里一定要调用setPackage()方法,指定这条广播是 发送给哪个应用程序的,从而让它变成一条显式广播,否则静态注册的BroadcastReceiver将 无法接收到这条广播。 注意只有静态注册才写,动态注册不需要写

    Button button = findViewById(R.id.button);
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent("com.jack.broadcasttest.MY_BROADCAST");
            intent.setPackage(getPackageName());
            //intent.setComponent(new ComponentName("com.jack.broadcasttest","com.jack.broadcasttest.MyBroadcastReceiver"));
            sendBroadcast(intent);
        }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.发送有序广播

            <receiver
                android:name=".AnotherBroadcastReceiver"
                android:enabled="true"
                android:exported="true">
                <intent-filter>
                    <action android:name="com.jack.broadcasttest.MY_BROADCAST" />
                intent-filter>
            receiver>
            <receiver
                android:name=".MyBroadcastReceiver"
                android:enabled="true"
                android:exported="true">
                <intent-filter>
                    <action android:name="com.jack.broadcasttest.MY_BROADCAST" />
                intent-filter>
            receiver>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    再注册一个静态接收广播,发现两个receiver都接收到自定义广播,并且和静态注册的顺序相关


            Button button = findViewById(R.id.send_broadcast);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent("com.jack.broadcasttest.MY_BROADCAST");
                    intent.setPackage(getPackageName());
                    //sendOrderedBroadcast()方法接收两个参数:第一个 参数仍然是Intent;第二个参数是一个与权限相关的字符串,这里传入null就行了。 
                    sendOrderedBroadcast(intent,null);
                }
            });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
            <receiver
                android:name=".AnotherBroadcastReceiver"
                android:enabled="true"
                android:exported="true">
                <intent-filter>
                    <action android:name="com.jack.broadcasttest.MY_BROADCAST" />
                intent-filter>
            receiver>
            <receiver
                android:name=".MyBroadcastReceiver"
                android:enabled="true"
                android:exported="true">
                //通过android:priority属性设置优先级
                <intent-filter android:priority="100">
                    <action android:name="com.jack.broadcasttest.MY_BROADCAST" />
                intent-filter>
            receiver>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    public class MyBroadcastReceiver extends BroadcastReceiver {
     
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show();
            //abortBroadcast()方法表示将广播截断
            abortBroadcast();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    实测 MyBroadcastReceiver可以把广播截断

    五、广播的最佳实践—实现强制下线功能

    发送自定义广播:

    public class MainActivity extends BaseAcitvity {
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button send = findViewById(R.id.send_forceOffline);
            send.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent intent = new Intent("com.jack.broadcastreceiverbest.FORCE_OFFLINE");
                    sendBroadcast(intent);
                }
            });
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    注册一个动态广播接收器:

    public class BaseAcitvity extends AppCompatActivity {
     
        private ForceOfflineReceiver forceOfflineReceiver;
     
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ActivityCollector.addActivity(this);
        }
     
        @Override
        protected void onResume() {
            super.onResume();
            IntentFilter filter = new IntentFilter();
            filter.addAction("com.jack.broadcastreceiverbest.FORCE_OFFLINE");
            forceOfflineReceiver = new ForceOfflineReceiver();
            registerReceiver(forceOfflineReceiver,filter);
        }
     
        @Override
        protected void onPause() {
            super.onPause();
            unregisterReceiver(forceOfflineReceiver);
        }
     
        @Override
        protected void onDestroy() {
            super.onDestroy();
            ActivityCollector.removeActivity(this);
        }
     
        class ForceOfflineReceiver extends BroadcastReceiver {
     
            @Override
            public void onReceive(Context context, Intent intent) {
                AlertDialog.Builder builder = new AlertDialog.Builder(BaseAcitvity.this);
                builder.setTitle("Warning");
                builder.setMessage("You are forced to be offline.Please try to login again");
                builder.setCancelable(false);
                builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        ActivityCollector.finishAll();
                        Intent intent = new Intent(context, LoginActivity.class);
                        //注意这里的写法,context去掉也行,或者改成BaseActivity.super也行
                        //为什么context也行呢,查看源码startActivity()是一个抽象方法呀?因为Context类也是一个抽象类,既然有实例context,必然是通过多态间接实现父类的实例化,那么调用的方法肯定是子类已经实现的方法
                        context.startActivity(intent);
                    }
                });
                builder.show();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
  • 相关阅读:
    项目相互依赖调用解决方法两种方法
    蓝牙协议文档下载
    2022 年全球十大最佳自动化测试工具
    借助cpolar 和大家分享有趣的照片 1 (在本地电脑上部署piwigo网页)
    【Java编程进阶之路--程序流程】
    【pytorch】目标检测:一文搞懂如何利用kaggle训练yolov5模型
    Linux-常见命令(三)
    【笔记篇】07基础数据中心——之《实战供应链》
    leetcode刷题日记:168. Excel Sheet Column Title(Excel表列名称)
    怎么解决MySQL 8.0.18 大小写敏感问题
  • 原文地址:https://blog.csdn.net/weixin_61653908/article/details/134357020