Launcher3应用的安装与卸载

本文我们来看下Launcher3应用的安装与卸载的处理流程。应用的安装与卸载是通过PackageManagerService来完成的,在成功安装或者卸载之后它是怎么通知Launcher3更新的呢?关于PackageManagerService那一块我们不作深入分析,我们知道LauncherModel是Launcher3的数据中心继承于BroadcastReceiver并且实现了LauncherAppsCompat.OnAppsChangedCallbackCompat接口,我们来看下接口的具体内容:

packages\apps\Launcher3\src\com\android\launcher3\compat\LauncherAppsCompat.java
    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);
        void onPackagesSuspended(String[] packageNames, UserHandleCompat user);
        void onPackagesUnsuspended(String[] packageNames, UserHandleCompat user);
        void onShortcutsChanged(String packageName, List<ShortcutInfoCompat> shortcuts,
                UserHandleCompat user);
    }

可以看到这个接口包含了所有与apk有关的回调。接下来我们来看下LauncherAppsCompat是怎么注册这个接口的。

packages\apps\Launcher3\src\com\android\launcher3\Launcher.java
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        LauncherAppState app = LauncherAppState.getInstance();
    }
packages\apps\Launcher3\src\com\android\launcher3\LauncherAppState.java
   private LauncherAppState() {
        ...
        LauncherAppsCompat.getInstance(sContext).addOnAppsChangedCallback(mModel);
   }
packages\apps\Launcher3\src\com\android\launcher3\compat\LauncherAppsCompat.java
    public static LauncherAppsCompat getInstance(Context context) {
        synchronized (sInstanceLock) {
            if (sInstance == null) {
                if (Utilities.ATLEAST_LOLLIPOP) {
                    //在V21之后是通过回调来通知应用更新的
                    sInstance = new LauncherAppsCompatVL(context.getApplicationContext());
                } else {
                    //在LOLLIPOP之前是通过注册广播来通知Launcher3应用更新的
                    sInstance = new LauncherAppsCompatV16(context.getApplicationContext());
                }
            }
            return sInstance;
        }
    }

通过代码我们看到不同的版本是通过不同的方式通知应用更新的。LOLLIPOP之前是用广播,之后采取回调的方式,这个过程有机会再详细分析。而在LauncherAppsCompat中通过addOnAppsChangedCallback()将mModel注册回调。所以当有应用安装成功后就会调用LauncherModel的onPackageAdded()方法。

packages\apps\Launcher3\src\com\android\launcher3\LauncherModel.java
    @Override
    public void onPackageChanged(String packageName, UserHandleCompat user) {
        int op = PackageUpdatedTask.OP_UPDATE;
        enqueueItemUpdatedTask(new PackageUpdatedTask(op, new String[] { packageName },
                user));
    }

代码中直接新建了一个PackageUpdatedTask任务,我们来详细分析下这个任务的run()方法。

packages\apps\Launcher3\src\com\android\launcher3\LauncherModel.java
private class PackageUpdatedTask implements Runnable {
        ...
        public void run() {
            if (!mHasLoaderCompletedOnce) {
                // Loader has not yet run.
                return;
            }
            final Context context = mApp.getContext();

            final String[] packages = mPackages;
            final int N = packages.length;
            FlagOp flagOp = FlagOp.NO_OP;
            StringFilter pkgFilter = StringFilter.of(new HashSet<>(Arrays.asList(packages)));
            switch (mOp) {
                case OP_ADD: {
                    for (int i=0; i<N; i++) {
                        if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);
                        mIconCache.updateIconsForPkg(packages[i], mUser);
                        mBgAllAppsList.addPackage(context, packages[i], mUser);
                    }

                    ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(context, mUser);
                    if (heuristic != null) {
                        heuristic.processPackageAdd(mPackages);
                    }
                    break;
                }
                ...
            }
            ArrayList<AppInfo> added = null;
            ArrayList<AppInfo> modified = null;
            final ArrayList<AppInfo> removedApps = new ArrayList<AppInfo>();

            if (mBgAllAppsList.added.size() > 0) {
                added = new ArrayList<>(mBgAllAppsList.added);
                mBgAllAppsList.added.clear();
            }
            ...
            final HashMap<ComponentName, AppInfo> addedOrUpdatedApps = new HashMap<>();

            if (added != null) {
                addAppsToAllApps(context, added);
                for (AppInfo ai : added) {
                    addedOrUpdatedApps.put(ai.componentName, ai);
                }
            }
            ...
            // Update shortcut infos
            if (mOp == OP_ADD || flagOp != FlagOp.NO_OP) {
                final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<ShortcutInfo>();
                final ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<ShortcutInfo>();
                final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<LauncherAppWidgetInfo>();

                synchronized (sBgLock) {
                    for (ItemInfo info : sBgItemsIdMap) {
                        if (info instanceof ShortcutInfo && mUser.equals(info.user)) {
                            ...

                            if (infoUpdated || shortcutUpdated) {
                                updatedShortcuts.add(si);
                            }
                            if (infoUpdated) {
                                updateItemInDatabase(context, si);
                            }
                        } 
                    ...
                }

                bindUpdatedShortcuts(updatedShortcuts, removedShortcuts, mUser);
                if (!removedShortcuts.isEmpty()) {
                    deleteItemsFromDatabase(context, removedShortcuts);
                }
                ...
            }
            ....
            // Notify launcher of widget update. From marshmallow onwards we use AppWidgetHost to
            // get widget update signals.
            if (!Utilities.ATLEAST_MARSHMALLOW &&
                    (mOp == OP_ADD || mOp == OP_REMOVE || mOp == OP_UPDATE)) {
                final Callbacks callbacks = getCallback();
                mHandler.post(new Runnable() {
                    public void run() {
                        Callbacks cb = getCallback();
                        if (callbacks == cb && cb != null) {
                            callbacks.notifyWidgetProvidersChanged();
                        }
                    }
                });
            }
        }
    }

代码很长我们只抽取了关键代码。对于OP_ADD操作mIconCache列表,加入到mBgAllAppsList中,然后调用addAppsToAllApps函数更新应用列表。关于应用列表更新的还请查看另一篇博客。再通过一个循环更新所有的桌面图标,如果有更新的话就保存到数据库,最后发出通知更新widget组件。卸载的代码也是在这个函数里面,由于流程类似还请大家自行分析。

由于本人知识水平有限,本文难免有写的不对的地方,欢迎大家指正。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值