android 开发程序员Android开发经验谈Android开发

BroadcastReceiver基础知识

2018-01-15  本文已影响32人  yangchendev

什么是广播

在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来发送的,这就说明了它比系统广播更加的高效。

上一篇 下一篇

猜你喜欢

热点阅读