Android-BroadcastReceiver(广播接收器)专题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010782846/article/details/88988183

前言

Broadcast是Android四大组件中的组件之一,其发布-订阅的模式有利于四大组件间的通信,当我们需要在组件间通信或者进程间通信的时候,应考虑Broadcast。

BroadcastReceiver在Android中的应用场景

  • 接收系统发送的广播信息
  • 运用于组件间通信(应用内消息传递),比如Activity 和 Service 间的通信,可使用Broadcast(自定义广播)
  • 跨应用消息传递

BroadcastReceiver的注册分类

  • 通过清单文件注册广播(静态注册)
  • 通过上下文注册广播(动态注册)

通过清单文件注册广播(静态注册)

静态注册在应用程序关闭的时候也能接收广播,系统软件管理器会在安装应用程序的时候注册接收器,然后接收器作为应用程序的单独入口点,当系统发送广播的时候,会遍历所有接受的接收器,遇到没有启动应用程序的接收器,系统会先启动应用程序,再发送广播让接收器接收。

代码事例如下:

		<receiver android:name=".UstorageReceiver" android:exported="true">
           		 <intent-filter android:priority="1000">
                		<action android:name="android.intent.action.BOOT_COMPLETED"/>
                		<action android:name="android.intent.action.MEDIA_MOUNTED"/>
                		<action android:name="android.intent.action.MEDIA_UNMOUNTED" />
               		 	<action android:name="android.intent.action.MEDIA_REMOVED"/>
                	<data android:scheme="file"></data>
            	</intent-filter>
        </receiver>

静态注册在注册清单中进行注册,其中android:exported为true表示可以跨进程接收,为false则是只接收

通过上下文注册广播(动态注册)

动态注册要看上下文对象来决定订阅对象,如果是Application为上下文对象,那么在应用程序启动没有被关闭进程之前都能接收到广播;假如Activity为上下文对象那么广播只能在Activity处于注册区间内接收到,比如一般我们需要确保注册和反注册的时候生命周期要对应 onCreate()对应 onDestory(),onResume()对应onStop()。
注册和反注册代码例子如下:

注册

	BroadcastReceiver br = new MyBroadcastReceiver();
	IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
    filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
    this.registerReceiver(br, filter);

反注册

this.unregisterReceiver(br)

Broadcast如何发送

发送Broadcast的分类

  • 顺序广播
  • 正常广播
  • 粘性广播(API-21以上已移除,不建议使用)

顺序广播:每个顺序广播都有序号,按照序号逐个发送广播,优先的广播会把结果传递到下一个广播,以便在某些情况下可以对广播进行中止操作,通过设置android:priority 来定义顺序
正常广播:正常广播,也称无序广播,不可以中止广播,也不会把结果传递到下一个广播

如何发送Broadcast

顺序广播:

	Intent intent = new Intent();
	intent.setAction("com.example.broadcast.MY_NOTIFICATION");
	intent.putExtra("data","Notice me senpai!");
	String receiverPermission=“android.permission.SEND_SMS";
	sendOrderedBroadcast(intent);

Intent为意图对象;String

正常广播:

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

从安全性考虑如何防止别人侵入自己的广播代码

  • 为广播接收器添加权限
  • 使用LocalBroadcastManager代替BroadcastReceiver

为广播接收器添加权限

在进行跨应用消息传递到场景中, BroadcastReceiver发送和注册的时候,Android提供了API对发送者和实施者进行了一定的限制。

发送应用限制权限

sendBroadcast(Intent, String)
sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
例子如下:

	sendBroadcast(new Intent(“com.example.NOTIFY”), Manifest.permission.SEND_SMS);

当我们发送应用使用以上的API进行发送广播的时候,接收应用在注册清单中必须具备对应的Manifest.permission.SEND_SMS权限才能接收到发送应用发送过来到广播

	<uses-permission android:name="android.permission.SEND_SMS"/>

接收应用限制权限

registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
接收方应用:
注册分为清单文件注册和上下文注册两种方式;
清单注册例子如下:

