Broadcast

1,642 阅读4分钟

特点:是一个典型的发布-订阅模式,发送方不关心接收方是否接到数据,也不关系接收方如何处理数据

广播指定相应的action等信息,每个接收器根据intentFilter过滤出自己要接收的广播

注意:

  • 安卓7以上系统,在清单中声明接收器通常不起作用
  • 当BroadcastReceiver在onReceive()运行时会被视为前台进程。结束onReceive()时BroadcastReceiver将不再是活跃状态,会被设为低优先级进程非常容易被杀掉。通常不要对广播接收器进行耗时操作,如果非要进行耗时操作,那么可以开启子线程。

广播分类

普通广播

优点:消息传递效率高

缺点:

  • 执行顺序不确定
  • 接受者无法将处理的结果传递给下一个接受者
  • 无法中断传播,直到没有与之匹配的广播接收器为止

发送广播:

sendBroadcast(new Intent("hello"));

有序广播

优点:

  • 所有广播接收器按优先级顺序执行,通过intent-filer的android:priority属性
  • 当前广播接收器可使用setResult()函数将结果传递给下一个广播接收器,通过getResult()函数获取上一个广播接收器返回的结果
  • 可以调用abortBroadcast()函数丢弃该广播,使其不再传送给其他广播接收器

显然有序广播优化了普通广播的缺点

设置广播优先级

mHelloBroadcastReceiver = new HelloBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter("hello");
intentFilter.setPriority(50);
registerReceiver(mHelloBroadcastReceiver,intentFilter);

发送广播

sendOrderedBroadcast(new Intent("hello"),null);

本地广播

上述的广播都是全局的,如果不需要向应用程序外部的组件发起广播,可以使用本地广播,提高效率。

LocalBroadcastManager可以实现限于应用内的广播

//注册广播
LocalBroadcastManager.getInstance(this).registerReceiver(@NonNull BroadcastReceiver receiver,
            @NonNull IntentFilter filter)

//注销广播
LocalBroadcastManager.getInstance(this).unregisterReceiver(@NonNull BroadcastReceiver receiver)

//发送异步广播
LocalBroadcastManager.getInstance(this).sendBroadcast(@NonNull Intent intent)

//发送本地广播
LocalBroadcastManager.getInstance(this).sendBroadcastSync(@NonNull Intent intent)

sticky广播

通过Context.sendStickyBroadcast(Intent intent)发送。发送粘性广播还需要BROADCAST_STICKY权限:

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

特点:

  • 此广播会滞留,即使已经有广播接收器处理了该广播,此广播认可继续被接受。直到调用removeStickyBroadcast()函数

BroadcastReceiver

当接受到广播时,会调用onReceive()方法。

public class HelloBroadcastReceiver extends BroadcastReceiver {

	private static final String TAG = HelloBroadcastReceiver.class.getSimpleName();

	@Override
	public void onReceive(Context context, Intent intent) {
		Log.e(TAG,"hello");
	}
}

BroadcastReceiver注册方式

静态注册

<receiver
	android:name=".components.broadcast.HelloBroadcastReceiver"
	android:exported="false">
	<!--intent过滤器指定接收者订阅的广播操作。-->
	<intent-filter>
		<action android:name="hello"/>

	</intent-filter>
</receiver>

exported为false表示接收方不接受来自应用外的广播

注意:

当应用程序关闭后如果有信息广播来,程序也会被系统调用,自己运行。

静态注册的接收器必须是独立外部类或者静态内部类,因为非静态内部类依赖外部类的实例

动态注册

registerReceiver(new HelloBroadcastReceiver(),new IntentFilter("hello"));

当用来注册的 Activity 关掉后,广播也就失效了。

取消注册

unregisterReceiver(android.content.BroadcastReceiver)

这里的注册和取消注册是针对非本地广播的。

本地广播和非本地广播区别

BroadcastReceiver,用于应用之间的传递消息,通过binder实现

LocalBroadcastReceiver ,用于应用内部传递消息,通过handler实现

扩展

安全问题

广播会有如下隐患:

别的程序监听我们的广播,造成数据泄露
别的程序冒充我们的程序发送广播
频繁发送广播,启动广播接收器,甚至崩溃

解决办法:

指定应用自己的权限,拥有该权限的应用才能接受广播

发送方发送广播时指定权限,接收方注册接收器时说明权限

详情见自定义权限

数据限制

Intent在传递数据时是有大小限制的,大约限制在1MB之内
你用Intent传递数据,实际上走的是跨进程通信(IPC),跨进程通信需要把数据从内核copy到进程中,每一个进程有一个接收内核数据的缓冲区,默认是1M;如果一次传递的数据超过限制,就会出现异常。

实际运用

常用于接受系统广播,例如:进程拉活

广播,eventbus,handler的区别

https://blog.csdn.net/sdsxtianshi/article/details/80598165
待学习,盲点

注意

安卓7以上系统,在清单中声明接收器通常不起作用
BroadcastReceiver在onReceive()运行时会被视为前台进程。
BroadCastReceiver发生ANR的时间是10秒

参考:developer.android.com/guide/compo…