Android:如何获取已安装活动的列表,就像它们出现在启动器中一样,没有重复

Posted

技术标签:

【中文标题】Android:如何获取已安装活动的列表,就像它们出现在启动器中一样,没有重复【英文标题】:Android: How to get a list of installed activities, as they appear in launcher, without duplicates 【发布时间】:2012-04-11 21:06:08 【问题描述】:

我正在编写一个应用程序,它允许用户查看已安装应用程序的列表,选择其中一个,然后按计划启动它。使用来自 *** 的教程,我设法弄清楚如何获取已安装活动的列表、它们的包名称和图标(即 here - 几种方法)。以防万一,这就是我开始活动的方式,它完美无缺,在这里没问题:

Intent launchIntent = packageManager.getLaunchIntentForPackage(packageName);
launchIntent.setAction(Intent.ACTION_MAIN);
launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(launchIntent);

问题在于检索已安装应用程序的列表。我找到了两种获取已安装应用程序列表的方法:

1) 使用

PackageManager pm = getPackageManager();
List<ApplicationInfo> apps = pm.getInstalledApplication(PackageManager.GET_META_DATA) 

apps 的每个元素中,您可以获得它的包名和包标签(应用程序名称)。

2) 使用

PackageManager pm = getPackageManager();    
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(mainIntent, 0);
for(ResolveInfo info : resolveInfos) 
    ApplicationInfo applicationInfo = info.activityInfo.applicationInfo;
    //...
    //get package name, icon and label from applicationInfo object    

first 方法存在问题:它返回所有已安装的包,包括系统服务,这些包可能不包含任何活动,因此无法启动。这是带有示例的屏幕截图:

以上所有没有图标的项目都不能启动。

second 方法也存在问题:列表中的多个项目有重复项:

当我在调试器中设置断点时,我看到这些“地图”项目具有不同的活动名称(“com.google.android.maps.MapsActivity”、“com.google.android.maps.LatitudeActivity”、“ com.google.android.maps.PlacesActivity”等)。

我决定使用第二种方法,因为它提供了一个更适合我需要的列表,但我找不到过滤重复项并仅显示应用程序的默认活动的方法,因为它们出现在启动器中(您只能在手机的应用程序列表中看到一个“地图”,而不是四个)。我已经尝试通过ApplicationInfo.FLAG_SYSTEM 过滤掉系统应用程序,但这会删除我想要拥有的许多应用程序,包括地图和其他预装的应用程序。我在执行 queryIntentActivities 时尝试使用PackageManager.MATCH_DEFAULT_ONLY 标志,但这也过滤掉了许多应用程序,只留下了一些。

我有点迷路了,我不知道该怎么办。我已阅读 *** 上有关检索已安装应用程序列表的所有问题,但从未提出过这个问题。请帮助任何人?如何检索没有重复的已安装可启动应用的列表?

【问题讨论】:

你说“这个问题从来没有被提出过”。请检查一下,也许有帮助:***.com/questions/4598769/list-of-user-installed-apps/… 我的意思是列表中的重复项,我没有看到有人提到这一点。是的,我看到了该评论,我尝试使用 ApplicationInfo.FLAG_SYSTEM 跳过应用程序,但由于某种原因,这会删除许多有效的应用程序,包括游戏等。 【参考方案1】:
Intent localIntent2 = new Intent(Intent.ACTION_PICK_ACTIVITY);
Intent localIntent3 = new Intent(Intent.ACTION_MAIN, null);
localIntent3.addCategory(Intent.CATEGORY_LAUNCHER); 
localIntent2.putExtra(Intent.EXTRA_INTENT, localIntent3);
startActivityForResult(localIntent2, 1);

试试这个代码。它只会列出所有安装在您设备中的应用程序。

【讨论】:

它可以工作,但如果您能够设法运行所选的应用程序,这将更有效。因为到目前为止,当您选择一个应用程序时,什么都没有发生。 不错的答案,但避免使用硬编码字符串,而是使用常量,例如 Intent.EXTRA_INTENT 用于“android.intent.extra.INTENT”。【参考方案2】:

我可能会迟到,但我刚刚找到了一种完美的方法,让所有应用程序都具有启动器并且没有重复的应用程序(包括联系人、地图等系统应用程序)。 虽然,Satheesh 的回答可能有效(我自己没有检查过),但我想选择多个活动,所以我使用下面的代码来安装应用程序。

我使用了您的第二种方法并使用 HashSet 丢弃了重复的包。 这是最终代码:

    final PackageManager packageManager = getPackageManager();
    Intent intent = new Intent(Intent.ACTION_MAIN, null);
    intent.addCategory(Intent.CATEGORY_LAUNCHER);
    List<ResolveInfo> resInfos = packageManager.queryIntentActivities(intent, 0);
    //using hashset so that there will be no duplicate packages, 
    //if no duplicate packages then there will be no duplicate apps
    HashSet<String> packageNames = new HashSet<String>(0);
    List<ApplicationInfo> appInfos = new ArrayList<ApplicationInfo>(0);

    //getting package names and adding them to the hashset
    for(ResolveInfo resolveInfo : resInfos) 
        packageNames.add(resolveInfo.activityInfo.packageName);
    

    //now we have unique packages in the hashset, so get their application infos
    //and add them to the arraylist
    for(String packageName : packageNames) 
        try 
            appInfos.add(packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA));
         catch (NameNotFoundException e) 
            //Do Nothing
        
    

    //to sort the list of apps by their names
    Collections.sort(appInfos, new ApplicationInfo.DisplayNameComparator(packageManager));

【讨论】:

【参考方案3】:

试试下面的代码,让我知道发生了什么。

PackageManager manager = getPackageManager();
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);

List<ResolveInfo> resolveInfos= manager.queryIntentActivities(mainIntent, 0);
// Below line is new code i added to your code
Collections.sort(resolveInfos, new ResolveInfo.DisplayNameComparator(manager));

for(ResolveInfo info : resolveInfos) 
     ApplicationInfo applicationInfo = info.activityInfo.applicationInfo;
     //...
     //get package name, icon and label from applicationInfo object    

【讨论】:

嗨,这里是发生的截图:i.stack.imgur.com/xCXqY.png 列表中还有 4 个“地图”,但现在它们是随机排列的。【参考方案4】:

@Ashish Tanna 和 jozze 都是对的,但性能可能有点问题。

这是性能最好的一个。

Set<String> packageNameSet = new HashSet<>();
PackageManager pm = context.getPackageManager();
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> resolveInfos = packageManager.queryIntentActivities(mainIntent, 0);
for(ResolveInfo info : resolveInfos) 
    // be added
    ApplicationInfo applicationInfo;
    if (info == null || (applicationInfo = info.activityInfo.applicationInfo) == null
            || !applicationInfo.enabled || packageNameSet.contains(applicationInfo.packageName)) 
        continue;
    
    packageNameSet.add(applicationInfo.packageName);

    //...
    //get package name, icon and label from applicationInfo object

(1) 添加一个 HashSet (2)判断应用是否开启 (3)判断hashset里面是否有

【讨论】:

【参考方案5】:

我也有同样的要求。最终,我添加了另一个条件来过滤应用列表。我刚刚检查了该应用是否具有“启动器意图”。

所以,生成的代码看起来像......

PackageManager pm = getPackageManager();
List<ApplicationInfo> apps = pm.getInstalledApplications(PackageManager.GET_GIDS);

for (ApplicationInfo app : apps) 
    if(pm.getLaunchIntentForPackage(app.packageName) != null) 
        // apps with launcher intent
        if((app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) == 1) 
            // updated system apps
         else if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 1) 
            // system apps
         else 
            // user installed apps
        
        appsList.add(app);
    


【讨论】:

以上是关于Android:如何获取已安装活动的列表,就像它们出现在启动器中一样,没有重复的主要内容,如果未能解决你的问题,请参考以下文章

如何获取 Android 11 中已安装应用程序的列表

如何获取已购买的应用列表,包括价格? [复制]

如何获取用户在 Android 设备上安装的应用程序列表?

如何获取列表视图的所有项目及其位置并将它们意图用于另一个活动,并且可以转到下一个和后退位置

如何在列表视图的每个项目上加载 json 数据并显示在 android 的另一个活动中获取的数据?

Subversion:如何获取所有活动的,未合并的分支的列表