About a month ago, Mono for Android 1.0 was released. I quickly downloaded "trial" version (which is very generous) and started hacking away on my first project. After working off and on for the last month I think I have enough smarts built up to share some things. I will start by share my Lazy Expandable List Adapter class for use with, as its name implies, Android Expandable Lists. The full source code is attached, but I'm going to go over a few of the methods and cool features that a lazy loading parent to child tree viewer can provide. This posting will assume some basic Android develop skills, i.e. inflating an xml layout and layout integer ids from the Resources.cs/r.java file. The class is defined as follows:
public class LazyExpandableListViewAdapter<TGroup, TItem>
: BaseExpandableListAdapter where TGroup : class where TItem : class
From my limited MonoDroid experience I have learned a few things: Android objects live in two places, the CLR and in the Dalvik VM, Android Objects must inherent from java.lang.object, NOT System.Object, and (pure) .NET types DO NOT inherent from java.lang.object. This can cause some issues with the MonoDroid toolkit because many of the default classes, like for the Expandable Lists, use java.lang.object internally. This can eliminate pure .NET types from being used. This class does two things that the default adapters will not easily allow you to do. 1) type safety (TGroup and TItem) and 2) no limitations on what TGroup and TItem are, they do not have to exist the the java world as well. To accomplish this I had to do two things: 1) custom generic indexers and 2) custom implementations of GetGroup and GetChild.
public override Java.Lang.Object GetChild (int groupPosition, int childPosition)
{
if (_groups[groupPosition] != default(TGroup) && map.ContainsKey(_groups[groupPosition]))
{
return AVAILABLE_OBJECT;
}
return UNAVAILABLE_OBJECT;
}
To overcome the java object issue I have defined two static readonly java objects, AVAILABLE_OBJECT and UNAVAILABLE_OBJECT. The are returned if the request item the loaded and not loaded respectively. With this we can draw a loading view or hydate an inflated view for this item in question based on its availability. This by itself does not type safety or the ability to read and populate you data. For that I have created two indexers:
public IEnumerable<TItem> this[TGroup g]
{
get
{
if (map.ContainsKey(g))
{
return map[g];
}
return System.Linq.Enumerable.Empty<TItem>();
}
set
{
if (!_groups.Contains(g))
{
_groups.Add(g);
}
if (map.ContainsKey(g))
{
map.Remove(g);
}
map.Add(g, new List<TItem>(value));
NotifyDataSetChanged();
}
}
public TGroup this[int position]
{
get { return _groups[position]; }
}
public void LoadGroups(IEnumerable<TGroup> groups)
{
_groups = new List<TGroup>(groups);
map.Clear();
NotifyDataSetChanged();
}
This provides you a type safe way to populate and access you data objects and takes care of change notifications to Android when you do so. The source for this class is attached, anyone reading enjoy.
LazyExpandableListViewAdapter.cs (4.02 kb)