当前位置:   article > 正文

Launcher3应用列表数据加载_launcherapps.getactivitylist

launcherapps.getactivitylist

本文我们详细看看应用列表的加载过程,代码是基于高通7.1。先前的文章我们分析过Launcher3数据的加载,知道应用列表数据加载的起点是在LauncherModel的loadAndBindAllApps()开始的,该方法会调用loadAllApps()。

  1. packages\apps\Launcher3\src\com\android\launcher3\LauncherModel.java
  2. private void loadAllApps() {
  3. ...
  4. mBgAllAppsList.clear();
  5. for (UserHandleCompat user : profiles) {
  6. // Query for the set of apps
  7. final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
  8. final List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);
  9. if (DEBUG_LOADERS) {
  10. Log.d(TAG, "getActivityList took "
  11. + (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);
  12. Log.d(TAG, "getActivityList got " + apps.size() + " apps for user " + user);
  13. }
  14. // Fail if we don't have any apps
  15. // TODO: Fix this. Only fail for the current user.
  16. if (apps == null || apps.isEmpty()) {
  17. return;
  18. }
  19. boolean quietMode = mUserManager.isQuietModeEnabled(user);
  20. // Create the ApplicationInfos
  21. for (int i = 0; i < apps.size(); i++) {
  22. LauncherActivityInfoCompat app = apps.get(i);
  23. // This builds the icon bitmaps.
  24. mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache, quietMode));
  25. }
  26. ...
  27. }
  28. // Huh? Shouldn't this be inside the Runnable below?
  29. final ArrayList<AppInfo> added = mBgAllAppsList.added;
  30. mBgAllAppsList.added = new ArrayList<AppInfo>();
  31. // Post callback on main thread
  32. mHandler.post(new Runnable() {
  33. public void run() {
  34. final long bindTime = SystemClock.uptimeMillis();
  35. final Callbacks callbacks = tryGetCallbacks(oldCallbacks);
  36. if (callbacks != null) {
  37. callbacks.bindAllApplications(added);
  38. if (DEBUG_LOADERS) {
  39. Log.d(TAG, "bound " + added.size() + " apps in "
  40. + (SystemClock.uptimeMillis() - bindTime) + "ms");
  41. }
  42. } else {
  43. Log.i(TAG, "not binding apps: no Launcher activity");
  44. }
  45. }
  46. });
  47. ...
  48. }

函数中调用LauncherAppsCompat.java的getActivityList方法获取所有安装的应用。LauncherAppsCompat是一个抽象类,不同的android版本有不同的处理方式。

  1. //Lollipop之前的版本
  2. packages\apps\Launcher3\src\com\android\launcher3\compat\LauncherAppsCompatV16.java
  3. public List<LauncherActivityInfoCompat> getActivityList(String packageName,
  4. UserHandleCompat user) {
  5. final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
  6. mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
  7. mainIntent.setPackage(packageName);
  8. List<ResolveInfo> infos = mPm.queryIntentActivities(mainIntent, 0);
  9. List<LauncherActivityInfoCompat> list =
  10. new ArrayList<LauncherActivityInfoCompat>(infos.size());
  11. for (ResolveInfo info : infos) {
  12. list.add(new LauncherActivityInfoCompatV16(mContext, info));
  13. }
  14. return list;
  15. }
  16. //以下为Lollipop之后的版本,获取应用的流程
  17. packages\apps\Launcher3\src\com\android\launcher3\compat\LauncherAppsCompatVL.java
  18. public List<LauncherActivityInfoCompat> getActivityList(String packageName,
  19. UserHandleCompat user) {
  20. List<LauncherActivityInfo> list = mLauncherApps.getActivityList(packageName,
  21. user.getUser());
  22. if (list.size() == 0) {
  23. return Collections.emptyList();
  24. }
  25. ArrayList<LauncherActivityInfoCompat> compatList =
  26. new ArrayList<LauncherActivityInfoCompat>(list.size());
  27. for (LauncherActivityInfo info : list) {
  28. compatList.add(new LauncherActivityInfoCompatVL(info));
  29. }
  30. return compatList;
  31. }
  32. frameworks\base\core\java\android\content\pm\LauncherApps.java
  33. public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
  34. logErrorForInvalidProfileAccess(user);
  35. try {
  36. return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(),
  37. packageName, user), user);
  38. } catch (RemoteException re) {
  39. throw re.rethrowFromSystemServer();
  40. }
  41. }
  42. frameworks\base\services\core\java\com\android\server\pm\LauncherAppsService.java
  43. @Override
  44. public ParceledListSlice<ResolveInfo> getLauncherActivities(String callingPackage,
  45. String packageName, UserHandle user)
  46. throws RemoteException {
  47. return queryActivitiesForUser(callingPackage,
  48. new Intent(Intent.ACTION_MAIN)
  49. .addCategory(Intent.CATEGORY_LAUNCHER)
  50. .setPackage(packageName),
  51. user);
  52. }

