Android: как получить список установленных приложений и показать их пользователю

Я рассмотрел много разных вариантов кода о том, как получить список установленных приложений и показать их в ListView для пользователя, но ни один из них не был успешным для меня. Я хотел бы знать, как это сделать и как добавить к нему флаги (?), Чтобы я мог просто перечислить приложения-шторки, которые имеют разные фильтры намерений, такие как LONG_SEARCH_BUTTON, и иметь возможность просматривать пакет и модуль запуска. класс этого приложения.. если это можно?

Я хотел бы получить полный Java-класс, если кто-то не против поделиться своими знаниями, поскольку попытка собрать воедино кусочки кода становится довольно напряженной! Я кодирую android в течение нескольких месяцев, поэтому я знаю большинство основных вещей (я хотел бы думать...), но не делаю ничего подобного раньше.

2 ответа

Я написал короткое приложение, которое делает именно это... проверить это здесь.

Вот пример кода из документации Android. Пожалуйста, будьте креативны для ваших требований.

/ ** * Этот класс содержит данные для каждого элемента в нашем Loader. */ public static class AppEntry { public AppEntry(загрузчик AppListLoader, информация о ApplicationInfo) { mLoader = загрузчик; mInfo = информация; mApkFile = новый файл (info.sourceDir); }

public ApplicationInfo getApplicationInfo() {
    return mInfo;
}

public String getLabel() {
    return mLabel;
}

public Drawable getIcon() {
    if (mIcon == null) {
        if (mApkFile.exists()) {
            mIcon = mInfo.loadIcon(mLoader.mPm);
            return mIcon;
        } else {
            mMounted = false;
        }
    } else if (!mMounted) {
        // If the app wasn't mounted but is now mounted, reload
        // its icon.
        if (mApkFile.exists()) {
            mMounted = true;
            mIcon = mInfo.loadIcon(mLoader.mPm);
            return mIcon;
        }
    } else {
        return mIcon;
    }

    return mLoader.getContext().getResources().getDrawable(
            android.R.drawable.sym_def_app_icon);
}

@Override public String toString() {
    return mLabel;
}

void loadLabel(Context context) {
    if (mLabel == null || !mMounted) {
        if (!mApkFile.exists()) {
            mMounted = false;
            mLabel = mInfo.packageName;
        } else {
            mMounted = true;
            CharSequence label = mInfo.loadLabel(context.getPackageManager());
            mLabel = label != null ? label.toString() : mInfo.packageName;
        }
    }
}

private final AppListLoader mLoader;
private final ApplicationInfo mInfo;
private final File mApkFile;
private String mLabel;
private Drawable mIcon;
private boolean mMounted; }

/ ** * Выполнить алфавитное сравнение объектов ввода приложения. */ public static final Comparator ALPHA_COMPARATOR = new Comparator() {приватный final Collator sCollator = Collator.getInstance (); @Override public int compare (AppEntry object1, AppEntry object2) {return sCollator.compare (object1.getLabel (), object2.getLabel ()); }};

/ ** * Помощник для определения, изменилась ли конфигурация интересным * образом, поэтому нам нужно перестроить список приложений. */ public static class InterestingConfigChanges {окончательная конфигурация mLastConfiguration = новая конфигурация (); int mLastDensity;

boolean applyNewConfig(Resources res) {
    int configChanges = mLastConfiguration.updateFrom(res.getConfiguration());
    boolean densityChanged = mLastDensity != res.getDisplayMetrics().densityDpi;
    if (densityChanged || (configChanges&(ActivityInfo.CONFIG_LOCALE
            |ActivityInfo.CONFIG_UI_MODE|ActivityInfo.CONFIG_SCREEN_LAYOUT)) != 0)

{mLastDensity = res.getDisplayMetrics (). densityDpi; вернуть истину; } вернуть ложь; }}

