Android编程之LocalBroadcastManager源码详解

原创 2014年02月07日 22:55:15

LocalBroadcastManager 是V4包中的一个类,主要负责程序内部广播的注册与发送。也就是说,它只是适用代码中注册发送广播,对于在AndroidManifest中注册的广播接收,则不适用。

官方英文解释如下:

Helper to register for and send broadcasts of Intents to local objects within your process. This is has a number of advantages over sending global broadcasts with sendBroadcast(Intent):

You know that the data you are broadcasting won't leave your app, so don't need to worry about leaking private data.
It is not possible for other applications to send these broadcasts to your app, so you don't need to worry about having security holes they can exploit.
It is more efficient than sending a global broadcast through the system. 


接下来如正题,先看一下全局变量:

private final Context mAppContext;
private final HashMap<BroadcastReceiver, ArrayList<IntentFilter>> mReceivers = new HashMap();

private final HashMap<String, ArrayList<ReceiverRecord>> mActions = new HashMap();

private final ArrayList<BroadcastRecord> mPendingBroadcasts = new ArrayList();
static final int MSG_EXEC_PENDING_BROADCASTS = 1;
private final Handler mHandler;
private static final Object mLock = new Object();
private static LocalBroadcastManager mInstance;

mAppContext:即ApplicationContext,所以不用担心内存泄漏问题。

mReceivers:记录注册的BroadcastReceiver及其IntentFilter的数组,这里为什么是数组,下面会有讲到。

mActions:记录IntentFilter中的action对应的BroadcastReceiver数组。虽然这里写的是ReceiverRecord类型,但它实际上是一个内部类,主要保存了BroadcastReceiver及其对应的IntentFilter。

mPendingBroadcasts:在发送广播时,会根据Intent的action,找到与之相对应的BroadcastReceiver。还记得吗?action是可以对应多个BroadcastReceiver,所以这里是数组。

mHandler:就做了一件事情,发送广播。

mLock:同步锁。

mInstance:自己本身的实例对象,有经验的可能已经猜到了,没错,LocalBroadcastManager是一个单例。


看一下它的构造方法,标准的单例写法:

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

private LocalBroadcastManager(Context context) {
	this.mAppContext = context;
	this.mHandler = new Handler(context.getMainLooper()) {
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case MSG_EXEC_PENDING_BROADCASTS:
				LocalBroadcastManager.this.executePendingBroadcasts();
				break;
			default:
				super.handleMessage(msg);
			}
		}
	};
}

上面谈到的mAppContext是ApplicationContext的证据:mInstance = new LocalBroadcastManager(context.getApplicationContext());

而mHandler就是在构造时创建的,内部就做了一件事,发送广播:executePendingBroadcasts。


接下来就看一下如何注册广播接收者:

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

就是将BroadcastReceiver和IntentFilter建立一对多的对应关系。可以通过BroadcastReceiver找到其对应的IntentFilter,也可以通过IntentFilter中的action找到所对应的BroadcastReceiver。这里还要解释一下上面提到的mReceivers中,为什么保存的IntentFilter是数组形式。我们知道,IntentFilter中是可以保存多个action的,这也就是为什么它初始化成1个长度的数组。那么这里的数组的意义,其实很简单,就是能支持传入多个IntentFilter。虽然是支持传入多个IntentFilter,但如果里面的action是同名的话,也还是按同一个处理的,后面代码就能看出,action是以键的方法存起来的。


有注册,就得有取消注册:

public void unregisterReceiver(BroadcastReceiver receiver) {
	synchronized (this.mReceivers) {
		ArrayList filters = (ArrayList) this.mReceivers.remove(receiver);
		if (filters == null) {
			return;
		}
		for (int i = 0; i < filters.size(); i++) {
			IntentFilter filter = (IntentFilter) filters.get(i);
			for (int j = 0; j < filter.countActions(); j++) {
				String action = filter.getAction(j);
				ArrayList receivers = (ArrayList) this.mActions.get(action);
				if (receivers != null) {
					for (int k = 0; k < receivers.size(); k++) {
						if (((ReceiverRecord) receivers.get(k)).receiver == receiver) {
							receivers.remove(k);
							k--;
						}
					}
					if (receivers.size() <= 0)
					this.mActions.remove(action);
				}
			}
		}
	}
}

简单来说,就是将BroadcastReceiver从mReceivers和mActions中移除掉。由于BroadcastReceiver是mReceivers的键,所以移除掉比较简单。而mActions就稍微复杂一些,需要根据BroadcastReceiver中的IntentFilter数组,从mActions中移除掉。

还记得注册时,同名的action可以对应不同的BroadcastReceiver吗,注意这里的一句话:if (((ReceiverRecord) receivers.get(k)).receiver == receiver),没错,它只会移除掉当前的,不会将action对应的BroadcastReceiver都删除掉。


最后就是关键的    public boolean sendBroadcast(Intent intent)方法,整个方法都是synchronized (this.mReceivers)的,由于这个方法内容太长,这里分段来讲解:

String action = intent.getAction();
String type = intent.resolveTypeIfNeeded(this.mAppContext.getContentResolver());

Uri data = intent.getData();
String scheme = intent.getScheme();
Set categories = intent.getCategories();

boolean debug = (intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION ) != 0;

首先取出intent中的参数,除了action外,其他都是用来作比较的。如果在intent中setFlag设置了Intent.FLAG_DEBUG_LOG_RESOLUTION,就会可以输出一些log信息。


然后就是从mActions中取出intent的action所对应的ReceiverRecord

ArrayList entries = (ArrayList) this.mActions.get(intent.getAction());
										
