• 将Android进行到底之广播(Broadcast)


    在这里插入图片描述


    前言

    在VR的开发中,Android的广播扮演着很重要的角色,因为我们的VR开发中显示的Launcher界面通常是使用Unity3d开发的,所以很多时候当我们想要在VR眼镜中,去调试我们的功能的时候。想象下,以前我们是直接在Android上显示,在Activity中写个Button就行了,但是遇到咱们到了VR眼镜中,要调试的时候,就不能直接在眼镜中让Unity3d的同事给你加个调试的按钮吧,人家也没那时间给你加

    下图就是使用Unity3d渲染出来的Launcher 界面

    在这里插入图片描述


    就算人家给你加了,但是假如这时候操作的手柄还没就位你咋去点击VR眼镜里面的按钮呢?所以这时候广播的作用就体现出来了。我们可以通过发广播的形式去调试我们写的功能。广播不仅有这些作用还有好多妙用,让我们一起去看看吧。


    一、广播的介绍

    1.广播的概念

    在Android中,广播是一种广泛应用在应用程序之间传输信息的机制,我们发送的广播内容是一个Intent,在这个Intent中,我们可以携带我们要发送的数据。举个例子,Android系统会在发生各种系统事件的时候发送广播,例如:系统启动了,电量改变了,USB设备插入拔出。设备充电时等等。不仅如此,我们还可以通过发送自定义的广播来通知其他应用,让他们做些事情。比如当一些新数据已经下载完了后,可以通过自定义广播通知其他应用。

    2.广播的分类

    在这里插入图片描述

    系统会在发生各种系统事件的时候自动发送广播,比如当系统进入和退出飞行模式的时候。系统广播会被发送给所有统一接收相关事件的应用,广播消息本身会被封装在一个Intent对象中 ,该对象会有一个标识
    (例如:android.intent.action.AIRPLANE_MODE)这个Intent可能还包含绑定其extra字段中的附加信息。如飞行模式intent包含布尔值extra来标识是否已经开启了飞行模式。

    在App内监听这些广播也非常简单,咱们接着往下看

    3.广播的使用

    (1)接收广播

    Android应用可以通过两种方式接收广播:分别是清单文件(AndroidManifest.xml)中声明的接收器(也叫静态注册),和上下文注册的接收器(也叫动态注册),咱们分别来看下两种注册方式。

    1.在清单文件(AndroidManifest.xml)中声明的接收器

    step1:创建一个类继承自BroadcastReceiver,并实现onReceive(Context,Intent)方法。
    代码如下:

     public class MyBroadcastReceiver
      extends BroadcastReceiver {
                @Override
                public void onReceive(Context context,
                 Intent intent) {
                String action = intent.getAction();
                if(action.equls("android.intent.action.BOOT_COMPLETED"){
                 //这样做是为了筛选出我们
                //想要监听的广播,然后做咱们的处理逻辑
                doSomeThings();
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    注意:广播时运行在主线程,所以不能在onReceive()方法中做耗时操作,否则可能会引起ANR

    step2:在清单文件中声明广播接收器

     <receiver android:name=".MyBroadcastReceiver"  android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
                <action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
            intent-filter>
        receiver>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    声明广播接收器还可以使用上下文的方式,也就是咱们平常说的动态注册的方式,代码如下:

     BroadcastReceiver br = new MyBroadcastReceiver();
     IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.android.intent.action.BOOT_COMPLETED);
            this.registerReceiver(br, filter);
    
    • 1
    • 2
    • 3
    • 4

    注意:只要注册的上下文有效,那么使用该上下文注册的接收器就会收到广播,例如,如果在Activity的上下文中注册,只要Activity没有被销毁,就会收到广播。如果是在Application的上下文中注册。只要应用还活着,没有被杀死,就可以接收到广播

    step3:停止接收广播,当我们需要停止接收广播的时候,需要调用unregisterReceiver(android.content.BroadcastReceiver)方法停止接收广播,一般我们都会在上下文不在有效的时候注销广播接收器。比如:在Activity销毁时,在activity的onDestroy()回调中注销掉广播。

    注意:我们注册和销毁接收器的位置需要特别小心。我们一般都是在Activity的onCreate()方法中注册广播,在onDestroy()中注销广播,但是假如你是在Activity的onResume()方法中注册的广播,则需要在onPause中注销广播,防止多次注册接收器

    (2)发送广播

    在前面的广播种类中我们提到了三种广播,所以发送广播的时候也分三种方式。分别是:
    有序广播:sendOrderedBroadcast(Intent, String)
    无序广播:sendBroadcast(Intent)
    本地广播:LocalBroadcastManager.sendBroadcast

    使用的方式很统一,除了调用的函数名不同,其他大概相同:代码如下:

      Intent intent = new Intent();
        intent.setAction("com.example.broadcast.MY_NOTIFICATION");
        intent.putExtra("data","Notice me senpai!");
        sendBroadcast(intent);
    
    • 1
    • 2
    • 3
    • 4

    注意: 广播消息封装在 Intent 对象中。Intent 的操作字符串必须提供应用的 Java 软件包名称语法,并唯一标识广播事件。我们可以使用 putExtra(String, Bundle) 向 intent 添加加其他信息。

    二、广播的妙用

    1.跨应用通信

    这个最简单了,但是需要注意的是这里的跨应用通信指的可不是大数据量的通信哈,因为广播是挺耗性能的,所以尽量用来做些通知的事情。打个比方。广播相当于咱们在人群中大声喊出某条命令,确保所有人能听到,类似古代的传令兵,只能是喊有限的次数,可不能让人大声把兵法读给大家听吧。谁受得了呀。广播也是如此,咱们应该尽量让它做些短暂的命令通知就可以了

    2.调试程序

    广播调试程序可谓是一个字,爽。如何利用广播来调试程序呢?我们可以利用Android的调试工具adb来发送自定义的广播,在我们要调试的界面中写上广播接收器。然后接收到广播的时候执行咱们需要调试的内容就行了。

    举个例子吧,假如咱们写了一个投屏的功能,使用广播的方式如何调试呢?以前的话咱们可能会写个按钮,点击的时候开始去投屏,这样很麻烦,在你自己的界面中还好,遇到我说的连接VR眼镜的时候,是不是就傻眼了。所以我们来看下利用广播如何做:

    step1: 在要调试的类中去写上广播接收器:

    private final static String ACTION_SAVE_DATA = 
        "action.save.data";
        private final static String ACTION_START_CAST = 
        "action.start.cast";
     private final BroadcastReceiver broadcastReceiver = new 
     BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent 
            intent) {
                String action = intent.getAction();
                Log.d(TAG,"ACTION==============saveData==>>"
                 + action);
                if(action.equals(ACTION_SAVE_DATA)){
                    Log.d(TAG,"save success====================>");
                    RtpReadAndPush.getInstance().saveData();
                }
    
                if(action.equals(ACTION_START_CAST)){
                    Log.d(TAG,"ACTION === START CAST==>" + 
                    action);
                    startCast(mCurrentLeLinkServiceInfo);
                }
            }
        };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    step2:在onCreate()方法中注册它

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_cast);
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction(ACTION_SAVE_DATA);
            intentFilter.addAction(ACTION_START_CAST);
            registerReceiver(broadcastReceiver,intentFilter);
            }
            
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    step3:使用Adb发送自定义广播

    adb shell am broadcast -a "action.start.cast"
    
    • 1

    step4:别忘了注销广播

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

    3.配合service做容错处理

    配合service做容错处理在咱们的前面也讲到了,其实很简单,因为service在配合AIDL做进程间通信的时候,通常都作为服务端,为客户端提供服务,假如服务端一直活着的情况下,客户端不出意外的话是百分百能够连接到服务端的,但是假如服务端意外死掉了,客户端这时候是不知道的,已经连接的客户端也不会重新去连接服务端,因为他们不知道服务端死掉了。所以这时候广播的作用就是告诉所有连接它的客户端,我发生异常重启了,你们重现连接下我再进行其他工作。

    三、广播的注意事项

    1.Android各版本的广播区别

    随着 Android 平台的发展,它会不定期地更改系统广播的行为方式。如果应用以 Android 7.0(API 级别 24)或更高版本为目标平台,或者安装在搭载 Android 7.0 或更高版本的设备上,需要注意下面的版本变化:

    Android 7.0
    Android 7.0(API 级别 24)及更高版本不发送以下系统广播:
    ACTION_NEW_PICTURE、ACTION_NEW_VIDEO
    此外,以 Android 7.0 及更高版本为目标平台的应用必须使用 registerReceiver(BroadcastReceiver, IntentFilter) 注册 CONNECTIVITY_ACTION 广播。无法在清单中声明接收器。

    Android 8.0
    从 Android 8.0(API 级别 26)开始,系统对清单声明的接收器施加了额外的限制。如果应用以 Android 8.0 或更高版本为目标平台,那么对于大多数隐式广播(没有明确针对咱们应用的广播),不能使用清单来声明接收器。当用户正在活跃地使用的咱们开发的应用时,仍可使用动态注册的接收器。

    Android 9
    从 Android 9(API 级别 28)开始,NETWORK_STATE_CHANGED_ACTION 广播不再接收有关用户位置或个人身份数据的信息。此外,如果您的应用安装在搭载 Android 9 或更高版本的设备上,则通过 WLAN 接收的系统广播不包含 SSID、BSSID、连接信息或扫描结果。要获取这些信息,请调用 getConnectionInfo()。

    2.不要滥用广播

    一般来说,广播可作为跨应用和普通用户流之外的消息传递系统。但是,您必须小心,不要滥用在后台响应广播和运行作业的机会,因为这会导致系统变慢

    总结

    好了,以上就是今天的内容,篇幅有点长,希望能对正在阅读这篇文章的你带来收获,有疑问的可以在评论区一起交流。本人很热爱计算机,也很热爱我现在的职业。如果你和我志同道合,咱们一起共同交流,共同进步。

  • 相关阅读:
    为什么香港服务器最适合海外建站使用
    可爱女生图片到期了,怎么办?当前是把Python爬虫升级到【可爱头像】站
    带你从源码看看webpack 的构建流程(上)?
    YOLOv5-seg数据集制作、模型训练以及TensorRT部署
    每天一个设计模式之解释器模式(Interpreter Pattern)
    当添加一个键值对元素时,HashMap发生了什么?
    第三天:js中的事件提高篇(事件流,事件对象,事件委托深层次理解)
    临门一脚踢不进?面试官就是不要我?程序员面试隐藏加分项你做对了吗?!
    「JVS低代码开发平台」关于逻辑引擎的触发讲解
    「学习笔记」CDQ分治
  • 原文地址:https://blog.csdn.net/zxj2589/article/details/127823804