@linux1s1s
2017-01-22T08:17:04.000000Z
字数 4108
阅读 3085
AndroidComponent 2015-06
Android BroadCast (一) 揭开了关于BroadCast网络上普遍的误解,这里进一步对BroadCast发送的两种方式做基本的介绍:
先看代码:
getActivity().sendBroadcast(new Intent("Action"));
假如这个是在Fragment中的一处代码,我们顺着这个代码跟踪下去:
ContextWrapper.java
@Overridepublic void sendBroadcast(Intent intent) {mBase .sendBroadcast( intent);}
我们接着往下看, sendBroadcast到底干神马了?
接着进入 Context类的抽象方法:
public abstract void sendBroadcast(Intent intent);
所以找一下实现方法:比较多,这里重点看一下:ContextImpl这个类的具体实现:
@Overridepublic 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做非法监听了。
