深入了解Android LocalBroadcastManager

一 前言

想写这篇文章,最大的原因就是前面写了一篇Android Handler机制分析https://www.jianshu.com/p/08ee800fe70e。然后有人问我,你了解安卓的LocalBroadcastManager吗?好吧,一脸懵逼的进来,一脸懵逼的出去。回去我们的工程中,发现LocalBroadcastManager在我们自己的项目中就有使用了,而且我还经常用到。。。痛定思痛,写下这篇文章,深入的剖析一下LocalBroadcastManager

二 什么是LocalBroadcastManager

LocalBroadcastManager 主要在你的进程中,用来注册和发送一个Intent。相对于全局的广播,LocalBroadcastManager有很多的优势:
1 安全性

1.1 使用localbroadcastmanager只会在你自己的app中传播数据,其他的app无法监听到你的广播,所以你无须担心隐私消息外漏

2.2 其他app不能发送广播到的app中,因此你不用担心安全漏洞的问题

2 高效性:localbroadcastmanager比全局的广播更加的高效

三 LocalBroadcastManager的使用

第一步:自定义BroadcastReceiver

  public static class MyBroadCardReveiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String intentFilter = intent.getAction();
        if (intentFilter.equals(MainActivity.INTENT_FILTER_REFRESH_UI)) {
            Toast.makeText(context, "收到了广播", Toast.LENGTH_LONG).show();
        }
    }
}

第二步:注册Receiver

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(INTENT_FILTER_REFRESH_UI);
LocalBroadcastManager.getInstance(this).registerReceiver(myBroadCardReveiver, intentFilter);  

LocalBroadcastManager 的注册需要传入自定义的BroadcastReceiverIntentFilter。IntentFilter主要用来注册当前需要监听的action是什么。这个我们后面再讲

第三步:在取消监听Receiver:unregisterReceiver(myBroadCardReveiver)

LocalBroadcastManager 的注册和监听一般是成对存在的。如果我们在Activity的onCreate()方法中注册监听Broadcast,那么我们就需要在onDestory()中进行反注册。如果我们不unregister,将会带来内存泄漏的问题

@Override
protected void onDestroy() {
    LocalBroadcastManager.getInstance(this).unregisterReceiver(myBroadCardReveiver);
    super.onDestroy();
}  

第四步:发送localBroadcast

 Intent intent=new Intent();
 intent.setAction(INTENT_FILTER_REFRESH_UI);
 LocalBroadcastManager.getInstance(MainActivity.this).sendBroadcast(intent);  

好了至此为止,我们已经知道了如何在我们的项目中使用localbroadcastmanager。接下来我们将进行源码的剖析

四 源码剖析

4.1 localBroadcastmanager的初始化

public static LocalBroadcastManager getInstance(Context context) {
    synchronized (mLock) {
        if (mInstance == null) {
            mInstance = new LocalBroadcastManager(context.getApplicationContext());
        }
        return mInstance;
    }
}

private LocalBroadcastManager(Context context) {
    mAppContext = context;
    mHandler = new Handler(context.getMainLooper()) {

        @Override``
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_EXEC_PENDING_BROADCASTS:
                    executePendingBroadcasts();
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    };
}

好吧,LocalBroadcastManager其实是一个单例设计,根据后面的初始化我们知道,其实我们在外面传入的context,到了localbroadcastmanager内部,用的是当前context所在的应用的上下文。这样是因为不造成内存泄漏,LocalBroadcastManager只持有当前app的上下文。同时我们看到,LocalBroadcastManager 在初始化的时候,还初始化了一个handler,这个handler是把结果抛向主线程的。所以,我们可以在LocalBroadcastManager接收回调的时候,进行UI的更新操作。

4.2 localbroadcastmanager的注册

