編輯:關於Android編程
在Android中,BroadcastReceiver是一套用來實現組件之間的通信機制,它是基於消息發布和訂閱機制,可以用在不同線程之間組件的通信,也可以跨進程進行組件間通信。
在Android中,根據注冊類型來看,BroadcastReceiver可以分為兩種類型:靜態廣播和動態廣播,其中靜態廣播中的廣播中心是PMS(PackageManagerService),而動態廣播的廣播中心是AMS(ActivityManagerService),這邊文章主要是分析動態廣播的。
動態BroadcastReceiver的注冊是借助Context接口中的registerReceiver方法來實現的。其中,繼承Context接口的類有:Activity,Service,Application,所以在這3個類中,都可以動態注冊廣播。此外,Context接口的實現類,是ContextImpl類。
在討論BroadcastReceiver前,需要稍微了解下Android不同進程之間的通信,以及一些Android系統級的Service。
Android跨進程之間的通信,主要有Binder實現的IPC機制,匿名共享內存,socket等等,而廣播的跨進程通信是使用Binder來實現的,通過Binder將App進程切換到system_server進程和AMS通信。
在手機開機的時候,Android啟動了很多系統級的進程,比如zygote進程,system_server進程,其中在system_server進程上,又啟動了很多服務,
比如PowerManagerService(電源管理服務),ActivityManagerService(管理四大組件)
下面,主要是通過探討廣播,主要是分為兩部分,
用戶進程和system_server進程,廣播registerReceiver的流程
用戶進程和system_server進程,廣播底層的數據存儲結構
Context.java
public abstract Intent registerReceiver(BroadcastReceiver receiver,IntentFilter filter);
receiver: 廣播接收組件,接收到相關的廣播會調用BroadcastReceiver中的onReceive方法
filter:主要是用來過濾廣播的,只有符合條件的廣播才會接收.
registerReceiver方法最終是調用ContextImpl中的registerReceiverInternal方法
ContextImpl.java
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 {
return ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
} catch (RemoteException e) {
return null;
}
}
mPackageInfo:LoadedApk類型,保存了整個App內部的信息,比如包名,資源的路徑,應用中所有啟動的service,注冊的reciver等等,用戶進程(即一個應用進程)中,只會存在一個對象,所有ContextImpl中的mPackageInfo都指向共同的mPackageInfo對象,因此,mPackageInfo在整個用戶進程中是唯一的。
registerReceiverInternal方法:
1,獲取Handler類型的scheduler對象,如果scheduler不為null,則scheduler為用戶傳遞進來的Handler,否則為主線程中的Hanlder(這也是為什麼BroadcastReceiver中的onReceive方法調用是處於主線程的原因),這個Handler對象主要是用來分發AMS傳遞過來的Intent,
2,如果mPackageInfo存在,則通過mPackageInfo獲取IIntentReceiver類型的rd對象,否則創建一個,rd同樣也是Binder類型。然後,將rd傳遞給AMS,AMS處理相對應的廣播,會通過這個Binder對象,跨進程回傳到這個Context所處的進程中。
3,通過ActivityManagerNative.getDefault()獲取到ActivityManagerProxy對象,然後借助ActivityManagerProxy對象,和AMS通信,這時候進程由用戶進程切換到system_server進程,最終調用的是AMS中的registerReceiver方法。
scheduler = mMainThread.getHandler();
mMainThread是ActivityThread對象,也可以說是主線程
這裡有個疑惑,關於mPackageInfo,這個對象什麼時候不存在?(以後再查看)按照我目前的理解,mPackageInfo最早是在Application創建的時候,就被初始化了,而context是當前的Activity,Service或者Application,所以符合條件(mPackageInfo != null && context != null)
rd = mPackageInfo.getReceiverDispatcher(receiver, context, scheduler, mMainThread.getInstrumentation(), true);
LoadedApk
public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
Context context, Handler handler,
Instrumentation instrumentation, boolean registered) {
synchronized (mReceivers) {
LoadedApk.ReceiverDispatcher rd = null;
ArrayMap 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();
mReceivers.put(context, map);
}
map.put(r, rd);
}
} else {
rd.validate(context, handler);
}
rd.mForgotten = false;
return rd.getIIntentReceiver();
}
}
1,如果廣播已經注冊過,則通過mReceivers對象獲取key為當前Context的LoadedApk.ReceiverDispatcher類型的rd對象
2,如果rd對象不存在,則創建,並且將rd添加到map中;否則,驗證rd對象中的context和activitythread(validate這個方法有疑惑,什麼場景下,rd中context和activitythread和目前的不一致)
3,返回rd對象的中IIntentReceiver對象
廣播在用戶進程中的底層數據存儲
上面說過,在用戶進程中所有ContextImpl中的mPackageInfo都指向同一對象。
mPackageInfo中存在維持一個ArrayMap的mReceivers變量,mReceivers是ArrayMap嵌套ArrayMap的數據結構
key:為注冊的Context(即Activity,Service或者Application),
value:同樣也是個ArrayMap,
key:注冊的BroadcastReceiver
value:ReceiverDispatcher對象,廣播分發者,該對象內部保存注冊者的Context,Handler,BroadcastReceiver,IIntentReceiver.Stub(和用戶進程交互的)等等,
發送廣播時,AMS將會將Intent信息分發到BroadcastReceiver的onRecieve方法中。
mReceivers
private final ArrayMap> mReceivers
= new ArrayMap>();
LoadedApk.ReceiverDispatcher
final IIntentReceiver.Stub mIIntentReceiver;
final BroadcastReceiver mReceiver;
final Context mContext;
final Handler mActivityThread;
final Instrumentation mInstrumentation;
final boolean mRegistered;
final IntentReceiverLeaked mLocation;
RuntimeException mUnregisterLocation;
//....
廣播在AMS中的注冊流程
try {
// 跨進程和AMS通信,廣播的注冊實際上是在AMS中執行的
return ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
} catch (RemoteException e) {
return null;
}
ActivityManagerNative.getDefault()
public abstract class ActivityManagerNative extends Binder implements IActivityManager
{
// ...省略
// 獲取到唯一的
static public IActivityManager getDefault() {
return gDefault.get();
}
// ...省略
// Singleton是一個抽象類,Android實現的單例模式
private static final Singleton gDefault = new Singleton() {
protected IActivityManager create() {
// 獲取指向ActivityManagerService的IBinder對象
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
// 創建ActivityManagerProxy對象,並將ActivityManagerService的Binder傳遞給ActivityManagerProxy
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
// 創建一個ActivityManagerProxy對象
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ActivityManagerProxy(obj);
}
}
ActivityManagerNative.getDefault()第一次會創建一個AMP(ActivityManagerProxy)對象,並通過ServiceManager遠程獲取到一個指向AMS
的IBinder對象,並將這個IBinder引用傳遞給AMS對象,最後返回AMP對象,注意這個對象運行在用戶進程中的,
ActivityManagerProxy中的IBinder引用是用來跨進程和AMS通信的。
ActivityManagerProxy.registerReceiver
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);
// 跨進程和AMS通信,注意Binder驅動會掛起當前用戶線程
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是一個IBinder對象,指向AMS的。
mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
Binder機制非常復雜,這裡不做討論。我們只需要知道IBinder.transact方法,會調用到IBinder.onTransact方法。
題外話:
這裡有個疑惑,mRemote.transact會不會阻塞線程呢?仔細思考了下,應該會的,准確的來說,Binder驅動會掛起當前用戶進程。
因為registerReceiver返回Intent對象,如果當前用戶線程沒有掛起的話,那麼後面的代碼就沒意義了,比如reply.readException肯定沒效果。
mRemote這個IBinder對象是指向AMS的,而AMS繼承了ActivityManagerNative類,並且AMS的onTransact方法是由ActivityManagerNative實現的。
ActivityManagerNative.onTransact,注意調用這個方法的時候,進程已經從用戶進程切換到system_server進程了。
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case REGISTER_RECEIVER_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
IApplicationThread app =
b != null ? ApplicationThreadNative.asInterface(b) : null;
String packageName = data.readString();
b = data.readStrongBinder();
IIntentReceiver rec
= b != null ? IIntentReceiver.Stub.asInterface(b) : null;
IntentFilter filter = IntentFilter.CREATOR.createFromParcel(data);
String perm = data.readString();
int userId = data.readInt();
// 調用AMS中的registerReceiver方法,這個方法是廣播注冊的最終實現
Intent intent = registerReceiver(app, packageName, rec, filter, perm, userId);
reply.writeNoException();
if (intent != null) {
reply.writeInt(1);
intent.writeToParcel(reply, 0);
} else {
reply.writeInt(0);
}
return true;
}
}
ActivityManagerService.registerReceiver
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
enforceNotIsolatedCaller("registerReceiver");
int callingUid;
int callingPid;
synchronized(this) {
ProcessRecord callerApp = null;
if (caller != null) {
callerApp = getRecordForAppLocked(caller);
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when registering receiver " + receiver);
}
if (callerApp.info.uid != Process.SYSTEM_UID &&
!callerApp.pkgList.containsKey(callerPackage) &&
!"android".equals(callerPackage)) {
throw new SecurityException("Given caller package " + callerPackage
+ " is not running in process " + callerApp);
}
callingUid = callerApp.info.uid;
callingPid = callerApp.pid;
} else {
callerPackage = null;
callingUid = Binder.getCallingUid();
callingPid = Binder.getCallingPid();
}
userId = this.handleIncomingUser(callingPid, callingUid, userId,
true, true, "registerReceiver", callerPackage);
List allSticky = null;
// Look for any matching sticky broadcasts...
Iterator actions = filter.actionsIterator();
if (actions != null) {
while (actions.hasNext()) {
String action = (String)actions.next();
allSticky = getStickiesLocked(action, filter, allSticky,
UserHandle.USER_ALL);
allSticky = getStickiesLocked(action, filter, allSticky,
UserHandle.getUserId(callingUid));
}
} else {
allSticky = getStickiesLocked(null, filter, allSticky,
UserHandle.USER_ALL);
allSticky = getStickiesLocked(null, filter, allSticky,
UserHandle.getUserId(callingUid));
}
// The first sticky in the list is returned directly back to
// the client.
Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
if (DEBUG_BROADCAST) Slog.v(TAG, "Register receiver " + filter
+ ": " + sticky);
if (receiver == null) {
return sticky;
}
ReceiverList rl
= (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
if (rl.app != null) {
rl.app.receivers.add(rl);
} else {
try {
receiver.asBinder().linkToDeath(rl, 0);
} catch (RemoteException e) {
return sticky;
}
rl.linkedToDeath = true;
}
mRegisteredReceivers.put(receiver.asBinder(), rl);
} else if (rl.uid != callingUid) {
throw new IllegalArgumentException(
"Receiver requested to register for uid " + callingUid
+ " was previously registered for uid " + rl.uid);
} else if (rl.pid != callingPid) {
throw new IllegalArgumentException(
"Receiver requested to register for pid " + callingPid
+ " was previously registered for pid " + rl.pid);
} else if (rl.userId != userId) {
throw new IllegalArgumentException(
"Receiver requested to register for user " + userId
+ " was previously registered for user " + rl.userId);
}
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId);
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadast");
}
mReceiverResolver.addFilter(bf);
// Enqueue broadcasts for all existing stickies that match
// this filter.
if (allSticky != null) {
ArrayList receivers = new ArrayList();
receivers.add(bf);
int N = allSticky.size();
for (int i=0; i
1,首先會獲取應用的uid和pid,然後調用handleIncomingUser檢測注冊廣播所需的權限,並獲取userId
2,檢測所有符合條件的黏性事件,如果廣播為null,則返回最近的一條黏性事件
3,通過mRegisteredReceivers獲取key為receiver(IBinder對象,從用戶進程中傳遞進來的IIntentReceiver對象),獲取相關的ReceiverList; 如果ReceiverList為null,則創建,並添加到mRegisteredReceivers中
4,創建BroadcastFilter(繼承IntentFilter)對象,並添加進入到ReceiverList中
5,處理符合條件的黏性事件(這裡暫不探討)
ReceiverList:繼承ArrayList,存儲的是BroadcastFilter對象
BroadcastFilter:繼承IntentFilter,主要是用來過濾廣播的,廣播接收器只能接收指定的廣播類型
AMS中維持一個mRegisteredReceivers變量的HashMap
final HashMap mRegisteredReceivers =
new HashMap();
mRegisteredReceivers的數據結構是HashMap
key:IBinder,也就是ReceiverDispatcher中的IIntentReceiver對象,是用於AMS和用戶進程通信的
value:ReceiverList,存儲一系列的BroadcastFilter的List
mReceiverResolver:存儲對應的BroadcastFilter
動態廣播注冊的底層數據存儲
要求 Tab 標簽可以橫向滾動,標簽可選擇,並且在選擇的時候有標線下劃線。 分析 可繼承HorizontalScrollView 實現,然後裡面標簽ITem可可以是Tex
前言前段時間需要用到recyclerview,就想找個封裝好的下拉刷新,上拉加載的庫,結果愣是沒找到,便自己寫了一個。注意:我說的是“上拉加載”,不是滑到底部自動加載。
Android性能的優化主要分為兩點1、布局優化2、內存優化布局優化首先來看一下布局優化,系統在渲染UI的時候會消耗大量的資源,所以,對布局的優化就顯得尤為重要避免Ove
一、查看自己的證書簽名信息如上一篇文章《我的Android進階之旅------>Android中制作和查看自定義的Debug版本Android簽名證書 》地址:ht