public synchronized ExpenseThumbnail getThumbnail(
      int id,
      ExpenseThumbnail.OnExpenseThumbnailLoadedListener onLoadedListener,
      Object onLoadedContext) {
    ExpenseThumbnail thumb = mThumbs.get(new Integer(id));
    if (thumb != null) {
      if (onLoadedListener != null)
        thumb.registerOnLoadedListener(onLoadedListener, onLoadedContext);

      return thumb;
    }

    thumb = new ExpenseThumbnail(mContext, id);

    if (onLoadedListener != null) {
      thumb.registerOnLoadedListener(onLoadedListener, onLoadedContext);
      Log.d(
          "ThumbCache",
          "thumb id "
              + Integer.toString(thumb.id)
              + " has new load listener "
              + onLoadedListener.toString()
              + " with context "
              + (onLoadedContext == null ? "<null>" : onLoadedContext.toString()));
    }

    LoadThumbnailTask task = new LoadThumbnailTask();
    task.execute(thumb);
    Log.d("ThumbCache", "added thumb id " + Integer.toString(thumb.id) + " to load list");

    // cache the thumbnail
    mThumbs.put(new Integer(id), thumb);
    Log.d("ThumbCache", "cached thumb id " + Integer.toString(thumb.id));

    return thumb;
  }
 /* (non-Javadoc)
  * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
  */
 @Override
 protected void onPostExecute(ExpenseThumbnail thumb) {
   // this will be executed on the UI thread
   thumb.notifyOnLoadedListeners();
 }