Databinding a ListView with Mono for Android: Listing 5

The GetView method.

public class CustomListAdapter : BaseAdapter
{
Activity context;
Dictionary<String,Bitmap> urlToImageMap = new Dictionary<String,Bitmap>();

public List<Tweet> items;

public CustomListAdapter(Activity context, List<Tweet> listItems) //We need a context to inflate our row view from
    : base()
{
    this.context = context;
    this.items = listItems;
}

public override int Count
{
    get { return items.Count; }
}

public override Java.Lang.Object GetItem(int position)
{
    return position;
}

public override long GetItemId(int position)
{
    return position;
}

public override View GetView(int position, View convertView, ViewGroup parent)
{
    //Get our object for this position
    var item = items[position];

    //Try to reuse convertView if it's not  null, otherwise inflate it from our item layout
    // This gives us some performance gains by not always inflating a new view
    // This will sound familiar to MonoTouch developers with UITableViewCell.DequeueReusableCell()
    var view = (convertView ??
        context.LayoutInflater.Inflate(
            Resource.Layout.tweet,
            parent,
            false)) as LinearLayout;

    //imageItem.Click += new EventHandler(imageItem_Click);
    try
    {
        //Find references to each subview in the list item's view
        var imageItem = view.FindViewById(Resource.Id.imageItem) as ImageView;
        var textTop = view.FindViewById(Resource.Id.textTop) as TextView;
        var textBottom = view.FindViewById(Resource.Id.textBottom) as TextView;
        //Assign this item's values to the various subviews
        if (!String.IsNullOrEmpty(item.ProfileImage))
        {
            string documents = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
            string fileName = System.Guid.NewGuid().ToString();
            string file = System.IO.Path.Combine(documents, fileName);
            var ptt = new PassToThread() { FileName = file, imageV = imageItem, UrlToDownload = item.ProfileImage };
            System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(downloadImage), ptt);
       }
        Android.Util.Log.Info("custom adapter", item.ProfileImage);
		textTop.Text = item.Status;
		textBottom.Text = item.StatusDate;
    }
    catch (System.Exception sysExc)
    {
        Android.Util.Log.Error("custom adapter", sysExc.Message);
    }
    //Finally return the view
    return view;
}

private void downloadImage(Object o)
{
    try
    {
		var ptt = (PassToThread)o;
        Bitmap bitmap;
		lock (this) {
		if (urlToImageMap.ContainsKey(ptt.UrlToDownload)) 
		{
			bitmap = urlToImageMap[ptt.UrlToDownload];
		}
		else 
		{
			var imageUrl = new Java.Net.URL(ptt.UrlToDownload);
			bitmap   = Android.Graphics.BitmapFactory.DecodeStream (imageUrl.OpenStream ());
			urlToImageMap.Add(ptt.UrlToDownload,bitmap);
			File.Delete(ptt.FileName);
		}
		}
		context.RunOnUiThread(() => ptt.imageV.SetImageBitmap(bitmap));
    }
    catch (System.Net.WebException wec)
    {
        Android.Util.Log.Error("twitter timelines", wec.Message);
    }
}
public Tweet GetItemAtPosition(int position)
{
    return items[position];
}
private class PassToThread
{
    public string UrlToDownload { get; set; }
    public string FileName { get; set; }
    public ImageView imageV { get; set; }
}
}

About the Author

Wallace (Wally) B. McClure has authored books on iPhone programming with Mono/Monotouch, Android programming with Mono for Android, application architecture, ADO.NET, SQL Server and AJAX. He's a Microsoft MVP, an ASPInsider and a partner at Scalable Development Inc. He maintains a blog, and can be followed on Twitter.