Android: Two Line ListView with custom data
After spending two weekends reading up on the SDK and in general playing with my new Google Nexus S, I finally decided to get my feet wet. Downloading the SDK wasn’t really a breeze because the data size is large and with my crappy internet it took forever. When I finally got to writing code, I was plesantly surpised by the ADT plugin, it works flawlessly.
Anyway, I decided I wanted to list all the packages installed on the emulator in a two line list view. You’d think this would be a breeze, it was anything but.
I struggled for a while with NullPointers all over the place before I came across this example in the SDK. Despite stackoverflow, I couldn’t find what I needed on the internet and the example was what eventually helped me.
Anyway, to the example cave! Because we want our default view to be a list view our main class must extend a ListActivity instead of an Activity.
public class HelloAndroid extends ListActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
The code to retrieve all installed applications on the system is pretty straightforward.
final PackageManager pm = getPackageManager();
List<ApplicationInfo> packages = pm
.getInstalledApplications(PackageManager.GET_META_DATA);
List<ApplicationInfo> list = new ArrayList<ApplicationInfo>();
for (ApplicationInfo packageInfo : packages) {
list.add(packageInfo);
}
setListAdapter(new MyAdapter(this, list));
Next, we use the default android layout and create an adapter that extends from the BaseAdapter class. We need a custom adapter because by default the ArrayAdapter displays the toString() of objects present in the array. And we can’t use a SimpleAdapter because we don’t have a cursor. Extending the BaseAdapter allows us to customize the view to our needs and display what we want in whichever element of the view we want.
class MyAdapter extends BaseAdapter {
private LayoutInflater mInflater;
private List<ApplicationInfo> list;
public MyAdapter(Context context, List<ApplicationInfo> list) {
mInflater = LayoutInflater.from(context);
this.list = list;
}
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item, parent, false);
}
TextView title = (TextView) convertView.findViewById(R.id.item_title);
TextView sub = (TextView) convertView.findViewById(R.id.item_subtitle);
ApplicationInfo info = list.get(position);
title.setText(String.valueOf(position));
sub.setText(info.processName);
return convertView;
}
public int getCount() {
return list.size();
}
public Object getItem(int arg0) {
return list.get(arg0);
}
public long getItemId(int arg0) {
return arg0;
}
}
Setting this adapter as the data provider for our list view is simple. The tricky part is making sure you get the id’s of the children view right (this one took me a while to figure out). So our final HelloAndroid class looks something like this.
public class HelloAndroid extends ListActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final PackageManager pm = getPackageManager();
// get a list of installed apps.
List<ApplicationInfo> packages = pm
.getInstalledApplications(PackageManager.GET_META_DATA);
List<ApplicationInfo> list = new ArrayList<ApplicationInfo>();
for (ApplicationInfo packageInfo : packages) {
Log.d("TAG", "Installed package :" + packageInfo.processName);
Log.d("TAG", "Launch Activity :" + packageInfo.className);
list.add(packageInfo);
}
setListAdapter(new MyAdapter(this, list));
}
}
This will display all the installed packages on your device in a neat list view. This code isn’t efficient because we query the packages in the UI threads. The ideal solution would be fire this off as an Intent and then query packages in the intent, displaying them and notifying the view that the data has changed. The use of the default ListActivity however does allow for auto-scrolling loading. This means that only what is visible on the screen is shown at the beginning and as and when you scroll down, more and more elements are rendered. This is very efficient from a UI perspective escpecially when the UI is running on a device which has limited resources (1GB RAM can run out pretty quickly).
I’ll be writing more on how we can fire off an Intent and then loa








