本文我们来看下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. 【Qt】ubuntu14.04+qt5.6+opencv2.4编程注意事项
  2. 工业富联2018年报来了!上市后首张成绩单大起底
  3. POJ 1989 贪心
  4. 接口里面的静态方法--痒啊
  5. 汇编语言之寄存器使用(bx,si,di,bp)
  6. 安装sql server 2008 报错
  7. 海南橡胶机器人成本_完成专利授权20余件!海南橡胶中橡科技搭建高标准研发平台...
  8. 子类能否访问或覆盖父类的private方法
  9. 浏览器自定义css代码,根据浏览器不同设置CSS
  10. 如何在Java中检查字符串是否为数字?
  11. 包含目录、库目录、附加包含目录、附加库目录、附加依赖项如何使用? 及静态库,动态库的创建与调用和vs里引用的使用
  12. 尼尔森十大可用性原则
  13. android tv 蓝牙服务_Android TV Remote Service
  14. win10下乌龟git安装和使用
  15. Svn内外网切换技巧
  16. 请领导批阅文件怎么说_汇报措辞:你懂得怎样向领导汇报吗(审阅、审批、批阅、批示、查阅)?...
  17. pycharm中TODO注释
  18. flutter 单线程异步 及 isolate 使用过程遇到的问题
  19. 这7个关键点,是每个产品用户体验设计的重中之重
  20. 手把手教你用Python打造一个语音合成系统(已生成软件)

热门文章

  1. 6. EL 表达式:${运算表达式}
  2. iOS -录音-音频的拼接剪切以及边录边压缩转码
  3. 地震勘探基础(一)之地震波
  4. 洗脑最厉害的10句名言,真是不服不行啊!
  5. 利用DirectSound实现声卡录音【老毕改版】【Part1】
  6. 计算机等级考试 公共基础知识资料
  7. APP测试基本流程以及要点梳理,保证您看了不后悔
  8. Ubuntu16.04使用apt get 命令安装 Nvidia 显卡驱动提示“更换介质:请把标有......”解决办法
  9. CMakeLists添加目录
  10. 我祖上三代都是以打鸟为生的