可以看到最终还是通过PackageManagerService查询出所有安装的应用。之后对mBgAllAppsList填充数据,回调Launcher3的bindAllApplications方法。而该方法只是简单调用了mAppsView.setApps(apps),并没有数据更新时,那个我们常见的Adapter.notifyDataSetChanged()方法调用。别急,我们慢慢来分析,setApps之后做了很多工作,其中比较重要的方法就是

  1. packages\apps\Launcher3\src\com\android\launcher3\allapps\AlphabeticalAppsList.java
  2. /**
  3. * Updates internals when the set of apps are updated.
  4. */
  5. private void onAppsUpdated() {
  6. // Sort the list of apps
  7. mApps.clear();
  8. mApps.addAll(mComponentToAppMap.values());
  9. Collections.sort(mApps, mAppNameComparator.getAppInfoComparator());
  10. // As a special case for some languages (currently only Simplified Chinese), we may need to
  11. // coalesce sections
  12. Locale curLocale = mLauncher.getResources().getConfiguration().locale;
  13. TreeMap<String, ArrayList<AppInfo>> sectionMap = null;
  14. boolean localeRequiresSectionSorting = curLocale.equals(Locale.SIMPLIFIED_CHINESE);
  15. if (localeRequiresSectionSorting) {
  16. // Compute the section headers. We use a TreeMap with the section name comparator to
  17. // ensure that the sections are ordered when we iterate over it later
  18. sectionMap = new TreeMap<>(mAppNameComparator.getSectionNameComparator());
  19. for (AppInfo info : mApps) {
  20. // Add the section to the cache
  21. String sectionName = getAndUpdateCachedSectionName(info.title);
  22. // Add it to the mapping
  23. ArrayList<AppInfo> sectionApps = sectionMap.get(sectionName);
  24. if (sectionApps == null) {
  25. sectionApps = new ArrayList<>();
  26. sectionMap.put(sectionName, sectionApps);
  27. }
  28. sectionApps.add(info);
  29. }
  30. // Add each of the section apps to the list in order
  31. List<AppInfo> allApps = new ArrayList<>(mApps.size());
  32. for (Map.Entry<String, ArrayList<AppInfo>> entry : sectionMap.entrySet()) {
  33. allApps.addAll(entry.getValue());
  34. }
  35. mApps.clear();
  36. mApps.addAll(allApps);
  37. } else {
  38. // Just compute the section headers for use below
  39. for (AppInfo info : mApps) {
  40. // Add the section to the cache
  41. getAndUpdateCachedSectionName(info.title);
  42. }
  43. }
  44. // Recompose the set of adapter items from the current set of apps
  45. updateAdapterItems();
  46. }

