Broadcast广播-Android

Posted hequnwang10

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Broadcast广播-Android相关的知识,希望对你有一定的参考价值。

一、Broadcast

1、定义

android 中,Broadcast 是一种在应用程序之间传输信息的机制,要发送的广播内容是一个 Intent,这个 Intent 中可以携带我们要传送的数据。(数据小于1MB)

  1. 普通广播Normal Broadcast:异步执行的广播,所有接收者在同一时刻收到这条广播消息。效率高,没有先后顺序,无法截断。属于全局广播。调用 sendBroadcast()发送,最常用的广播。

  2. 有序广播Ordered Broadcast:同步执行的广播,发出去的广播会被广播接收者按照顺序接收,广播接收者按照Priority属性值从大-小排序,Priority属性相同者,动态注册的广播优先,广播接收者还可以选择对广播进行截断和修改。调用sendOrderedBroadcast()发送。

  3. 本地广播Local Broadcast:App应用内广播可理解为一种局部广播,广播的发送者和接收者都同属于一个App。相比于全局广播(普通广播),App应用内广播优势体现在:安全性高 & 效率高。对于LocalBroadcastManager方式发送的应用内广播,只能通过LocalBroadcastManager动态注册,不能静态注册。调用sendBroadcast发送。

2、用途

  1. 广播实现了不同程序之间的信息传输与共享,只要和发送广播的 action 相同的接收者,都能接收到这个广播。典型的应用就是 android 自带的短信,电话等等广播,只要我们实现了他们的 action 的广播,那么我们就能接收他们的数据了,以便做出一些处理。比如说拦截系统短信,拦截骚扰电话等。
  2. 作为通知的作用,比如在 Service 中要通知主程序、更新主程序的 UI 等,因为 Service 是没有界面的,所以不能直接获得主程序中的控件,这样我们就只能在主程序中实现一个广播接收者专门用来接收service发过来的数据和通知了。

3、使用场景

  1. 同一app内部的同一组件内的消息通信(单个或多个线程之间)(可用handler解决);
  2. 同一app内部的不同组件之间的消息通信(单个进程)(可用EventBus);
  3. 同一app具有多个进程的不同组件之间的消息通信;
  4. 不同app之间的组件之间的消息通信;
  5. Android系统在特定情况下与App之间的消息通信。

二、注册广播接收 (静态和动态)

1、两种注册方法的区别:

  1. 动态注册的接收器必须要在程序启动之后才能接收到广播
  2. 静态注册的接收器即便程序未启动也能接收到广播,比如想接收到手机开机完成后系统发出的广播就只能用静态注册了。

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());
    

三、广播内部实现机制

  1. 自定义广播接收者 BroadcastReceiver,并复写 onRecvice();
  2. 通过 Binder 机制向 AMS(Activity Manager Service) 注册广播;
  3. 通过 Binder 机制向 AMS(Activity Manager Service) 发送广播。
  4. AMS 查找符合相应条件(IntentFilter/Permission等)的BroadcastReceiver,将广播发送到BroadcastReceiver 所在的消息循环队列中。
  5. BroadcastReceiver 所在消息队列拿到此广播后,回调它的 onReceive() 方法。

四、本地广播 LocalBroadcastManager

Android中的广播可以跨App直接通信(exported对于有intent-filter情况下默认值为true)
问题:

  1. 其他App针对性发出与当前App intent-filter相匹配的广播,由此导致当前App不断接收广播并处理;
  2. 其他App注册与当前App一致的intent-filter用于接收广播,获取广播具体信息(即会出现安全性 & 效率性的问题)。

解决方案:使用App应用内广播(Local Broadcast)

  1. App应用内广播可理解为一种局部广播,广播的发送者和接收者都同属于一个App。
  2. 相比于全局广播(普通广播),App应用内广播优势体现在:安全性高 & 效率高;

特点:

  1. 发送的广播只能够在自己 App 的内部传递,不会泄露给其他 App,确保隐私数据不会泄露;
  2. 广播接收器只能接收来自本 App 发出的广播;
  3. 其他App也无法向你的App发送该广播,不用担心其他App会来搞破坏;
  4. 比系统的全局广播更加高效。

内部实现原理:

  1. LocalBroadcastManager 高效的原因主要因为它内部是通过Handler实现的,它的sendBroadcast()方法是通过handler()发送一个Message实现的。
  2. 相比系统广播是通过Binder实现的,本地广播会更加高效。别人应用无法向自己的App发送广播,而自己App发送的广播也不会离开自己的App。
  3. LocalBroadcastManager 内部协作主要是靠两个Map集合:mReceivers和mActions,当然还有一个List集合mPendingBroadcasts,主要是存储待接收的广播对象。

五、BroadcastReceiver 和 LocalBroadcastReceiver 区别

  1. BroadcastReceiver 是跨应用广播,利用Binder机制实现。
  2. LocalBroadcastReceiver 是应用内广播,利用Handler实现,利用了IntentFilter的match功能,提供消息的发布与接收功能,实现应用内通信,效率比较高。
  3. LocalBroadcastReceiver不能静态注册,只能采用动态注册的方式。
    在发送和注册的时候采用,LocalBroadcastManager的sendBroadcast方法和registerReceiver方法

六、广播传输的数据是否有限制,是多少,为什么要限制?

  1. Broadcast广播通过Intent来传输数据,而Intent的数据大小限制为小于1MB,如果大于等于1MB都会出现异常。

  2. Intent携带信息的大小其实是受Binder限制,Binder传递缓存有一个限定大小,通常是1Mb。但同一个进程中所有的传输共享缓存空间。多个地方在进行传输时,即时它们各自传输的数据不超出大小限制,TransactionTooLargeException异常也可能会被抛出。

以上是关于Broadcast广播-Android的主要内容,如果未能解决你的问题,请参考以下文章

Android四大组件-Broadcast Receiver

广播(Broadcast)

Android 7.0 ActivityManagerService 广播(Broadcast)相关流程分析

Android面试收集录2 Broadcast Receiver详解

Android App开发超实用实例 | ​Broadcast

Broadcast