Android: как получить список установленных действий, как они появляются в пусковой установке, без дубликатов
Я пишу приложение, которое позволяет пользователю просматривать список установленных приложений, выбирать один из них, а затем запускать его по расписанию. Используя учебники из stackoverflow, мне удалось выяснить, как получить список установленных действий, их имена пакетов и значки (т.е. здесь - несколько способов сделать это). На всякий случай, так я начинаю деятельность, она работает безупречно, здесь нет проблем:
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: он возвращает все установленные пакеты, включая системные службы, которые могут не содержать никакой активности и поэтому не могут запускаться. Вот скриншот с примером:
![app list with packages]()
Все элементы, которые не имеют значков, не запускаются.
Существует проблема с подходом второй: несколько элементов в списке имеют дубликаты:
![app list with duplicates]()
Когда я устанавливаю точку останова в отладчике, я вижу, что эти элементы "Карты" имеют разные имена активности ( "com.google.android.maps.MapsActivity", "com.google.android.maps.LatitudeActivity", com.google.android.maps.PlacesActivity "и т.д.).
Я решил использовать второй подход, потому что он дает список, который больше подходит для моих нужд, но я не могу найти способ отфильтровать дубликаты и показывать активность по умолчанию для приложения, поскольку они появляются в Launcher (вы видите только один "Карты" в своем списке приложений, а не четыре). Я пробовал фильтровать системные приложения через ApplicationInfo.FLAG_SYSTEM
, но это удаляет многие приложения, которые я хочу иметь, включая Карты и другие предустановленные приложения. Я попытался использовать флаг PackageManager.MATCH_DEFAULT_ONLY
при выполнении queryIntentActivities, но это также отфильтровывает многие приложения, оставляя всего несколько.
Я немного потерялся здесь, и я не знаю, что делать. Я прочитал все вопросы о stackoverflow о том, как получить список установленных приложений, но этот вопрос так и не был поднят. Пожалуйста, помогите кому-нибудь? Как получить список установленных запущенных приложений, у которых нет дубликатов?
Ответы
Ответ 1
Intent localIntent2 = new Intent("android.intent.action.PICK_ACTIVITY");
Intent localIntent3 = new Intent("android.intent.action.MAIN",null);
localIntent3.addCategory("android.intent.category.LAUNCHER");
localIntent2.putExtra("android.intent.extra.INTENT",localIntent3);
startActivityForResult(localIntent2, 1);
Попробуйте этот код. Он будет перечислять только приложения, все из которых установлены на вашем устройстве.
Ответ 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
}
Ответ 4
У меня было такое же требование. В конечном итоге я добавил еще одно условие для фильтрации списка приложений. Я просто проверил, имеет ли приложение "намерение запуска".
Итак, полученный код выглядит как...
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);
}
}
Ответ 5
Оба @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) Судите, есть ли внутри хэш-сет