Broadcast广播-Android
Posted hequnwang10
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Broadcast广播-Android相关的知识,希望对你有一定的参考价值。
一、Broadcast
1、定义
在 android 中,Broadcast 是一种在应用程序之间传输信息的机制,要发送的广播内容是一个 Intent,这个 Intent 中可以携带我们要传送的数据。(数据小于1MB)
-
普通广播Normal Broadcast:异步执行的广播,所有接收者在同一时刻收到这条广播消息。效率高,没有先后顺序,无法截断。属于全局广播。调用 sendBroadcast()发送,最常用的广播。
-
有序广播Ordered Broadcast:同步执行的广播,发出去的广播会被广播接收者按照顺序接收,广播接收者按照Priority属性值从大-小排序,Priority属性相同者,动态注册的广播优先,广播接收者还可以选择对广播进行截断和修改。调用sendOrderedBroadcast()发送。
-
本地广播Local Broadcast:App应用内广播可理解为一种局部广播,广播的发送者和接收者都同属于一个App。相比于全局广播(普通广播),App应用内广播优势体现在:安全性高 & 效率高。对于LocalBroadcastManager方式发送的应用内广播,只能通过LocalBroadcastManager动态注册,不能静态注册。调用sendBroadcast发送。
2、用途
- 广播实现了不同程序之间的信息传输与共享,只要和发送广播的 action 相同的接收者,都能接收到这个广播。典型的应用就是 android 自带的短信,电话等等广播,只要我们实现了他们的 action 的广播,那么我们就能接收他们的数据了,以便做出一些处理。比如说拦截系统短信,拦截骚扰电话等。
- 作为通知的作用,比如在 Service 中要通知主程序、更新主程序的 UI 等,因为 Service 是没有界面的,所以不能直接获得主程序中的控件,这样我们就只能在主程序中实现一个广播接收者专门用来接收service发过来的数据和通知了。
3、使用场景
- 同一app内部的同一组件内的消息通信(单个或多个线程之间)(可用handler解决);
- 同一app内部的不同组件之间的消息通信(单个进程)(可用EventBus);
- 同一app具有多个进程的不同组件之间的消息通信;
- 不同app之间的组件之间的消息通信;
- Android系统在特定情况下与App之间的消息通信。
二、注册广播接收 (静态和动态)
1、两种注册方法的区别:
- 动态注册的接收器必须要在程序启动之后才能接收到广播;
- 静态注册的接收器即便程序未启动也能接收到广播,比如想接收到手机开机完成后系统发出的广播就只能用静态注册了。
2、动态注册
自定义类继承 BroadcastReceiver,然后重写具体实现onReceive()。在代码中调用registerReceiver()注册来进行广播的注册。必须在 onDestroy 中调用unregisterReceiver()方法,否则会引起内存泄露。特点是:不常驻,跟随组件的生命变化,组件结束,广播结束。在组件结束前,需要先移除广播,否则容易造成内存泄漏。
下面的代码包含了动态注册和有序广播的使用,直接放在一起了
BroadcastMainActivity.java
public class BroadcastMainActivity extends AppCompatActivity
public static final String staticAction = "My_Broadcast";
//动态注册
public static final String dynamicAction = "Dynamic_Broadcast";
private MyReceiver myDynamicReceiver;
//有序广播
public static final String orderAction = "Order_Broadcast";
private MyOrderReceiverOne orderReceiverOne; // 自定义接收者one
private MyOrderReceiverTwo orderReceiverTwo; // 自定义接收者two
private MyOrderReceiverThree orderReceiverThree; // 自定义接收者three
public static final String localAction = "Local_Broadcast";
private LocalBroadcastManager localBroadcastManager;
private LocalReceiver localReceiver;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_broadcast_main);
initDynamicReceiver();
initOrderReceiver();
private void initOrderReceiver()
orderReceiverOne = new MyOrderReceiverOne();
//设置优先级
IntentFilter intentFilter1 = new IntentFilter();
intentFilter1.addAction(orderAction);
intentFilter1.setPriority(400);
registerReceiver(orderReceiverOne,intentFilter1);
orderReceiverTwo = new MyOrderReceiverTwo();
IntentFilter intentFilter2 = new IntentFilter();
intentFilter2.addAction(orderAction);
intentFilter2.setPriority(200);
registerReceiver(orderReceiverTwo,intentFilter2);
orderReceiverThree = new MyOrderReceiverThree();
IntentFilter intentFilter3 = new IntentFilter();
intentFilter3.addAction(orderAction);
intentFilter3.setPriority(300);
registerReceiver(orderReceiverThree,intentFilter3);
//动态广播接收者
private void initDynamicReceiver()
myDynamicReceiver = new MyReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(dynamicAction);
registerReceiver(myDynamicReceiver,intentFilter);
//发送广播 静态注册广播 -- 无效
public void btn_click_send(View view)
Intent intent = new Intent();
intent.setAction(staticAction);
sendBroadcast(intent);
//发送广播 动态注册广播
public void btn_click_sendbydynamic(View view)
Intent intent = new Intent();
intent.setAction(dynamicAction);
sendBroadcast(intent);
//注册完成后要解注册
@Override
protected void onDestroy()
super.onDestroy();
unregisterReceiver(myDynamicReceiver);
unregisterReceiver(orderReceiverOne);
unregisterReceiver(orderReceiverTwo);
unregisterReceiver(orderReceiverThree);
//接收4:在onDestroy中取消注册
localBroadcastManager.unregisterReceiver(localReceiver);
//发送有序广播
public void btn_click_ordersend(View view)
Intent intent = new Intent();
intent.setAction(orderAction);
// sendBroadcast(intent);
sendOrderedBroadcast(intent,null);
public void btn_click_localsend(View view)
//发送1:实例化localBroadcastManager
localBroadcastManager = LocalBroadcastManager.getInstance(BroadcastMainActivity.this);
//接收1:实例化IntentFilter和接收器LocalReceiver
IntentFilter intentFilter = new IntentFilter();
localReceiver = new LocalReceiver();
//接收2:设置广播接收类型
intentFilter.addAction(localAction);
localBroadcastManager.registerReceiver(localReceiver,intentFilter);
Intent intent = new Intent(localAction);
localBroadcastManager.sendBroadcast(intent);
activity_broadcast_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".BroadcastDemo.BroadcastMainActivity">
<TextView
android:id="@+id/text"
android:text="广播接收示例"
android:textSize="22sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#FF5722"
/>
<Button
android:text="发送广播消息"
android:onClick="btn_click_send"
android:textSize="22sp"
android:textColor="@color/orange"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<Button
android:text="发送动态广播消息"
android:onClick="btn_click_sendbydynamic"
android:textSize="22sp"
android:textColor="@color/orange"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<Button
android:text="发送有序广播消息"
android:onClick="btn_click_ordersend"
android:textSize="22sp"
android:textColor="@color/orange"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<Button
android:text="发送本地广播消息"
android:onClick="btn_click_localsend"
android:textSize="22sp"
android:textColor="@color/orange"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
MyReceiver.java
public class MyReceiver extends BroadcastReceiver
public static final String TAG = "MyReceiver";
@Override
public void onReceive(Context context, Intent intent)
//TO DO
Log.i(TAG,"自定义广播接收者,接收到了消息");
Log.i(TAG, intent.getAction());
MyOrderReceiverOne.java
public class MyOrderReceiverOne extends BroadcastReceiver
public static final String TAG = "MyOrderReceiverOne";
@Override
public void onReceive(Context context, Intent intent)
//TO DO
Log.i(TAG,"有序广播接收者,接收到了消息");
Log.i(TAG, intent.getAction());
MyOrderReceiverTwo.java
public class MyOrderReceiverTwo extends BroadcastReceiver
public static final String TAG = "MyOrderReceiverTwo";
@Override
public void onReceive(Context context, Intent intent)
//TO DO
Log.i(TAG,"有序广播接收者,接收到了消息");
Log.i(TAG, intent.getAction());
MyOrderReceiverThree.java
public class MyOrderReceiverThree extends BroadcastReceiver
public static final String TAG = "MyOrderReceiverThree";
@Override
public void onReceive(Context context, Intent intent)
//TO DO
Log.i(TAG,"有序广播接收者,接收到了消息");
Log.i(TAG, intent.getAction());
LocalReceiver.java
public class LocalReceiver extends BroadcastReceiver
public static final String TAG = "LocalReceiver";
@Override
public void onReceive(Context context, Intent intent)
//TO DO
Log.i(TAG,"本地广播接收者,接收到了消息");
Log.i(TAG, intent.getAction());
三、广播内部实现机制
- 自定义广播接收者 BroadcastReceiver,并复写 onRecvice();
- 通过 Binder 机制向 AMS(Activity Manager Service) 注册广播;
- 通过 Binder 机制向 AMS(Activity Manager Service) 发送广播。
- AMS 查找符合相应条件(IntentFilter/Permission等)的BroadcastReceiver,将广播发送到BroadcastReceiver 所在的消息循环队列中。
- BroadcastReceiver 所在消息队列拿到此广播后,回调它的 onReceive() 方法。
四、本地广播 LocalBroadcastManager
Android中的广播可以跨App直接通信(exported对于有intent-filter情况下默认值为true)
问题:
- 其他App针对性发出与当前App intent-filter相匹配的广播,由此导致当前App不断接收广播并处理;
- 其他App注册与当前App一致的intent-filter用于接收广播,获取广播具体信息(即会出现安全性 & 效率性的问题)。
解决方案:使用App应用内广播(Local Broadcast)
- App应用内广播可理解为一种局部广播,广播的发送者和接收者都同属于一个App。
- 相比于全局广播(普通广播),App应用内广播优势体现在:安全性高 & 效率高;
特点:
- 发送的广播只能够在自己 App 的内部传递,不会泄露给其他 App,确保隐私数据不会泄露;
- 广播接收器只能接收来自本 App 发出的广播;
- 其他App也无法向你的App发送该广播,不用担心其他App会来搞破坏;
- 比系统的全局广播更加高效。
内部实现原理:
- LocalBroadcastManager 高效的原因主要因为它内部是通过Handler实现的,它的sendBroadcast()方法是通过handler()发送一个Message实现的。
- 相比系统广播是通过Binder实现的,本地广播会更加高效。别人应用无法向自己的App发送广播,而自己App发送的广播也不会离开自己的App。
- LocalBroadcastManager 内部协作主要是靠两个Map集合:mReceivers和mActions,当然还有一个List集合mPendingBroadcasts,主要是存储待接收的广播对象。
五、BroadcastReceiver 和 LocalBroadcastReceiver 区别
- BroadcastReceiver 是跨应用广播,利用Binder机制实现。
- LocalBroadcastReceiver 是应用内广播,利用Handler实现,利用了IntentFilter的match功能,提供消息的发布与接收功能,实现应用内通信,效率比较高。
- LocalBroadcastReceiver不能静态注册,只能采用动态注册的方式。
在发送和注册的时候采用,LocalBroadcastManager的sendBroadcast方法和registerReceiver方法
六、广播传输的数据是否有限制,是多少,为什么要限制?
-
Broadcast广播通过Intent来传输数据,而Intent的数据大小限制为小于1MB,如果大于等于1MB都会出现异常。
-
Intent携带信息的大小其实是受Binder限制,Binder传递缓存有一个限定大小,通常是1Mb。但同一个进程中所有的传输共享缓存空间。多个地方在进行传输时,即时它们各自传输的数据不超出大小限制,TransactionTooLargeException异常也可能会被抛出。
以上是关于Broadcast广播-Android的主要内容,如果未能解决你的问题,请参考以下文章
Android四大组件-Broadcast Receiver
Android 7.0 ActivityManagerService 广播(Broadcast)相关流程分析
Android面试收集录2 Broadcast Receiver详解