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

packages\apps\Launcher3\src\com\android\launcher3\compat\LauncherAppsCompat.javapublic 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@Overrideprotected void onCreate(Bundle savedInstanceState) {...LauncherAppState app = LauncherAppState.getInstance();}
packages\apps\Launcher3\src\com\android\launcher3\LauncherAppState.javaprivate LauncherAppState() {...LauncherAppsCompat.getInstance(sContext).addOnAppsChangedCallback(mModel);}
packages\apps\Launcher3\src\com\android\launcher3\compat\LauncherAppsCompat.javapublic 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@Overridepublic 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 infosif (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组件。卸载的代码也是在这个函数里面,由于流程类似还请大家自行分析。

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

Launcher3应用的安装与卸载相关推荐

  1. python 之 pip、pypdf2 安装与卸载

    pip是个啥? pip 是一个现代的,通用的 Python 包管理工具.提供了对 Python 包的查找.下载.安装.卸载的功能. 第一步:pip 下载:https://pypi.org/projec ...

  2. Android预安装可卸载程序

    /****************************************************************************** Android预安装可卸载程序* 说明: ...

  3. 数据库的概念以及MYSQL的安装和卸载

    一.数据库的基本概念: 1.什么是数据库? DataBase,简称DB.是用来存储和管理数据的仓库. 2.数据库的特点: 持久化存储数据的.其实数据库就是一个文件系统. 方便存储和管理数据 使用了统一 ...

  4. mysql.msi卸载_MySql安装与卸载的详细教程

    本文为大家分享了MySql安装与卸载的教程,供大家参考,具体内容如下 一.MYSQL的安装 1.打开下载的mysql安装文件,双击运行mysql-5.5.40-win32.msi. 2.选择安装类型, ...

  5. R包操作相关:安装、卸载、加载、移除、已经安装的包、包的路径、函数查看等

    R包操作相关:安装.卸载.加载.移除.已经安装的包.包的路径.函数查看等 查看已经加载的R包: (.packages()) 列出包所在的路径: .libPaths() 查看已经安装的包的详细信息: i ...

  6. mysql 安装卸载_MySQL(一)——安装、卸载以及基本操作

    安装 如果在安装的过程中缺少依赖:https://www.microsoft.com/zh-cn/download/details.aspx?id=40784 数据库已经安装完成,路径 C:\Prog ...

  7. Android实践 -- 监听应用程序的安装、卸载

    监听应用程序的安装.卸载 在AndroidManifest.xml中注册一个静态广播,监听安装的广播 android.intent.action.PACKAGE_ADDED 监听程序卸载的广播 and ...

  8. 第十章 Linux下RPM软件的安装与卸载

    第十章 Linux下RPM软件的安装与卸载 第一节 RPM软件包安装 rpm命名原则 如: vsftpd-3.0.2-9.el7.x86_64.rpm vsftpd 3.0.2 9 e17 x86_6 ...

  9. Android代码实现APK文件的安装与卸载

    Android代码实现APK文件的安装与卸载 Android程序使用代码的安装和卸载!!! 安装: String str = "/CanavaCancel.apk"; String ...

最新文章

  1. 虚拟化部署之灵活应用Hyper-V快照
  2. Android selector
  3. cropbox php,jQuery用户头像裁剪插件cropbox.js实例分享
  4. [转]Vi 教程(Unix行编辑器)
  5. 苹果数据线不能充电_外媒痛批苹果!iPhone 12不送充电器绝非为环保,理由太真实!|充电器|数据线|手机|iphone...
  6. Flink专题-Source
  7. 广义表及其存储方式简介
  8. 分布式锁的几种实现方式~
  9. python 水位_Leetcode 42. 接雨水 - python - 递归 查找分水岭
  10. Spring事务管理知识概述
  11. MyEclipse IDEA 安装 激活JRebel工具
  12. xposed环境搭建
  13. HDU1874 畅通工程续【Dijkstra算法】
  14. 平安科技一轮等多久_科技正等着我们成长
  15. Win7安装RNDIS驱动
  16. matlab常用符号意思,matlab常用的符号
  17. 阿里云主要产品及功能介绍,阿里云产品分为6大分类:云计算基础/安全/大数据/人工智能/企业应用/物联网...
  18. LabVIEW编程LabVIEW开发以编程方式将前面板移动到所需位置
  19. SNETCracker:开源的超级弱口令检查审计工具,支持批量多线程
  20. JdbcTemplate空指针异常

热门文章

  1. 0 2JavaScript
  2. Mybatis代码实例
  3. 虚拟环境工具pyenv的安装,配置和使用,完美控制python版本
  4. tomcat manager 禁止外网访问 只容许内网访问
  5. android 手电筒
  6. java+ssm基于微信小程序的校内商铺购物商城系统 uniapp 小程序
  7. 漫步线性代数二——线性方程的几何形状
  8. Java_输入三个整数x,y,z,请把这三个数由小到大输出
  9. 如何清除主板CMOS
  10. 如何为PDF添加目录