/ ** * Вспомогательный класс для поиска интересных изменений в установленных приложениях *, чтобы можно было обновлять загрузчик. * / открытый статический класс PackageIntentReceiver extends BroadcastReceiver {final AppListLoader mLoader;

public PackageIntentReceiver(AppListLoader loader) {
    mLoader = loader;
    IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
    filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
    filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
    filter.addDataScheme("package");
    mLoader.getContext().registerReceiver(this, filter);
    // Register for events related to sdcard installation.
    IntentFilter sdFilter = new IntentFilter();
    sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
    sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
    mLoader.getContext().registerReceiver(this, sdFilter);
}

@Override public void onReceive(Context context, Intent intent) {
    // Tell the loader about the change.
    mLoader.onContentChanged();
} }

/ ** * Пользовательский загрузчик, который загружает все установленные приложения. * / открытый статический класс AppListLoader extends AsyncTaskLoader> { final InterestingConfigChanges mLastConfig = new InterestingConfigChanges(); конечный PackageManager mPm;

List<AppEntry> mApps;
PackageIntentReceiver mPackageObserver;

public AppListLoader(Context context) {
    super(context);

    // Retrieve the package manager for later use; note we don't
    // use 'context' directly but instead the save global application
    // context returned by getContext().
    mPm = getContext().getPackageManager();
}

/**
 * This is where the bulk of our work is done.  This function is
 * called in a background thread and should generate a new set of
 * data to be published by the loader.
 */
@Override public List<AppEntry> loadInBackground() {
    // Retrieve all known applications.
    List<ApplicationInfo> apps = mPm.getInstalledApplications(
            PackageManager.GET_UNINSTALLED_PACKAGES |
            PackageManager.GET_DISABLED_COMPONENTS);
    if (apps == null) {
        apps = new ArrayList<ApplicationInfo>();
    }

    final Context context = getContext();

    // Create corresponding array of entries and load their labels.
    List<AppEntry> entries = new ArrayList<AppEntry>(apps.size());
    for (int i=0; i<apps.size(); i++) {
        AppEntry entry = new AppEntry(this, apps.get(i));
        entry.loadLabel(context);
        entries.add(entry);
    }

    // Sort the list.
    Collections.sort(entries, ALPHA_COMPARATOR);

    // Done!
    return entries;
}

/**
 * Called when there is new data to deliver to the client.  The
 * super class will take care of delivering it; the implementation
 * here just adds a little more logic.
 */
@Override public void deliverResult(List<AppEntry> apps) {
    if (isReset()) {
        // An async query came in while the loader is stopped.  We
        // don't need the result.
        if (apps != null) {
            onReleaseResources(apps);
        }
    }
    List<AppEntry> oldApps = apps;
    mApps = apps;

    if (isStarted()) {
        // If the Loader is currently started, we can immediately
        // deliver its results.
        super.deliverResult(apps);
    }

    // At this point we can release the resources associated with
    // 'oldApps' if needed; now that the new result is delivered we
    // know that it is no longer in use.
    if (oldApps != null) {
        onReleaseResources(oldApps);
    }
}

/**
 * Handles a request to start the Loader.
 */
@Override protected void onStartLoading() {
    if (mApps != null) {
        // If we currently have a result available, deliver it
        // immediately.
        deliverResult(mApps);
    }

    // Start watching for changes in the app data.
    if (mPackageObserver == null) {
        mPackageObserver = new PackageIntentReceiver(this);
    }

    // Has something interesting in the configuration changed since we
    // last built the app list?
    boolean configChange = mLastConfig.applyNewConfig(getContext().getResources());

    if (takeContentChanged() || mApps == null || configChange) {
        // If the data has changed since the last time it was loaded
        // or is not currently available, start a load.
        forceLoad();
    }
}

/**
 * Handles a request to stop the Loader.
 */
@Override protected void onStopLoading() {
    // Attempt to cancel the current load task if possible.
    cancelLoad();
}

/**
 * Handles a request to cancel a load.
 */
@Override public void onCanceled(List<AppEntry> apps) {
    super.onCanceled(apps);

    // At this point we can release the resources associated with 'apps'
    // if needed.
    onReleaseResources(apps);
}

/**
 * Handles a request to completely reset the Loader.
 */
@Override protected void onReset() {
    super.onReset();

    // Ensure the loader is stopped
    onStopLoading();

    // At this point we can release the resources associated with 'apps'
    // if needed.
    if (mApps != null) {
        onReleaseResources(mApps);
        mApps = null;
    }

    // Stop monitoring for changes.
    if (mPackageObserver != null) {
        getContext().unregisterReceiver(mPackageObserver);
        mPackageObserver = null;
    }
}

/**
 * Helper function to take care of releasing resources associated
 * with an actively loaded data set.
 */
protected void onReleaseResources(List<AppEntry> apps) {
    // For a simple List<> there is nothing to do.  For something
    // like a Cursor, we would close it here.
} }