一大段的代码都是对mApps进行排序。先按title来排序,如果title一样再对componentName排序,如果是中文则用AlphabeticIndex类来进行处理。具体的就请大家自行看下代码了。我们来看一下最后的updateAdapterItems调用。

  1. packages\apps\Launcher3\src\com\android\launcher3\allapps\AlphabeticalAppsList.java
  2. private void updateAdapterItems() {
  3. SectionInfo lastSectionInfo = null;
  4. String lastSectionName = null;
  5. FastScrollSectionInfo lastFastScrollerSectionInfo = null;
  6. int position = 0;
  7. int appIndex = 0;
  8. // Prepare to update the list of sections, filtered apps, etc.
  9. mFilteredApps.clear();
  10. mFastScrollerSections.clear();
  11. mAdapterItems.clear();
  12. mSections.clear();
  13. if (DEBUG_PREDICTIONS) {
  14. if (mPredictedAppComponents.isEmpty() && !mApps.isEmpty()) {
  15. mPredictedAppComponents.add(new ComponentKey(mApps.get(0).componentName,
  16. UserHandleCompat.myUserHandle()));
  17. mPredictedAppComponents.add(new ComponentKey(mApps.get(0).componentName,
  18. UserHandleCompat.myUserHandle()));
  19. mPredictedAppComponents.add(new ComponentKey(mApps.get(0).componentName,
  20. UserHandleCompat.myUserHandle()));
  21. mPredictedAppComponents.add(new ComponentKey(mApps.get(0).componentName,
  22. UserHandleCompat.myUserHandle()));
  23. }
  24. }
  25. // Add the search divider
  26. mAdapterItems.add(AdapterItem.asSearchDivder(position++));
  27. // Process the predicted app components
  28. mPredictedApps.clear();
  29. if (mPredictedAppComponents != null && !mPredictedAppComponents.isEmpty() && !hasFilter()) {
  30. for (ComponentKey ck : mPredictedAppComponents) {
  31. AppInfo info = mComponentToAppMap.get(ck);
  32. if (info != null) {
  33. mPredictedApps.add(info);
  34. } else {
  35. if (ProviderConfig.IS_DOGFOOD_BUILD) {
  36. Log.e(TAG, "Predicted app not found: " + ck);
  37. }
  38. }
  39. // Stop at the number of predicted apps
  40. if (mPredictedApps.size() == mNumPredictedAppsPerRow) {
  41. break;
  42. }
  43. }
  44. if (!mPredictedApps.isEmpty()) {
  45. // Add a section for the predictions
  46. lastSectionInfo = new SectionInfo();
  47. lastFastScrollerSectionInfo = new FastScrollSectionInfo("");
  48. AdapterItem sectionItem = AdapterItem.asSectionBreak(position++, lastSectionInfo);
  49. mSections.add(lastSectionInfo);
  50. mFastScrollerSections.add(lastFastScrollerSectionInfo);
  51. mAdapterItems.add(sectionItem);
  52. // Add the predicted app items
  53. for (AppInfo info : mPredictedApps) {
  54. AdapterItem appItem = AdapterItem.asPredictedApp(position++, lastSectionInfo,
  55. "", lastSectionInfo.numApps++, info, appIndex++);
  56. if (lastSectionInfo.firstAppItem == null) {
  57. lastSectionInfo.firstAppItem = appItem;
  58. lastFastScrollerSectionInfo.fastScrollToItem = appItem;
  59. }
  60. mAdapterItems.add(appItem);
  61. mFilteredApps.add(info);
  62. }
  63. mAdapterItems.add(AdapterItem.asPredictionDivider(position++));
  64. }
  65. }
  66. // Recreate the filtered and sectioned apps (for convenience for the grid layout) from the
  67. // ordered set of sections
  68. for (AppInfo info : getFiltersAppInfos()) {
  69. String sectionName = getAndUpdateCachedSectionName(info.title);
  70. // Create a new section if the section names do not match
  71. if (lastSectionInfo == null || !sectionName.equals(lastSectionName)) {
  72. lastSectionName = sectionName;
  73. lastSectionInfo = new SectionInfo();
  74. lastFastScrollerSectionInfo = new FastScrollSectionInfo(sectionName);
  75. mSections.add(lastSectionInfo);
  76. mFastScrollerSections.add(lastFastScrollerSectionInfo);
  77. // Create a new section item to break the flow of items in the list
  78. if (!hasFilter()) {
  79. AdapterItem sectionItem = AdapterItem.asSectionBreak(position++, lastSectionInfo);
  80. mAdapterItems.add(sectionItem);
  81. }
  82. }
  83. // Create an app item
  84. AdapterItem appItem = AdapterItem.asApp(position++, lastSectionInfo, sectionName,
  85. lastSectionInfo.numApps++, info, appIndex++);
  86. if (lastSectionInfo.firstAppItem == null) {
  87. lastSectionInfo.firstAppItem = appItem;
  88. lastFastScrollerSectionInfo.fastScrollToItem = appItem;
  89. }
  90. mAdapterItems.add(appItem);
  91. mFilteredApps.add(info);
  92. }
  93. // Append the search market item if we are currently searching
  94. if (hasFilter()) {
  95. if (hasNoFilteredResults()) {
  96. mAdapterItems.add(AdapterItem.asEmptySearch(position++));
  97. } else {
  98. mAdapterItems.add(AdapterItem.asMarketDivider(position++));
  99. }
  100. mAdapterItems.add(AdapterItem.asMarketSearch(position++));
  101. }
  102. // Merge multiple sections together as requested by the merge strategy for this device
  103. mergeSections();
  104. ...
  105. // Refresh the recycler view
  106. if (mAdapter != null) {
  107. mAdapter.notifyDataSetChanged();
  108. }
  109. }

代码很长,耐心多看几遍就可以理解。mPredictedApps是预测apk,就是使用最频繁的几个apk,如果有就先加入到mAdapterItems中;然后就是getFiltersAppInfos(),如果我们正在搜索某个apk,如果关键字匹配,就会返回匹配关键字的所有apk,函数中有一个mSearchResults变量可以用来判断是否正处于搜索状态。如果这个为空则表示不在搜索,此时直接返回排好序的mApps列表。当然函数里面还有一些分割线的相关处理,我们对照下界面布局效果就更好理解。准备好mAdapterItems数据,直接调用我们希望调用的notifyDataSetChanged刷新应用列表。

本文就写到这里了,有不对的地方还请大家评论指出。

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/377125
推荐阅读
相关标签
  

闽ICP备14008679号