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也就接收到了廣播。