public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
    synchronized (mReceivers) {
        ReceiverRecord entry = new ReceiverRecord(filter, receiver);
        ArrayList filters = mReceivers.get(receiver);
        if (filters == null) {
            filters = new ArrayList<>(1);
            mReceivers.put(receiver, filters);
        }
        filters.add(entry);
        for (int i=0; i entries = mActions.get(action);
            if (entries == null) {
                entries = new ArrayList(1);
                mActions.put(action, entries);
            }
            entries.add(entry);
        }
    }
}

registerReceiver方法是为那些匹配了intentFilter的action注册的监听。
我们可以看到,这个方法有两个重要的变量,一个是mReceiver:mReceivers是一个hashMap,它是以Receiver当做key,filters当成value保存进hashMap中。第二个是mActions:mActions保存着filter中添加进去的action,也就是我们上面的代码

intentFilter.addAction(INTENT_FILTER_REFRESH_UI);  

4.3 localbroadcastmanager的反注册

public void unregisterReceiver(BroadcastReceiver receiver) {
    synchronized (mReceivers) {
        final ArrayList filters = mReceivers.remove(receiver);
        if (filters == null) {
            return;
        }
        for (int i=filters.size()-1; i>=0; i--) {
            final ReceiverRecord filter = filters.get(i);
            filter.dead = true;
            for (int j=0; j receivers = mActions.get(action);
                if (receivers != null) {
                    for (int k=receivers.size()-1; k>=0; k--) {
                        final ReceiverRecord rec = receivers.get(k);
                        if (rec.receiver == receiver) {
                            rec.dead = true;
                            receivers.remove(k);
                        }
                    }
                    if (receivers.size() <= 0) {
                        mActions.remove(action);
                    }
                }
            }
        }
    }
}

从上面代码中,我们可以看到,LocalBroadcastManager尝试从mReceiver中移除当前的监听,如果这个监听没有被注册进去,那么就直接返回,否则的话,就进一步去那mAction中被添加进去的action,把他们一个一个找到,然后移除出去。

4.4 localbroadcastmanager发送广播

public boolean sendBroadcast(Intent intent) {
    synchronized (mReceivers) {
        final String action = intent.getAction();
        final String type = intent.resolveTypeIfNeeded(
                mAppContext.getContentResolver());
        final Uri data = intent.getData();
        final String scheme = intent.getScheme();
        final Set categories = intent.getCategories();

        final boolean debug = DEBUG ||
                ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);
        if (debug) Log.v(
                TAG, "Resolving type " + type + " scheme " + scheme
                + " of intent " + intent);

        ArrayList entries = mActions.get(intent.getAction());
        if (entries != null) {
            ArrayList receivers = null;
            for (int i=0; i

sendBroadcast()方法是是一个异步的操作。LocalBroadcastManager会马上返回这个值,但是真正的操作要等待异步回调到handler我们才能真正的收到广播的回调。

  if (!mHandler.hasMessages(MSG_EXEC_PENDING_BROADCASTS)) {
      mHandler.sendEmptyMessage(MSG_EXEC_PENDING_BROADCASTS);
  }

所以又回到了我们在localbroadcastmanager初始化方法,也即是初始化handler中。通过代码,我们可以看到,handler最后调用了executePendingBroadcasts()方法中

 private void executePendingBroadcasts() {
    while (true) {
        final BroadcastRecord[] brs;
        synchronized (mReceivers) {
            final int N = mPendingBroadcasts.size();
            if (N <= 0) {
                return;
            }
            brs = new BroadcastRecord[N];
            mPendingBroadcasts.toArray(brs);
            mPendingBroadcasts.clear();
        }
        for (int i=0; i

最后的 rec.receiver.onReceive(mAppContext, br.intent); 表明广播已经回到了我们注册的Broadcast的onReceive()方法中。

五:结语

LocalBroadcastManager其实是一个很简单的工具方法,但是其中的设计各有精妙的地方,很值得我们去借鉴。

你可能感兴趣的:(深入了解Android LocalBroadcastManager)