@linux1s1s
2017-01-22T16:17:04.000000Z
字数 4108
阅读 2709
AndroidComponent
2015-06
Android BroadCast (一) 揭开了关于BroadCast网络上普遍的误解,这里进一步对BroadCast发送的两种方式做基本的介绍:
先看代码:
getActivity().sendBroadcast(new Intent("Action"));
假如这个是在Fragment中的一处代码,我们顺着这个代码跟踪下去:
ContextWrapper.java
@Override
public void sendBroadcast(Intent intent) {
mBase .sendBroadcast( intent);
}
我们接着往下看, sendBroadcast到底干神马了?
接着进入 Context类的抽象方法:
public abstract void sendBroadcast(Intent intent);
所以找一下实现方法:比较多,这里重点看一下:ContextImpl这个类的具体实现:
@Override
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false,
getUserId());
} catch (RemoteException e) {
}
}
最后调用了ActivityManagerNative.getDefault().broadcastIntent(...) 跟着这个方法继续往下看:
进入到ActviityManagerService类,这个是典型的Android Service 类:
public final int broadcastIntent(IApplicationThread caller,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle map,
String requiredPermission, int appOp, boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
intent = verifyBroadcastLocked(intent);
final ProcessRecord callerApp = getRecordForAppLocked(caller);
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
int res = broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null,
intent, resolvedType, resultTo,
resultCode, resultData, map, requiredPermission, appOp, serialized, sticky,
callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
看到这里 不打算往下追代码了:本质上可以理解为: App进程发送广播到系统的Service,然后系统的Service转发给所有正在运行的进程。当这些进程接受到广播后,看一下自己是否注册了这个广播,如果需要这个信息,那么就会根据这个信息在各自的onReceive()方法中作出响应,这样一个过程像不像是广域网发送广播的情况(当然真实的网络通信是不可能在广域网发送广播的,如果一个请求,每次都要向互联网的所有网络都发送请求,那将是一个灾难。这里为了说明情况,只是打个比方,理解一下就可以了。)
有很多APP不想让其他App接收到自己发出去的广播,大部分有这些需求的都是出于安全考虑,那么该如何避免"广域网"广播呢?
很简单,Android 为我们提供了一个比较方便的类:LocalBroadcastManager类,所以这个时候想发送比较安全的广播,应该这么做:
LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(new Intent("Action"));
往下追踪一下代码,看看是如何做到的?
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<String> 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<ReceiverRecord> entries = mActions.get(intent.getAction());
if (entries != null) {
if (debug) Log.v(TAG, "Action list: " + entries);
ArrayList<ReceiverRecord> receivers = null;
for (int i=0; i<entries.size(); i++) {
ReceiverRecord receiver = entries.get(i);
if (debug) Log.v(TAG, "Matching against filter " + receiver.filter);
if (receiver.broadcasting) {
if (debug) {
Log.v(TAG, " Filter's target already added");
}
continue;
}
int match = receiver.filter.match(action, type, scheme, data,
categories, "LocalBroadcastManager");
if (match >= 0) {
if (debug) Log.v(TAG, " Filter matched! match=0x" +
Integer.toHexString(match));
if (receivers == null) {
receivers = new ArrayList<ReceiverRecord>();
}
receivers.add(receiver);
receiver.broadcasting = true;
} else {
if (debug) {
String reason;
switch (match) {
case IntentFilter.NO_MATCH_ACTION: reason = "action"; break;
case IntentFilter.NO_MATCH_CATEGORY: reason = "category"; break;
case IntentFilter.NO_MATCH_DATA: reason = "data"; break;
case IntentFilter.NO_MATCH_TYPE: reason = "type"; break;
default: reason = "unknown reason"; break;
}
Log.v(TAG, " Filter did not match: " + reason);
}
}
}
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;
}
}
}
return false;
}
我们可以发现,其实是对Receiver做了一定的筛选以后,再发送广播的,所以仅仅是在App所在的进程中才会接收到广播,就像是网络通信中的局域网广播一样,这样就有效避免的不怀好意的Receive做非法监听了。