最近打算把Android基礎的一些知識再深入一點,所以就打算從四大組件開始入手,廣播是經常使用的,但是也僅僅只停留在會用,卻不知其原理,就着這個機會把源碼給擼一遍吧。
public class MainActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
registerReceiver(broadcastReceiver, new IntentFilter("broadcast_test"));
sendBroadcast(new Intent("broadcast_test"));
}
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("broadcast_test")){
Log.d("broadcast","receice");
}
}
};
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(broadcastReceiver);
}
}
本文不打算講解廣播的使用方法,就直接從動態註冊廣播開始好了,涉及到的源碼爲Android API 23。
上面demo中的registerReceiver(broadcastReceiver, new IntentFilter("broadcast_test"))執行的是ContextWrapper的方法:
@Override
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter) {
return mBase.registerReceiver(receiver, filter);
}
ContextWrapper的真正方法實現類爲ContextImpl,也就是說mBase是ContextImpl的實例,對於這一塊不是很瞭解的朋友可以看郭霖大神的這篇博客Android Context完全解析,你所不知道的Context的各種細節,由於這部分源碼很多加了/**
{@hide} */的註釋,所以在Android Studio裏面不能直接看到相關代碼,我們要到SDK的路徑\sdk\sources\android-23\android\app\下去查看相關代碼。
class ContextImpl extends Context {
/*省略其它無關代碼*/
@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();//獲取主線程的Handler
}
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 {
return ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
} catch (RemoteException e) {
return null;
}
}
}
mPackageInfo是LoadedApk的實例對象,mMainThread是ActivityThread的實例對象,IIntentReceiver是有一個接口,其對象rd是一個實現了Binder對象(我沒有找到IIntentReceiver的源碼,是查閱相關資料才知道的)。
public final class LoadedApk {
/*省略其它代碼*/
private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
= new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
Context context, Handler handler,
Instrumentation instrumentation, boolean registered) {
synchronized (mReceivers) {
LoadedApk.ReceiverDispatcher rd = null;
ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
if (registered) {
map = mReceivers.get(context);
if (map != null) {
rd = map.get(r);
}
}
if (rd == null) {
rd = new ReceiverDispatcher(r, context, handler,
instrumentation, registered);
if (registered) {
if (map == null) {
map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
mReceivers.put(context, map);
}
map.put(r, rd);
}
} else {
rd.validate(context, handler);
}
rd.mForgotten = false;
return rd.getIIntentReceiver();//最終返回一個Binder對象
}
}
static final class ReceiverDispatcher {
final static class InnerReceiver extends IIntentReceiver.Stub {
/*省略其它代碼*/
}
final IIntentReceiver.Stub mIIntentReceiver;
ReceiverDispatcher(BroadcastReceiver receiver, Context context,
Handler activityThread, Instrumentation instrumentation,
boolean registered) {
/*省略其它代碼*/
mIIntentReceiver = new InnerReceiver(this, !registered);
}
IIntentReceiver getIIntentReceiver() {
return mIIntentReceiver;
}
}
}
從LoadedApk的getReceiverDispatcher方法我們可以知道幾點:
1、每一個註冊的廣播接收器都有對應的ReceiverDispatcher(即Binder對象)。
2、廣播接收器和ReceiverDispatcher以鍵值對的形式存在map中。
3、存儲廣播接收器和ReceiverDispatcher的map與context也以鍵值對的形式存儲在map中。
那麼有一個問題來了,LoadedApk到底有什麼用?它的註釋文檔就一句話“Local state maintained about a currently loaded .apk.”,大概意思就是當前加載的APK在內存中的狀態,如果查看代碼還會發現,它存儲的還有Service等。
這時候該走到ContextWrapper.registerReceiverInternal的try-catch代碼塊了,在try中ActivityManagerNative.getDefault()方法返回一個ActivityManagerProxy對象,ActivityManagerProxy相關代碼:
class ActivityManagerProxy implements IActivityManager {
/*省略其它代碼*/
public ActivityManagerProxy(IBinder remote) {
mRemote = remote;
}
public Intent registerReceiver(IApplicationThread caller, String packageName,
IIntentReceiver receiver,
IntentFilter filter, String perm, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(packageName);
data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
filter.writeToParcel(data, 0);
data.writeString(perm);
data.writeInt(userId);
//此處與ActivityServiceManager通信
mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
reply.readException();
Intent intent = null;
int haveIntent = reply.readInt();
if (haveIntent != 0) {
intent = Intent.CREATOR.createFromParcel(reply);
}
reply.recycle();
data.recycle();
return intent;
}
}
關鍵代碼mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);涉及到的進程間通信不是今天的內容,真要說我也說不清,我們就不深究了,只要知道它的作用就是調用了ActivityManagerService的註冊方法。ActivityManagerService的代碼就不貼了,簡單來說它的註冊方法就是以調用方法的App的進程ID爲唯一標識,生成一個ReceiverList存放所有註冊的廣播接收器。至此,就完成了廣播接收器的註冊過程,也就是說所有app的廣播接收器都會存在ActivityManagerService中。
接下來就是廣播的發送了,同樣sendBroadcast(new Intent("broadcast_test"))方法的真正實現也是在ContextImpl中
class ContextImpl extends Context {
/*省略其它代碼*/
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, null, false, false,
getUserId());
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
}
}
ActivityManagerNative.getDefault()是不是很熟悉呢,沒錯,和註冊一樣都是調用了ActivityManagerProxy的方法
class ActivityManagerProxy implements IActivityManager {
/*省略其它代碼*/
public int broadcastIntent(IApplicationThread caller,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle map,
String[] requiredPermissions, int appOp, Bundle options, boolean serialized,
boolean sticky, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeStrongBinder(resultTo != null ? resultTo.asBinder() : null);
data.writeInt(resultCode);
data.writeString(resultData);
data.writeBundle(map);
data.writeStringArray(requiredPermissions);
data.writeInt(appOp);
data.writeBundle(options);
data.writeInt(serialized ? 1 : 0);
data.writeInt(sticky ? 1 : 0);
data.writeInt(userId);
//此處與ActivityServiceManager通信
mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
reply.recycle();
data.recycle();
return res;
}
}
不一樣的方法,還是熟悉的味道。發送廣播也是調用的ActivityManagerService的方法,具體代碼也不貼了(主要是我沒有在6.0的源碼裏找到這個類)。ActivityManagerService在發送的過程中的工作就是根據發送的廣播的Action找到相應的廣播接收器(手機上所有註冊的廣播接收器都在這裏存着了,找一個還不容易嘛)。ActivityManagerService內部有一個Handler會循環處理髮送的廣播,處理的過程就是利用Binder機制將廣播分發給相應的廣播接收器的ReceiverDispatcher
static final class ReceiverDispatcher {
/*省略其它代碼*/
final static class InnerReceiver extends IIntentReceiver.Stub {
final class Args extends BroadcastReceiver.PendingResult implements Runnable {
public void run() {
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
} catch (Exception e) {
}
}
}
}
}
ReceiverDispatcher實現了Runnable接口,最終會回調到相應BroadcastReceiver的onReceive方法。那麼會在哪個線程中處理這個任務呢,還記得註冊廣播時的scheduler嗎,就是在這個裏面被post進去的。這樣一來,整個廣播的註冊和發送接收事件就完成了。我這裏只是大致梳理了最基礎的廣播使用過程,沒有對細節深入,仔細探索的話還有粘性廣播的處理、廣播優先級的處理、廣播註銷的處理等等,那我就不再多囉嗦啦。(再囉嗦一句,廣播的這種訂閱--發佈過程就是觀察者模式的體現)
參考資料 《Android源碼設計模式解析與實踐》