BroadcastReceiver基础知识

作者: yangchendev | 来源:发表于2018-01-15 09:37 被阅读32次

    什么是广播

    在Android中,广播是一种广泛运用的在应用程序之间传输信息的机制,Android中我们要发送的广播内容是一个Intent,这个Intent中可以携带我们要传送的数据。比如我们可以使用广播来实现Activity与Service之间的通信,而不必使用bindService;还有一个常用的场景就是当我们在应用中退出登录后,需要调到登录界面,而之前的主界面可以发送一个广播来通知主界面销毁自己。

    广播的种类

    广播一共有以下3种类型:

    1. Normal Broadcast:普通广播,调用方法是Context.sendBroadcast
    2. System Broadcast:系统广播(开机、电量低),调用方法是Context.sendOrderedBroadcast
    3. Local Broadcast:本地广播,只在自身APP内传播,内部实现机制是Handler

    广播的使用场景

    1. 同一个App具有多个进程的不同组件之间的消息通信,定位服务一般都会在一个单独的进程中,通过广播告诉其他进程定位信息
    2. 不同app之间的组件之间的消息通信,比如系统电话

    实现广播

    实现广播有两种方式:

    1. 静态注册:
      在AndroidManifest.xml里通过<receiver>标签声明
    <receiver 
        android:enabled=["true" | "false"]
    //此broadcastReceiver能否接收其他App的发出的广播
    //默认值是由receiver中有无intent-filter决定的:如果有intent-filter,默认值为true,否则为false
        android:exported=["true" | "false"]
        android:icon="drawable resource"
        android:label="string resource"
    //继承BroadcastReceiver子类的类名
        android:name=".mBroadcastReceiver"
    //具有相应权限的广播发送者发送的广播才能被此BroadcastReceiver所接收;
        android:permission="string"
    //BroadcastReceiver运行所处的进程
    //默认为app的进程,可以指定独立的进程
    //注:Android四大基本组件都可以通过此属性指定自己的独立进程
        android:process="string" >
    
    //用于指定此广播接收器将接收的广播类型
    //本示例中给出的是用于接收网络状态改变时发出的广播
     <intent-filter>
    <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
        </intent-filter>
    </receiver>
    

    创建一个类继承自BroadcastReciver,然后复写其中的onReceive()方法,判断相应的action即可。
    静态注册的广播会一直存在,不管app是否是运行的,只要接收到注册的广播就会执行onRecive里的代码。

    1. 动态注册:
      需要在activity中动态的registerReceiver
    // 选择在Activity生命周期方法中的onResume()中注册
    @Override
      protected void onResume(){
          super.onResume();
    
        // 1. 实例化BroadcastReceiver子类 &  IntentFilter
         mBroadcastReceiver mBroadcastReceiver = new mBroadcastReceiver();
         IntentFilter intentFilter = new IntentFilter();
    
        // 2. 设置接收广播的类型
        intentFilter.addAction(android.net.conn.CONNECTIVITY_CHANGE);
    
        // 3. 动态注册:调用Context的registerReceiver()方法
         registerReceiver(mBroadcastReceiver, intentFilter);
     }
    
    
    // 注册广播后,要在相应位置记得销毁广播
    // 即在onPause() 中unregisterReceiver(mBroadcastReceiver)
    // 当此Activity实例化时,会动态将MyBroadcastReceiver注册到系统中
    // 当此Activity销毁时,动态注册的MyBroadcastReceiver将不再接收到相应的广播。
     @Override
     protected void onPause() {
         super.onPause();
          //销毁在onResume()方法中的广播
         unregisterReceiver(mBroadcastReceiver);
         }
    }
    

    相比于静态注册,动态注册的广播跟随着activity的生命周期,同时为了防止内存溢出,需要在activity的onDestory方法中调用unregisterReceiver(mBroadcastReceiver);

    广播的内部实现机制

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

    本地广播的优点

    1. 使用它发送的广播将只在自身app内传播,因此你不必担心泄漏隐私数据
    2. 其他App无法对你的app发送广播,因为你的app根本就不可能接收到非自身应用发送的该广播,因此不必担心有安全漏洞可以利用
    3. 它比系统广播更加高效

    LocalBroadcastManager源码分析

    首先我们看源码要有目的的去看,而且入口点是你调用的方法,从该方法去看
    这里的入口就是registerReceiver

    public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
            synchronized (mReceivers) {
                //保存的是filter和receiver
                ReceiverRecord entry = new ReceiverRecord(filter, receiver);
                ArrayList<ReceiverRecord> filters = mReceivers.get(receiver);
                if (filters == null) {
                    filters = new ArrayList<>(1);
                    mReceivers.put(receiver, filters);
                }
              
                filters.add(entry);
                for (int i=0; i<filter.countActions(); i++) {
                    String action = filter.getAction(i);
                    ArrayList<ReceiverRecord> entries = mActions.get(action);
                    if (entries == null) {
                        entries = new ArrayList<ReceiverRecord>(1);
                        mActions.put(action, entries);
                    }
                    entries.add(entry);
                }
            }
        }
    

    再来看发送广播的方法,这里只截取的关键的一部分

    if (receivers != null) {
                       for (int i=0; i<receivers.size(); i++) {
                            receivers.get(i).broadcasting = false;
                        }
                        mPendingBroadcasts.add(new BroadcastRecord(intent, receivers));
                        if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {
                            mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);
                        }
                        return true;
                    }
    

    可以看到它内部是使用Handler来发送的,这就说明了它比系统广播更加的高效。

    相关文章

      网友评论

        本文标题:BroadcastReceiver基础知识

        本文链接:https://www.haomeiwen.com/subject/splroxtx.html