Skip to content

Instantly share code, notes, and snippets.

@sayan1886
Created February 4, 2013 18:26
Show Gist options
  • Save sayan1886/4708531 to your computer and use it in GitHub Desktop.
Save sayan1886/4708531 to your computer and use it in GitHub Desktop.
// LICENSE: USE IT IF YOU NEED IT, BUT PLEASE MENTION AT LEAST MY NAME, THANKS!
// (Juraj Suchán, [email protected])
//
// PREFACE:
// So i've been building client application for one local "closed community"
// nyx.cz for year and a half where the displayed content is standard html code.
//
// There is Html.fromHtml to the rescue for that! But unfortunatelly, anyone who tried it
// have to deal with custom Html.ImageGetter implementation.
// This interface contains only one method, with only one paramter (url) and it's completelly
// "impossibru" to make it asynchronous anyhow.
// Not to mention, if you want to use it in application targeted to HC/ICS and higher,
// the NetworkOnMainThreadException will be thrown!
//
// Here is my workaround (please note that this is snippet rather than full solution):
// The first Html.ImageGetter implementation in the getDrawable method
// fires of AsyncTask to get the image from specified source and stores it in cache.
// Return value for this method is just drawable placeholder (empty image or so).
// The second Html.ImageGetter implementation takes the loaded drawable from cache..
// I have this code inside custom list adapter and it may looks like this:
// TL;DR we need two imageGetter implementations, one for imageDownloading (igcacher) and one for image drawing from cache (igfromcache)
// - when the task from first imageGetter (igcacher) finishes, it sets the resulting drawable to the cache
// - apply the second imageGetter (igfromcache) in task onPostExecute, and you're done.
// - the textView will redraw correctly because of new calling "setText".
//...
static final Map<String, WeakReference<Drawable>> mDrawableCache = Collections.synchronizedMap(new WeakHashMap<String, WeakReference<Drawable>>());
//...
private Drawable mDefaultDrawable;
private Executor mExecutor = Executors.newSingleThreadExecutor();
//...
Html.ImageGetter igfromcache = new Html.ImageGetter() { // this is the second imageGetter implementation we need
public Drawable getDrawable(String source) {
if (!mDrawableCache.containsKey(source)) {
return null;
}
return mDrawableCache.get(source).get(); // the image has been already downloaded and it's stored in cache, right?
}
}
//...
final String message = "some html content with image tasks";
final TextView textView = (TextView)findViewById(R.id.discussion_message_tv);
Html.ImageGetter igcacher = new Html.ImageGetter() { // this is first imageGetter implementation we need
public Drawable getDrawable(String source) {
ImageDownloadData imageDownloadData = new ImageDownloadData(source, message, textView);
ImageDownloadAsyncTask imageDownloadTask = new ImageDownloadAsyncTask(imageDownloadData);
imageDownloadTask.executeOnExecutor(mExecutor, null); // go for it online!
return mDefaultDrawable; // this is placeholder image taken from resources.
}
};
textView.setText(Html.fromHtml(message, igcacher, null)); // the trick starts here, spinoff caching image getter.
//...
class ImageDownloadData {
private String imageSource;
private String message;
private TextView textView;
public ImageDownloadData(String imageSource, String message, TextView textView) {
this.imageSource = imageSource;
this.message = message;
this.textView = textView;
}
public String getImageSource() {
return imageSource;
}
public String getMessage() {
return message;
}
public TextView getTextView() {
return textView;
}
}
//...
class ImageDownloadAsyncTask extends AsyncTask<Void, Void, Drawable> {
private ImageDownloadData imageDownloadData;
public ImageDownloadAsyncTask(ImageDownloadData imageDownloadData) {
this.imageDownloadData = imageDownloadData;
}
@Override
protected Drawable doInBackground(Void... params) {
Drawable drawable = null;
/*
code for downloading bitmap is not required here, do it by yourself,
remember, the uri for it is in imageDownloadData.getImageSource() !
*/
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
return drawable;
}
@Override
protected void onPostExecute(Drawable drawable) {
// put the downloaded drawable into the cache (so the second image getter can access it)
if (!mDrawableCache.containsKey(imageDownloadData.getSource())) {
mDrawableCache.put(imageDownloadData.getSource(), new WeakReference<Drawable>(drawable));
}
TextView textView = imageDownloadData.getTextView();
String message = imageDownloadData.getMessage();
// this does the trick, we need to set the message/text again, but with
// different imageGetter (the second one) imeplementation !
textView.setText(MyHtml.fromHtml(content, igfromcache, null));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment