首先根据Launcher3的源码查找卸载后的图标删除流程,看看它在卸载后做了那些事。根据源码查找到LauncherAppState类的构造方法中有个叫LauncherAppsCompat的类,它监听着APP的变化,并且向它注册了一个callback:
LauncherAppsCompat.getInstance(sContext).addOnAppsChangedCallback(mModel);
这里的mModel就是LauncherModel对象,它实现了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);
}
OnAppsChangedCallbackCompat接口有各种回调,其中onPackageRemoved方法就是卸载某一个APK时会回调的方法。紧接着我们看看它在LauncherModel里的实现。
@Override
public void onPackageRemoved(String packageName, UserHandleCompat user) {
int op = PackageUpdatedTask.OP_REMOVE;
enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName }, user));
}
public void enqueueModelUpdateTask(ModelUpdateTask task) {
task.init(mApp, this, sBgDataModel, mBgAllAppsList, mUiExecutor);
runOnWorkerThread(task);
}
它启动了一个叫PackageUpdatedTask的Runnable,我们看看run()方法里面干了些什么。run()方法里面做了很多事情,这里我们只关心卸载相关的逻辑。
switch (mOp) {
case OP_ADD: {
...........................
break;
}
case OP_UPDATE:
............................
break;
case OP_REMOVE: {
ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(context, mUser);
if (heuristic != null) {
heuristic.processPackageRemoved(mPackages);
}
for (int i=0; i<N; i++) {
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);
mIconCache.removeIconsForPkg(packages[i], mUser);
}
// Fall through
}
//注意:这里并没有break,它是直接往下走的
case OP_UNAVAILABLE:
for (int i=0; i<N; i++) {
if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);
mBgAllAppsList.removePackage(packages[i], mUser);
mApp.getWidgetCache().removePackage(packages[i], mUser);
}
break;
}
............................
final ArrayList<AppInfo> removedApps = new ArrayList<AppInfo>();
............................
if (mBgAllAppsList.removed.size() > 0) {
removedApps.addAll(mBgAllAppsList.removed);
mBgAllAppsList.removed.clear();
}
这段逻辑特别要注意的地方是switch里面的OP_REMOVE处理,它是没有break的,它是直接走进了OP_UNAVAILABLE逻辑中,在这里它把这个卸载的应用从所有应用列表中删除mBgAllAppsList.removePackage(packages[i], mUser);
,紧接着下面创建了一个removedApps
的list存放着卸载数据。这个数据是在 mBgAllAppsList.removePackage(packages[i], mUser);
中被添加到mBgAllAppsList.removed
列表中的。
/**
* Remove the apps for the given apk identified by packageName.
*/
public void removePackage(String packageName, UserHandleCompat user) {
final List<AppInfo> data = this.data;
for (int i = data.size() - 1; i >= 0; i--) {
AppInfo info = data.get(i);
final ComponentName component = info.intent.getComponent();
if (info.user.equals(user) && packageName.equals(component.getPackageName())) {
removed.add(info);
data.remove(i);
}
}
}
把卸载的数据放入一个列表存起来干嘛呢?我们继续往下看,中间有一大段是新增和修改APP的处理逻辑,我们直接略过,我们依然只看卸载相关。
final HashSet<String> removedPackages = new HashSet<>();
final HashSet<ComponentName> removedComponents = new HashSet<>();
if (mOp == OP_REMOVE) {
// Mark all packages in the broadcast to be removed
Collections.addAll(removedPackages, packages);
// No need to update the removedComponents as
// removedPackages is a super-set of removedComponents
} else if (mOp == OP_UPDATE) {
// Mark disabled packages in the broadcast to be removed
.....................................
}
if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
ItemInfoMatcher removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser)
.or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
.and(ItemInfoMatcher.ofItemIds(removedShortcuts, true));//
deleteAndBindComponentsRemoved(removeMatch); //关键代码1
// Remove any queued items from the install queue
InstallShortcutReceiver.removeFromInstallQueue(context, removedPackages, mUser);
}
if (!removedApps.isEmpty()) {
// Remove corresponding apps from All-Apps
scheduleCallbackTask(new CallbackTask() {
@Override
public void execute(Callbacks callbacks) {
callbacks.bindAppInfosRemoved(removedApps);//关键代码2
}
});
}
1)首先分析ItemInfoMatcher 是ItemInfo 匹配器,这个匹配器非常有用。
/**
* A utility class to check for {@link ItemInfo}
*/
public abstract class ItemInfoMatcher {
public abstract boolean matches(ItemInfo info, ComponentName cn);
/**
* Filters {@param infos} to those satisfying the {@link #matches(ItemInfo, ComponentName)}.
*/
public final HashSet<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos) {
HashSet<ItemInfo> filtered = new HashSet<>();
for (ItemInfo i : infos) {
if (i instanceof ShortcutInfo) {
ShortcutInfo info = (ShortcutInfo) i;
ComponentName cn = info.getTargetComponent();
if (cn != null && matches(info, cn)) {
filtered.add(info);
}
} else if (i instanceof FolderInfo) {
FolderInfo info = (FolderInfo) i;
for (ShortcutInfo s : info.contents) {
ComponentName cn = s.getTargetComponent();
if (cn != null && matches(s, cn)) {
filtered.add(s);
}
}
} else if (i instanceof LauncherAppWidgetInfo) {
LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;
ComponentName cn = info.providerName;
if (cn != null && matches(info, cn)) {
filtered.add(info);
}
}
}
return filtered;
}
/**
* Returns a new matcher with returns true if either this or {@param matcher} returns true.
*/
public ItemInfoMatcher or(final ItemInfoMatcher matcher) {
final ItemInfoMatcher that = this;
return new ItemInfoMatcher() {
@Override
public boolean matches(ItemInfo info, ComponentName cn) {
return that.matches(info, cn) || matcher.matches(info, cn);
}
};
}
/**
* Returns a new matcher with returns true if both this and {@param matcher} returns true.
*/
public ItemInfoMatcher and(final ItemInfoMatcher matcher) {
final ItemInfoMatcher that = this;
return new ItemInfoMatcher() {
@Override
public boolean matches(ItemInfo info, ComponentName cn) {
return that.matches(info, cn) && matcher.matches(info, cn);
}
};
}
/**
* Returns a new matcher which returns the opposite boolean value of the provided
* {@param matcher}.
*/
public static ItemInfoMatcher not(final ItemInfoMatcher matcher) {
return new ItemInfoMatcher() {
@Override
public boolean matches(ItemInfo info, ComponentName cn) {
return !matcher.matches(info, cn);
}
};
}
public static ItemInfoMatcher ofUser(final UserHandle user) {
return new ItemInfoMatcher() {
@Override
public boolean matches(ItemInfo info, ComponentName cn) {
return info.user.equals(user);
}
};
}
public static ItemInfoMatcher ofComponents(
final HashSet<ComponentName> components, final UserHandle user) {
return new ItemInfoMatcher() {
@Override
public boolean matches(ItemInfo info, ComponentName cn) {
return components.contains(cn) && info.user.equals(user);
}
};
}
public static ItemInfoMatcher ofPackages(
final HashSet<String> packageNames, final UserHandle user) {
return new ItemInfoMatcher() {
@Override
public boolean matches(ItemInfo info, ComponentName cn) {
return packageNames.contains(cn.getPackageName()) && info.user.equals(user);
}
};
}
public static ItemInfoMatcher ofShortcutKeys(final HashSet<ShortcutKey> keys) {
return new ItemInfoMatcher() {
@Override
public boolean matches(ItemInfo info, ComponentName cn) {
return info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT &&
keys.contains(ShortcutKey.fromItemInfo(info));
}
};
}
public static ItemInfoMatcher ofItemIds(
final LongArrayMap<Boolean> ids, final Boolean matchDefault) {
return new ItemInfoMatcher() {
@Override
public boolean matches(ItemInfo info, ComponentName cn) {
return ids.get(info.id, matchDefault);
}
};
}
}
2、关键代码1 - deleteAndBindComponentsRemoved
public void deleteAndBindComponentsRemoved(final ItemInfoMatcher matcher) {
getModelWriter().deleteItemsFromDatabase(matcher);
// Call the components-removed callback
scheduleCallbackTask(new CallbackTask() {
@Override
public void execute(Callbacks callbacks) {
callbacks.bindWorkspaceComponentsRemoved(matcher);
}
});
}
ModelWriter 处理模式更新的类; deleteItemsFromDatabase 按照匹配过滤后的项删除.
/**
* Removes all the items from the database matching {@param matcher}.
*/
public void deleteItemsFromDatabase(ItemInfoMatcher matcher) {
deleteItemsFromDatabase(matcher.filterItemInfos(mBgDataModel.itemsIdMap));
}
/**
* Removes the specified items from the database
*/
public void deleteItemsFromDatabase(final Iterable<? extends ItemInfo> items) {
ModelVerifier verifier = new ModelVerifier();
mWorkerExecutor.execute(() -> {
for (ItemInfo item : items) {
final Uri uri = Favorites.getContentUri(item.id);
mContext.getContentResolver().delete(uri, null, null);
mBgDataModel.removeItem(mContext, item);
verifier.verifyModel();
}
});
}
3)关键代码2 --callbacks.bindAppInfosRemoved(removedApps);
这段代码在调度任务中执行的内容; 而这个任务获取一个callback; 这个call有时谁注册的呢?根据跟踪代码;
scheduleCallbackTask(new CallbackTask() {
@Override
public void execute(Callbacks callbacks) {
callbacks.bindAppInfosRemoved(removedApps);//关键代码2
}
});
/**
* Schedules a {@param task} to be executed on the current callbacks.
*/
public final void scheduleCallbackTask(final CallbackTask task) {
final Callbacks callbacks = mModel.getCallback();
mUiExecutor.execute(() -> {
Callbacks cb = mModel.getCallback();
if (callbacks == cb && cb != null) {
task.execute(callbacks); --->执行关键代码2
}
});
}
根据追踪是在LauncherAppState
类中setLauncher
方法中通过mModel.initialize(launcher);
设置的Callbacks
,实现接口的是Launcher
类,那我们来看看里面是怎么实现的
LauncherAppState.java中
LauncherModel setLauncher(Launcher launcher) {
getLocalProvider(mContext).setLauncherProviderChangeListener(launcher);
mModel.initialize(launcher);
return mModel;
}
LauncherModel.java
/**
* Set this as the current Launcher activity object for the loader.
*/
public void initialize(Callbacks callbacks) {
synchronized (mLock) {
Preconditions.assertUIThread();
mCallbacks = new WeakReference<>(callbacks);
}
}
我们看在Launcher.java中如何实现的呢
@Override
public void bindAppInfosRemoved(final ArrayList<AppInfo> appInfos) {
mAppsView.getAppsStore().removeApps(appInfos);
}
AllappStore.java
/**
* Removes some apps from the list.
*/
public void removeApps(List<AppInfo> apps) {
for (AppInfo app : apps) {
mComponentToAppMap.remove(app.toComponentKey());
}
notifyUpdate();
}
private void notifyUpdate() {
if (mDeferUpdates) {
mUpdatePending = true;
return;
}
int count = mUpdateListeners.size();
for (int i = 0; i < count; i++) {
mUpdateListeners.get(i).onAppsUpdated();
}
}
notifyUpdate通知更新
经过代码跟踪
AllAppsContainerView 构造函数中添加
mAllAppsStore.addUpdateListener(this::onAppsUpdated);
注意:
{
::是java8 中新引入的运算符
- Class::function的时候function是属于Class的,应该是静态方法。
- this::function的funtion是属于这个对象的。
}
private void onAppsUpdated() {
if (FeatureFlags.ALL_APPS_TABS_ENABLED) {
boolean hasWorkApps = false;
for (AppInfo app : mAllAppsStore.getApps()) {
if (mWorkMatcher.matches(app, null)) {
hasWorkApps = true;
break;
}
}
rebindAdapters(hasWorkApps);
}
}
private void rebindAdapters(boolean showTabs, boolean force) {
if (showTabs == mUsingTabs && !force) {
return;
}
replaceRVContainer(showTabs);
mUsingTabs = showTabs;
mAllAppsStore.unregisterIconContainer(mAH[AdapterHolder.MAIN].recyclerView);
mAllAppsStore.unregisterIconContainer(mAH[AdapterHolder.WORK].recyclerView);
if (mUsingTabs) {
mAH[AdapterHolder.MAIN].setup(mViewPager.getChildAt(0), mPersonalMatcher);
mAH[AdapterHolder.WORK].setup(mViewPager.getChildAt(1), mWorkMatcher);
onTabChanged(mViewPager.getNextPage());
} else {
mAH[AdapterHolder.MAIN].setup(findViewById(R.id.apps_list_view), null);
mAH[AdapterHolder.WORK].recyclerView = null;
}
setupHeader();
mAllAppsStore.registerIconContainer(mAH[AdapterHolder.MAIN].recyclerView);
mAllAppsStore.registerIconContainer(mAH[AdapterHolder.WORK].recyclerView);
}
AlphabeticalAppsList 实现了AllAppsStore.OnUpdateListener 并在构造函数中添加
mAllAppsStore.addUpdateListener(this);
/**
* Updates internals when the set of apps are updated.
*/
@Override
public void onAppsUpdated() {
// Sort the list of apps
mApps.clear();
for (AppInfo app : mAllAppsStore.getApps()) {
if (mItemFilter == null || mItemFilter.matches(app, null) || hasFilter()) {
mApps.add(app);
}
}
Collections.sort(mApps, mAppNameComparator);
// As a special case for some languages (currently only Simplified Chinese), we may need to
// coalesce sections
Locale curLocale = mLauncher.getResources().getConfiguration().locale;
boolean localeRequiresSectionSorting = curLocale.equals(Locale.SIMPLIFIED_CHINESE);
if (localeRequiresSectionSorting) {
// Compute the section headers. We use a TreeMap with the section name comparator to
// ensure that the sections are ordered when we iterate over it later
TreeMap<String, ArrayList<AppInfo>> sectionMap = new TreeMap<>(new LabelComparator());
for (AppInfo info : mApps) {
// Add the section to the cache
String sectionName = getAndUpdateCachedSectionName(info.title);
// Add it to the mapping
ArrayList<AppInfo> sectionApps = sectionMap.get(sectionName);
if (sectionApps == null) {
sectionApps = new ArrayList<>();
sectionMap.put(sectionName, sectionApps);
}
sectionApps.add(info);
}
// Add each of the section apps to the list in order
mApps.clear();
for (Map.Entry<String, ArrayList<AppInfo>> entry : sectionMap.entrySet()) {
mApps.addAll(entry.getValue());
}
} else {
// Just compute the section headers for use below
for (AppInfo info : mApps) {
// Add the section to the cache
getAndUpdateCachedSectionName(info.title);
}
}
// Recompose the set of adapter items from the current set of apps
updateAdapterItems();
}
参考:https://www.jianshu.com/p/67d82d56ca1d ,并根据最新代码做了修改.