ArrayList receivers = null;
for (int i = 0; i < entries.size(); i++)

这段就是for循环里面的内容:

ReceiverRecord receiver = (ReceiverRecord) entries.get(i);

if (receiver.broadcasting) {
					
	} else {
		int match = receiver.filter.match(action, type, scheme,
		data, categories, "LocalBroadcastManager");

		if (match >= 0) {						
			if (receivers == null) {
				receivers = new ArrayList();
			}
			receivers.add(receiver);
			receiver.broadcasting = true;
		} else {
												
		}
	}
}

在这里,如果是发送中,就什么也不做。否则,先匹配一下receiver中的IntentFilter,如果匹配上,就设置其为发送中,即设置变量broadcasting为true。其意义在于避免重复发送。


最后,添加到ArrayList中:this.mPendingBroadcasts.add(new BroadcastRecord(intent,receivers));通知Handler,执行executePendingBroadcasts()方法。

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

executePendingBroadcasts()方法就很简单了,就是取出mPendingBroadcasts数组中的BroadcastReceiver(在ReceiverRecord中保存其对象),调用其onReceive方法。

private void executePendingBroadcasts() {
	while (true) {
		BroadcastRecord[] brs = null;
		synchronized (this.mReceivers) {
			int N = this.mPendingBroadcasts.size();
			if (N <= 0) {
				return;
			}
			brs = new BroadcastRecord[N];
			this.mPendingBroadcasts.toArray(brs);
			this.mPendingBroadcasts.clear();
		}
		for (int i = 0; i < brs.length; i++) {
			BroadcastRecord br = brs[i];
			for (int j = 0; j < br.receivers.size(); j++)
				((ReceiverRecord) br.receivers.get(j)).receiver.onReceive(
						this.mAppContext, br.intent);
		}
	}
}

还有一个方法sendBroadcastSync,平常我们一般不会用到这个方法,这里放一下源码:

public void sendBroadcastSync(Intent intent) {
	if (sendBroadcast(intent))
		executePendingBroadcasts();
}

这里再补一个其内部类ReceiverRecord的源码:

private static class ReceiverRecord {
	final IntentFilter filter;
	final BroadcastReceiver receiver;
	boolean broadcasting;

	ReceiverRecord(IntentFilter _filter, BroadcastReceiver _receiver) {
		this.filter = _filter;
		this.receiver = _receiver;
	}
}

小结:

1、LocalBroadcastManager在创建单例传参时,不用纠结context是取activity的还是Application的,它自己会取到tApplicationContext。

2、LocalBroadcastManager只适用于代码间的,因为它就是保存接口BroadcastReceiver的对象,然后直接调用其onReceive方法。

3、LocalBroadcastManager注册广播后,当该其Activity或者Fragment不需要监听时,记得要取消注册,注意一点:注册与取消注册在activity或者fragment的生命周期中要保持一致,例如onResume,onPause。

4、LocalBroadcastManager虽然支持对同一个BroadcastReceiver可以注册多个IntentFilter,但还是应该将所需要的action都放进一个IntentFilter,即只注册一个IntentFilter,这只是我个人的建议。

5、LocalBroadcastManager所发送的广播action,只能与注册到LocalBroadcastManager中BroadcastReceiver产生互动。如果你遇到了通过LocalBroadcastManager发送的广播,对面的BroadcastReceiver没响应,很可能就是这个原因造成的。

相关文章推荐

Android 三种sendBroadCast的方式对比

作为android 的四大基本组件之一的 BroadCast Receiver,是进行进程间通信的重要手段,几乎所有的应用都会注册和发送各种不同的intent, 那么有一个问题,你是否了解Intent...

Android中LocalBroadcastManager的基本用法及源码分析

本篇博客主要记录一下LocalBroadcastManager的基本用法, 同时分析一下LocalBroadcastManager的源码,看看其功能实现的原理。...

LocalBroadcastManager基本用法

LocalBroadcastManager基本用法LocalBroadcastManager发送的广播只作用于本应用,如果不涉及到其他应用,但用到了广播的话那么用LocalBroadcastManag...

LocalBroadcastManager—创建更高效、更安全的广播

前言在写Android应用时候,有时候或多或少的需要运用广播来解决某些需求,我们知道广播有一个特性,就是使用sendBroadcast(intent);发送广播时,手机内所有注册了BroadcastR...

LocalBroadcastManager源码解析

LocalBroadcastManager源码解析1.简介LocalBroadcastManager是Android v4兼容包提供的应用内广播发送与接收的工具类。BroadcastReceiver的...

Android应用程序发送广播(sendBroadcast)的过程分析

前面我们分析了Android应用程序注册广播接收器的过程,这个过程只完成了万里长征的第一步,接下来它还要等待ActivityManagerService将广播分发过来。ActivityManagerS...

Android 之使用LocalBroadcastManager,源码解析

在Android系统中,BroadcastReceiver的设计初衷就是从全局考虑的,可以方便应用程序和系统、应用程序之间、应用程序内的通信,所以对单个应用程序而言BroadcastReceiver是...

Android之LocalBroadcastManager源码解析

LocalBroadcastManager在项目中遇到LocalBroadcastManager,看英文大概知道是“管理本地广播”的,翻了一下api文档,发现他就是用来注册,发送本地广播的,用于应用内...

LocalBroadcastManager的代码示例源码

  • 2016年06月26日 01:42
  • 19.11MB
  • 下载

LocalBroadcastManager源码分析

源码分析/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android编程之LocalBroadcastManager源码详解
举报原因:
原因补充:

(最多只允许输入30个字)