BroadcastReceiver的使用
通常情況下,我們使用廣播的方式,首先定義廣播接收者,繼承BroadcastReceiver并重寫onReceive方法:
public class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent){
Log.d("TAG", "on receive action = " + intent.getAction());
}
}
定義好廣播之后,就可以注冊廣播接收者了。
有兩種方式:靜態注冊和動態注冊。
靜態注冊:
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="com.fastaoe.receiver.LAUNCH"/>
</intent-filter>
</receiver>
動態注冊:
IntentFilter filter = new IntentFilter();
filter.addAction("com.fastaoe.receiver.LAUNCH");
registerReceiver(new MyReceiver(), filter);
當注冊完成之后就可以通過send來發送廣播了:
Intent intent = new Intent();
intent.setAction("com.fastaoe.register.LAUNCH");
sendBroadcast(intent);
BroadcastReceiver的注冊過程
靜態注冊的過程其實就是PackageManagerService解析的過程,其實四大組件都是有PMS來解析并注冊的可以參考【Android源碼】PackageManagerService 淺析。
我們現在只分析動態注冊的過程:
同樣的動態注冊和Activity和Service一樣都是在ContextWrapper中,而其實mBase的具體實現類是ContextImpl對象:
// ContextWrapper.java
@Override
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter) {
return mBase.registerReceiver(receiver, filter);
}
// ContextImpl.java
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
return registerReceiver(receiver, filter, null, null);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext());
}
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context) {
IIntentReceiver rd = null;
if (receiver != null) {
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
try {
final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
intent.prepareToEnterProcess();
}
return intent;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
上述代碼主要做了這樣幾件事:
-
從
mPackageInfo
中獲取IIntentReceiver
對象。因為廣播是可以跨進程通信的,所以不能直接使用BroadcastReceiver,而是使用
InnerReceiver extends IIntentReceiver.Stub
的類型,也就是Binder接口,這個其實和Service的綁定流程類似。 通過AMS注冊廣播。
// ActivityManagerService.java
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
mRegisteredReceivers.put(receiver.asBinder(), rl);
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId);
rl.add(bf);
}
通過registerReceiver
方法將IIntentReceiver和IntentFilter保存起來,這個時候廣播就被注冊好了。
BroadcastReceiver的發送和接收過程
同樣的sendBroadcast也是由ContextImpl來實現的:
@Override
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
上述代碼什么都沒做,只是使用AMS調用broadcastIntent
:
public final int broadcastIntent(IApplicationThread caller,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
String[] requiredPermissions, int appOp, Bundle bOptions,
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, resultExtras,
requiredPermissions, appOp, bOptions, serialized, sticky,
callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
從上面的代碼可以看到是調用broadcastIntentLocked
方法:
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
在開始的時候添加了一個特殊的標記,這個標記表明默認情況下,廣播不會發送給已經停止的應用。
if ((receivers != null && receivers.size() > 0)
|| resultTo != null) {
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, resolvedType,
requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
resultData, resultExtras, ordered, sticky, false, userId);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
+ ": prev had " + queue.mOrderedBroadcasts.size());
if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
"Enqueueing broadcast " + r.intent.getAction());
boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
if (!replaced) {
queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
}
之后broadcastIntentLocked
內部,會根據intent-filter
來過濾匹配所有的廣播接收者,最終滿足所有條件的廣播接收者會被添加到BroadcastQueue
中,之后BroadcastQueue
會通過scheduleBroadcastsLocked
將廣播發送給這些符合條件的廣播接收者。
public void scheduleBroadcastsLocked() {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
+ mQueueName + "]: current="
+ mBroadcastsScheduled);
if (mBroadcastsScheduled) {
return;
}
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
在scheduleBroadcastsLocked
,系統并沒有直接發送廣播,而是通過handler來發送消息給BroadcastHandler
,而BroadcastHandler
在接收到BROADCAST_INTENT_MSG
之后調用了processNextBroadcast
:
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();
final int N = r.receivers.size();
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
+ mQueueName + "] " + r);
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Delivering non-ordered on [" + mQueueName + "] to registered "
+ target + ": " + r);
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
}
addBroadcastToHistoryLocked(r);
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
+ mQueueName + "] " + r);
}
通過循環遍歷mParallelBroadcasts
并將廣播發送給接收者,就是通過deliverToRegisteredReceiverLocked
來完成的:
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.repProcState);
}
最終調用了ApplicationThread的scheduleRegisteredReceiver
來完成廣播的接收:
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
int resultCode, String dataStr, Bundle extras, boolean ordered,
boolean sticky, int sendingUser, int processState) throws RemoteException {
updateProcessState(processState, false);
receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
sticky, sendingUser);
}
receiver
其實就是之前我們所講的InnerReceiver
:
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);
}
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
final Args args = new Args(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
if (intent == null) {
Log.wtf(TAG, "Null intent received");
} else {
if (ActivityThread.DEBUG_BROADCAST) {
int seq = intent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()
+ " seq=" + seq + " to " + mReceiver);
}
}
if (intent == null || !mActivityThread.post(args)) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManagerNative.getDefault();
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing sync broadcast to " + mReceiver);
args.sendFinished(mgr);
}
}
}
這里有一段關鍵代碼mActivityThread.post(args)
,其中args是Args的實例,而Args實現了Runnable接口,mActivityThread是ActivityThread中的mH的Handler對象,在Args的run方法中:
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
BroadcastReceiver的onReceive就被執行了,這個使用app也就接收到了廣播。