<receiver android:name=".MyBroadcastReceiver"
          android:permission="android.permission.SEND_SMS">
    <intent-filter>
        <action android:name="android.intent.action.AIRPLANE_MODE"/>
    </intent-filter>
</receiver>

上下文注册如下:

IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
registerReceiver(receiver, filter, Manifest.permission.SEND_SMS, null );

为了能够发送信息到这些接收器,发送方的注册清单必须添加如下权限:

<uses-permission android:name="android.permission.SEND_SMS"/>

使用LocalBroadcastManager代替BroadcastReceiver

当我们仅仅运用Broadcast在应用内传递消息时,为了安全考虑使用权限限制会增加我们的代码量而显得没有必要,基于此Google 在support 包中引入了LocalBroadcastManager API 来发送广播,以支持应用内传递消息,而不需要做安全壁垒。
LocalBroadcastManager有如下优点:

  • 只能在应用内传递消息,不用担心因其他应用脚本恶意发送广播导致的安全漏洞
  • 相对于全局的重量级广播,LocalBroadcastManager的效率更高

LocalBroadcastManager创建对象:

LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance( this ) ;

LocalBroadcastManager注册广播接收器:

LocalBroadcastManager.registerReceiver( broadcastReceiver , intentFilter );

LocalBroadcastManager反注册广播接收器:

LocalBroadcastManager.unregisterReceiver( broadcastReceiver );

LocalBroadcastManager发送广播:

LocalBroadcastManager.sendBroadcast( intent ) ;

Broadcast版本兼容

在Android7.0以上的系统中。Google公司对广播7进行来一定的修改和优化,需要注意一些东西。

Android 9.0

  • NETWORK_STATE_CHANGED_ACTION广播不再提供个人用户位置和有关个人身份数据的信息
  • WI-FI的广播不再提供SSID、BSSID、连接信息和扫码结果,如果想要做类似的操作,请参考 getConnectionInfo()

Android 8.0

  • 系统对清单文件注册做了一些限制,大多数隐式广播只能通过上下文注册,而不能使用清单注册

Android 7.0

  • 删除ACTION_NEW_PICTUREACTION_NEW_VIDEO两种系统广播,当媒体产生变化时,Android7.0以上将不再发送这两个广播中的其中一个
  • CONNECTIVITY_ACTION广播仅能使用上下文注册,在清单文件中注册将不起任何作用

为什么我们不要滥用Broadcast

  • BroadcastReceiver作为在后台工作的组件,会消耗资源,影响手机用户体验。
  • 有更轻量级、更高效的应用内消息传递机制代替Broadcast,比如EventBus、RxBus、LocalBroadcastManager 等。

常见的一些系统广播例子

监控U盘拨入拨出,获取U盘路径

注意添加:android:scheme

  • android.intent.action.MEDIA_MOUNTED:sd卡被插入,且已经挂载
  • android.intent.action.MEDIA_UNMOUNTED:sd卡存在,但还没有挂载
  • android.intent.action.MEDIA_REMOVED:sd卡被移除
		<receiver android:name=".UstorageReceiver" android:exported="true">
            <intent-filter android:priority="1000">
                <action android:name="android.intent.action.MEDIA_MOUNTED"/>
                <action android:name="android.intent.action.MEDIA_UNMOUNTED" />
                <action android:name="android.intent.action.MEDIA_REMOVED"/>
                <data android:scheme="file"></data>
            </intent-filter>
        </receiver>

获取U盘的路径为:

intent.getData().getPath()

耳机插入拔出状态

Intent.ACTION_HEADSET_PLUG:android.intent.action.HEADSET_PLUG
获取状态

intent.getIntExtra("state", 0)

当state为零时,耳机未插入;当state为1时,耳机为已插入;

屏幕相关的信息改变时

Intent.ACTION_SCREEN_ON:开屏
Intent.ACTION_SCREEN_OFF:锁屏

猜你喜欢

转载自blog.csdn.net/u010782846/article/details/88988183