Integrating graphical elements into a ListActivity requires precise handling of layout construction and data binding. While modern development often favors XML-based layouts, programmatic generation offers flexibility when strict resource constraints exist. Below is an approach to building list rows entirely within Java code, embedding checkboxes, application names, status flags, and icons.
Defining the Custom Row Component
To create a distinct look for each list entry, we define a class etxending LinearLayout. Instead of loading an XML resource, individual widgets are instantiated and appended using addView. This allows dynamic control over orientation and dimensions at runtime.
public class AppListItem extends LinearLayout {
private CheckBox checkBox;
private ImageView appIcon;
private TextView appNameText;
private TextView sysFlagText;
public AppListItem(Context context) {
super(context);
setOrientation(HORIZONTAL);
// Setup Checkbox column
checkBox = new CheckBox(context);
addView(checkBox, generateLayoutParams(0.2f, 60));
// Setup Icon column
appIcon = new ImageView(context);
addView(appIcon, generateLayoutParams(0.2f, 60));
// Setup Name column
appNameText = new TextView(context);
addView(appNameText, generateLayoutParams(0.4f, 60));
// Setup Flag column
sysFlagText = new TextView(context);
addView(sysFlagText, generateLayoutParams(0.2f, 60));
}
private static LayoutParams generateLayoutParams(float weight, int height) {
return new LayoutParams((int)(weight * getScreenWidth()), height);
}
private static int getScreenWidth() {
WindowManager wm = (WindowManager) ((Activity)getContext()).getWindowManager();
return wm.getDefaultDisplay().getWidth();
}
public void setIcon(Drawable drawable) {
appIcon.setImageDrawable(drawable);
}
public void setTextFields(String name, String flag) {
appNameText.setText(name);
sysFlagText.setText(flag);
}
}
Constructing the Data Adapter
The adapter bridges the gap between the dataset and the ListActivity. By extending BaseAdapter, we gain full control over how cells are recycled and populated. We maintain a dedicatde data model rather than storing raw view instances to ensure stability.
public class InstalledAppsAdapter extends BaseAdapter {
private final Context context;
private final List<apkinfo> dataPool;
public InstalledAppsAdapter(Context context) {
this.context = context;
this.dataPool = new ArrayList<>();
}
@Override
public int getCount() {
return dataPool.size();
}
@Override
public Object getItem(int position) {
return dataPool.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
AppListItem view;
if (convertView == null) {
view = new AppListItem(context);
} else {
view = (AppListItem) convertView;
}
ApkInfo info = dataPool.get(position);
view.setIcon(info.icon);
view.setTextFields(info.label, info.isSystem ? "Yes" : "No");
return view;
}
public void addItem(ApkInfo item) {
dataPool.add(item);
notifyDataSetChanged();
}
}
// Supporting Data Model
class ApkInfo {
Drawable icon;
String label;
boolean isSystem;
public ApkInfo(Drawable icon, String label, boolean isSystem) {
this.icon = icon;
this.label = label;
this.isSystem = isSystem;
}
}</apkinfo>
Implementing the Activity Logic
The activity itself manages the lifecycle of the data retrieval process. Rather than using setContentView for a static layout, we utilize setListAdapter. Inside onCreate, we query the system for installed packages, filter their properties, and feed them into the adapter.
public class PackageManagerList extends ListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PackageManager pm = getPackageManager();
List<packageinfo> installedPkgs = pm.getInstalledPackages(PackageManager.GET_META_DATA);
InstalledAppsAdapter adapter = new InstalledAppsAdapter(this);
for (PackageInfo pkg : installedPkgs) {
ApplicationInfo appInfo = pkg.applicationInfo;
String pkgLabel = (String) appInfo.loadLabel(pm);
// Determine System Status
boolean isSystemApp = (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
// Retrieve or Default Icon
Drawable appIcon = null;
try {
appIcon = appInfo.loadIcon(pm);
if (appIcon == null) {
appIcon = getResources().getDrawable(R.drawable.ic_launcher);
}
} catch (Exception e) {
appIcon = getResources().getDrawable(R.drawable.ic_launcher);
}
adapter.addItem(new ApkInfo(appIcon, pkgLabel, isSystemApp));
}
setListAdapter(adapter);
}
}</packageinfo>