Ниже приведен пример реализации фрагмента, который использует вышеуказанный загрузчик для отображения установленных приложений в списке.

открытый статический класс AppListAdapter extends ArrayAdapter { private final LayoutInflater mInflater;

public AppListAdapter(Context context) {
    super(context, android.R.layout.simple_list_item_2);
    mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

public void setData(List<AppEntry> data) {
    clear();
    if (data != null) {
        addAll(data);
    }
}

/**
 * Populate new items in the list.
 */
@Override public View getView(int position, View convertView, ViewGroup parent) {
    View view;

    if (convertView == null) {
        view = mInflater.inflate(R.layout.list_item_icon_text, parent, false);
    } else {
        view = convertView;
    }

    AppEntry item = getItem(position);
    ((ImageView)view.findViewById(R.id.icon)).setImageDrawable(item.getIcon());
    ((TextView)view.findViewById(R.id.text)).setText(item.getLabel());

    return view;
} }

открытый статический класс AppListFragment расширяет ListFragment, реализует OnQueryTextListener, LoaderManager.LoaderCallbacks> {

// This is the Adapter being used to display the list's data.
AppListAdapter mAdapter;

// If non-null, this is the current filter the user has provided.
String mCurFilter;

@Override public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    // Give some text to display if there is no data.  In a real
    // application this would come from a resource.
    setEmptyText("No applications");

    // We have a menu item to show in action bar.
    setHasOptionsMenu(true);

    // Create an empty adapter we will use to display the loaded data.
    mAdapter = new AppListAdapter(getActivity());
    setListAdapter(mAdapter);

    // Start out with a progress indicator.
    setListShown(false);

    // Prepare the loader.  Either re-connect with an existing one,
    // or start a new one.
    getLoaderManager().initLoader(0, null, this);
}

@Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    // Place an action bar item for searching.
    MenuItem item = menu.add("Search");
    item.setIcon(android.R.drawable.ic_menu_search);
    item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM
            | MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
    SearchView sv = new SearchView(getActivity());
    sv.setOnQueryTextListener(this);
    item.setActionView(sv);
}

@Override public boolean onQueryTextChange(String newText) {
    // Called when the action bar search text has changed.  Since this
    // is a simple array adapter, we can just have it do the filtering.
    mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
    mAdapter.getFilter().filter(mCurFilter);
    return true;
}

@Override public boolean onQueryTextSubmit(String query) {
    // Don't care about this.
    return true;
}

@Override public void onListItemClick(ListView l, View v, int position, long id) {
    // Insert desired behavior here.
    Log.i("LoaderCustom", "Item clicked: " + id);
}

@Override public Loader<List<AppEntry>> onCreateLoader(int id, Bundle args) {
    // This is called when a new Loader needs to be created.  This
    // sample only has one Loader with no arguments, so it is simple.
    return new AppListLoader(getActivity());
}

@Override public void onLoadFinished(Loader<List<AppEntry>> loader, List<AppEntry> data) {
    // Set the new data in the adapter.
    mAdapter.setData(data);

    // The list should now be shown.
    if (isResumed()) {
        setListShown(true);
    } else {
        setListShownNoAnimation(true);
    }
}

@Override public void onLoaderReset(Loader<List<AppEntry>> loader) {
    // Clear the data in the adapter.
    mAdapter.setData(null);
} }
Другие вопросы по тегам