I am displaying all apps installed in a gridView. When loading a lot of apps, lets say 30 or more, the icons will display at the default Android icon and then several seconds later update to the correct icon. I am wondering about improvements I can make to my code to make the icon images display faster.
Load the following with: new LoadIconsTask().execute(mApps.toArray(new AppsInstalled[]{}));
Here is what I do.
private class LoadIconsTask extends AsyncTask<AppsInstalled, Void, Void>{
@Override
protected Void doInBackground(AppsInstalled... params) {
// TODO Auto-generated method stub
Map<String, Drawable> icons = new HashMap<String, Drawable>();
PackageManager manager = getApplicationContext().getPackageManager();
// match package name with icon, set Adapter with loaded Map
for (AppsInstalled app : params) {
String pkgName = app.getAppUniqueId();
Drawable ico = null;
try {
Intent i = manager.getLaunchIntentForPackage(pkgName);
if (i != null) {
ico = manager.getActivityIcon(i);
}
} catch (NameNotFoundException e) {
Log.e(TAG, "Unable to find icon match based on package: " + pkgName
+ " : " + e.getMessage());
}
icons.put(app.getAppUniqueId(), ico);
}
mAdapter.setIcons(icons);
return null;
}
Also populate my listing of apps before I loadIconsTask() with
private List<App> loadInstalledApps(boolean includeSysApps) {
List<App> apps = new ArrayList<App>();
// the package manager contains the information about all installed apps
PackageManager packageManager = getPackageManager();
List<PackageInfo> packs = packageManager.getInstalledPackages(0); // PackageManager.GET_META_DATA
for (int i = 0; i < packs.size(); i++) {
PackageInfo p = packs.get(i);
ApplicationInfo a = p.applicationInfo;
// skip system apps if they shall not be included
if ((!includeSysApps)
&& ((a.flags & ApplicationInfo.FLAG_SYSTEM) == 1)) {
continue;
}
App app = new App();
app.setTitle(p.applicationInfo.loadLabel(packageManager).toString());
app.setPackageName(p.packageName);
app.setVersionName(p.versionName);
app.setVersionCode(p.versionCode);
CharSequence description = p.applicationInfo
.loadDescription(packageManager);
app.setDescription(description != null ? description.toString()
: "");
apps.add(app);
}
return apps;
}
In regards to my Adapter class it is standard. My getView() looks like the following:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
AppViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.row, null);
// creates a ViewHolder and stores a reference to the children view
// we want to bind data to
holder = new AppViewHolder();
holder.mTitle = (TextView) convertView.findViewById(R.id.apptitle);
holder.mIcon = (ImageView) convertView.findViewById(R.id.appicon);
convertView.setTag(holder);
} else {
// reuse/overwrite the view passed assuming that it is castable!
holder = (AppViewHolder) convertView.getTag();
}
App app = mApps.get(position);
holder.setTitle(app.getTitle());
if (mIcons == null || mIcons.get(app.getPackageName()) == null) {
holder.setIcon(mStdImg);
} else {
holder.setIcon(mIcons.get(app.getPackageName()));
}
return convertView;
}
Is there a better way? Can I somehow store the images of the icons in a data structure and when I return back to this Activity I can skip the loadIconsTask? Is that possible? Thank you in advance.