前言
android L開始launcher3對(duì)于package變化的監(jiān)聽發(fā)生了改變隙笆,M之前都是通過PackageChangedReceiver(PackageChangedReceiver.java)這個(gè)廣播接收器來監(jiān)聽的。但是從L開始我們發(fā)現(xiàn)LauncherAppsCompat的實(shí)現(xiàn)類有兩個(gè):LauncherAppsCompatV16和LauncherAppsCompatVL漂坏。在LauncherAppsCompatV16中還是通過廣播(PackageMonitor extends BroadcastReceiver)來監(jiān)聽packages變化摸屠。而在 LauncherAppsCompatVL并沒有發(fā)現(xiàn)有廣播接收器谓罗,那么它到底是如何實(shí)現(xiàn)packages的監(jiān)聽的呢?
LauncherApps的初始化
我們看到在LauncherAppsCompatVL初始化時(shí)季二,通過getSystemService("launcherapps")得到一個(gè)mLauncherApps的系統(tǒng)服務(wù)檩咱。代碼如下:
LauncherAppsCompatVL(Context context) {
super();
mLauncherApps = (LauncherApps) context.getSystemService("launcherapps");
}
看到getSystemService我們可以知道m(xù)LauncherApps是一個(gè)系統(tǒng)服務(wù),那這個(gè)系統(tǒng)服務(wù)到底是何方神圣呢胯舷?
LauncherApps.java位于frameworks/base/core/java/android/content/pm目錄下刻蚯,我們首先看下它的初始化。
public LauncherApps(Context context, ILauncherApps service) {
mContext = context;
mService = service;
mPm = context.getPackageManager();
}
在LauncherApps的構(gòu)造方法中重要做三個(gè)初始化:上下文mContext桑嘶、ILauncherApps及獲取PackageManager對(duì)象炊汹。我們重點(diǎn)關(guān)注mService是如何實(shí)現(xiàn)的,它是如何做到package的監(jiān)聽的呢逃顶?
ILauncherApps的實(shí)現(xiàn)
從上文我們可以知道LauncherApps是作為客戶端通過ILauncherApps獲取服務(wù)端package變化狀態(tài)讨便,那么ILauncherApps這個(gè)接口定義了些什么呢,它又是如何實(shí)現(xiàn)對(duì)package的監(jiān)聽呢以政?我們繼續(xù)往下分析霸褒,首先看下ILauncherApps定義了什么方法:
interface ILauncherApps {
void addOnAppsChangedListener(in IOnAppsChangedListener listener);
void removeOnAppsChangedListener(in IOnAppsChangedListener listener);
List<ResolveInfo> getLauncherActivities(String packageName, in UserHandle user);
ResolveInfo resolveActivity(in Intent intent, in UserHandle user);
void startActivityAsUser(in ComponentName component, in Rect sourceBounds,
in Bundle opts, in UserHandle user);
void showAppDetailsAsUser(in ComponentName component, in Rect sourceBounds,
in Bundle opts, in UserHandle user);
boolean isPackageEnabled(String packageName, in UserHandle user);
boolean isActivityEnabled(in ComponentName component, in UserHandle user);
}
我們看到在這個(gè)接口中有addOnAppsChangedListener和removeOnAppsChangedListener這兩個(gè)方法及其他一些方法(我們暫時(shí)不關(guān)心),我們只關(guān)心addOnAppsChangedListener和removeOnAppsChangedListener這兩個(gè)方法盈蛮,通過名字我們可以猜測(cè)這應(yīng)該就是我們要找的package監(jiān)聽器的添加和刪除方法
傲霸。那么接下來我們來看下ILauncherApps接口的實(shí)現(xiàn)。其實(shí)現(xiàn)類LauncherAppsImpl是在LauncherAppsService的內(nèi)部類,代碼路徑是frameworks/base/services/core/java/com/android/server/pm/,LauncherAppsService是繼承自SystemService昙啄,主要用來處理適配到當(dāng)前配置文件(管理不同的user)的launcher發(fā)出的請(qǐng)求及回調(diào)。
class LauncherAppsImpl extends ILauncherApps.Stub {
...//省略不必要的代碼
public void addOnAppsChangedListener(IOnAppsChangedListener listener) throws RemoteException {
synchronized (mListeners) {
if (DEBUG) {
Log.d(TAG, "Adding listener from " + Binder.getCallingUserHandle());
}
if (mListeners.getRegisteredCallbackCount() == 0) {
if (DEBUG) {
Log.d(TAG, "Starting package monitoring");
}
startWatchingPackageBroadcasts();
}
mListeners.unregister(listener);
mListeners.register(listener, Binder.getCallingUserHandle());
}
}
public void removeOnAppsChangedListener(IOnAppsChangedListener listener)
throws RemoteException {
synchronized (mListeners) {
if (DEBUG) {
Log.d(TAG, "Removing listener from " + Binder.getCallingUserHandle());
}
mListeners.unregister(listener);
if (mListeners.getRegisteredCallbackCount() == 0) {
stopWatchingPackageBroadcasts();
}
}
}
...//省略不必要的代碼
}
在addOnAppsChangedListener方法中寸五,當(dāng)當(dāng)前注冊(cè)的Callback個(gè)數(shù)為0時(shí)梳凛,會(huì)調(diào)用startWatchingPackageBroadcasts()方法,也就是啟動(dòng)一個(gè)廣播監(jiān)聽梳杏,我們來看下這個(gè)廣播監(jiān)聽是如何實(shí)現(xiàn)的韧拒。
廣播監(jiān)聽
startWatchingPackageBroadcasts方法的具體實(shí)現(xiàn):
private void startWatchingPackageBroadcasts() {
mPackageMonitor.register(mContext, null, UserHandle.ALL, true);
}
在startWatchingPackageBroadcasts方法中使用了成員變量mPackageMonitor的register方法來實(shí)現(xiàn)廣播注冊(cè)。mPackageMonitor是LauncherAppsService的一個(gè)私有內(nèi)部類十性,繼承自PackageMonitor叛溢,mPackageMonitor的register方法來自父類PackageMonitor。
//廣播的intent過濾
static {
sPackageFilt.addAction(Intent.ACTION_PACKAGE_ADDED);
sPackageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED);
sPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED);
sPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
sPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED);
sPackageFilt.addDataScheme("package");
sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED);
sNonDataFilt.addAction(Intent.ACTION_USER_STOPPED);
sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
}
//PackageMonitor的register方法實(shí)現(xiàn)
public void register(Context context, Looper thread, UserHandle user,
boolean externalStorage) {
if (mRegisteredContext != null) {
throw new IllegalStateException("Already registered");
}
mRegisteredContext = context;
if (thread == null) {
mRegisteredHandler = BackgroundThread.getHandler();
} else {
mRegisteredHandler = new Handler(thread);
}
if (user != null) {
context.registerReceiverAsUser(this, user, sPackageFilt, null, mRegisteredHandler);
context.registerReceiverAsUser(this, user, sNonDataFilt, null, mRegisteredHandler);
if (externalStorage) {
context.registerReceiverAsUser(this, user, sExternalFilt, null,
mRegisteredHandler);
}
} else {
context.registerReceiver(this, sPackageFilt, null, mRegisteredHandler);
context.registerReceiver(this, sNonDataFilt, null, mRegisteredHandler);
if (externalStorage) {
context.registerReceiver(this, sExternalFilt, null, mRegisteredHandler);
}
}
}
至此我們已經(jīng)明白了L及以上版本的launcher3其實(shí)也是通過廣播監(jiān)聽來實(shí)現(xiàn)監(jiān)聽package的變化的劲适。那么這樣做的優(yōu)勢(shì)是什么呢楷掉?在我看來主要是添加對(duì)不同用戶的監(jiān)聽, 從上邊的代碼我們就可已看出在注冊(cè)監(jiān)聽的時(shí)候是有參數(shù)user的霞势。而L之前的廣播監(jiān)聽是沒有這樣做烹植,也就無法達(dá)到對(duì)不同user的精確監(jiān)聽。
當(dāng)我們監(jiān)聽到有package變化的時(shí)候愕贡,Launcher是如何實(shí)現(xiàn)圖標(biāo)的添加草雕、刪除等操作的呢?我們繼續(xù)回到LauncherAppsImpl的addOnAppsChangedListener和removeOnAppsChangedListener方法固以,我們可以看到這兩個(gè)方法的參數(shù)IOnAppsChangedListener也是一個(gè)AIDL定義的一個(gè)接口墩虹,那么這個(gè)接口到底干了什么呢?
IOnAppsChangedListener接口的實(shí)現(xiàn)
首先我們先看下這個(gè)接口中定義了哪些方法:
oneway interface IOnAppsChangedListener {
void onPackageRemoved(in UserHandle user, String packageName);
void onPackageAdded(in UserHandle user, String packageName);
void onPackageChanged(in UserHandle user, String packageName);
void onPackagesAvailable(in UserHandle user, in String[] packageNames, boolean replacing);
void onPackagesUnavailable(in UserHandle user, in String[] packageNames, boolean replacing);
}
我們看到它是使用oneway關(guān)鍵字定義的接口憨琳,這就表明它的所有方法都采用非阻塞式方式诫钓。在這個(gè)監(jiān)聽接口中我們找到了監(jiān)聽package變化的五個(gè)方法。那這些監(jiān)聽時(shí)如何實(shí)現(xiàn)的呢栽渴?我們接下來看下IOnAppsChangedListener的實(shí)現(xiàn)方法尖坤。
IOnAppsChangedListener的實(shí)現(xiàn)是在frameworks/base/core/java/android/content/pm/LauncherApps.java
private IOnAppsChangedListener.Stub mAppsChangedListener = new IOnAppsChangedListener.Stub() {
public void onPackageRemoved(UserHandle user, String packageName)
throws RemoteException {
if (DEBUG) {
Log.d(TAG, "onPackageRemoved " + user.getIdentifier() + "," + packageName);
}
synchronized (LauncherApps.this) {
for (CallbackMessageHandler callback : mCallbacks) {
callback.postOnPackageRemoved(packageName, user);
}
}
}
...//省略其他方法
}
在這個(gè)方法中我們看到它是通過CallbackMessageHandler來處理package變化的消息,CallbackMessageHandler是LauncherApps的一個(gè)內(nèi)部類闲擦,繼承自Handler慢味。具體實(shí)現(xiàn)如下所示:
private static class CallbackMessageHandler extends Handler {
...//省略其他代碼
private static final int MSG_REMOVED = 2;
private LauncherApps.Callback mCallback;
private static class CallbackInfo {
String[] packageNames;
String packageName;
boolean replacing;
UserHandle user;
}
public CallbackMessageHandler(Looper looper, LauncherApps.Callback callback) {
super(looper, null, true);
mCallback = callback;
}
@Override
public void handleMessage(Message msg) {
if (mCallback == null || !(msg.obj instanceof CallbackInfo)) {
return;
}
CallbackInfo info = (CallbackInfo) msg.obj;
switch (msg.what) {
...//省略其他選擇
case MSG_REMOVED:
mCallback.onPackageRemoved(info.packageName, info.user);
break;
}
}
public void postOnPackageRemoved(String packageName, UserHandle user) {
CallbackInfo info = new CallbackInfo();
info.packageName = packageName;
info.user = user;
obtainMessage(MSG_REMOVED, info).sendToTarget();
}
...//省略其他代碼
在handleMessage方法中,是通過回調(diào)的方式來調(diào)用onPackageRemoved方法的墅冷。CallbackMessageHandler的構(gòu)造方法中傳進(jìn)來的是LauncherApps.Callback纯路,也就是我們的mCallback,那么這個(gè)callback到底是在什么地方實(shí)現(xiàn)的呢寞忿?
pacakge變化的回調(diào)實(shí)現(xiàn)
我們回到Launcher3的源碼驰唬,在類LauncherAppsCompatVL中有方法addOnAppsChangedCallback,在這個(gè)方法中LauncherApps調(diào)用registerCallback,將回調(diào)注冊(cè)到CallbackMessageHandler叫编。
public void registerCallback(Callback callback, Handler handler) {
synchronized (this) {
if (callback != null && findCallbackLocked(callback) < 0) {
boolean addedFirstCallback = mCallbacks.size() == 0;
addCallbackLocked(callback, handler);
if (addedFirstCallback) {
try {
mService.addOnAppsChangedListener(mAppsChangedListener);
} catch (RemoteException re) {
}
}
}
}
}
那么LauncherAppsCompatVL的addOnAppsChangedCallback是在什么時(shí)候調(diào)用的呢辖佣?在LauncherAppState的構(gòu)造方法中有調(diào)用addOnAppsChangedCallback,參數(shù)是LauncherModel搓逾。
//LauncherAppsState構(gòu)造方法中調(diào)用addOnAppsChangedCallback
LauncherAppsCompat.getInstance(sContext).addOnAppsChangedCallback(mModel);
LauncherModel實(shí)現(xiàn)了LauncherAppsCompat.OnAppsChangedCallbackCompat的接口卷谈。
//LauncherAppsCompat.OnAppsChangedCallbackCompat的接口
public interface OnAppsChangedCallbackCompat {
void onPackageRemoved(String packageName, UserHandleCompat user);
void onPackageAdded(String packageName, UserHandleCompat user);
void onPackageChanged(String packageName, UserHandleCompat user);
void onPackagesAvailable(String[] packageNames, UserHandleCompat user, boolean replacing);
void onPackagesUnavailable(String[] packageNames, UserHandleCompat user, boolean replacing);
}
通過上面的分析我們可以看到,當(dāng)package變化最終調(diào)用到的是LauncherModel中實(shí)現(xiàn)的以上接口霞篡,我們以onPackageRemoved為例來看下LauncherModel中的實(shí)現(xiàn)世蔗。
LauncherModel對(duì)package變化的處理
我們首先來看下LauncherModel中onPackageRemoved的實(shí)現(xiàn)。
public void onPackageRemoved(String packageName, UserHandleCompat user) {
int op = PackageUpdatedTask.OP_REMOVE;
enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName },
user));
}
在該方法中會(huì)初始化一個(gè)PackageUpdatedTask朗兵,這是LauncherModel中一個(gè)繼承自Runnable接口的內(nèi)部類污淋,然后通過Handler.post(Runnable)來執(zhí)行。根據(jù)傳進(jìn)來變量PackageUpdatedTask.OP_REMOVE余掖,PackageUpdatedTask會(huì)對(duì)當(dāng)前user的配置文件寸爆、IconCache、桌面圖標(biāo)等進(jìn)行清除操作浊吏。后邊我們會(huì)針對(duì)這一過程專門討論而昨。
總結(jié)
Android L及以上版本,Launcher3通過獲取launcherapps系統(tǒng)服務(wù)找田,監(jiān)聽package變化歌憨。而在系統(tǒng)服務(wù)launcherapps也是通PackageMonitor注冊(cè)廣播來進(jìn)行package的監(jiān)聽,和之前版本最大的變化其實(shí)是針對(duì)不同用戶的不同package進(jìn)行監(jiān)聽墩衙。