Skip to content

Instantly share code, notes, and snippets.

@koush
Created March 24, 2011 03:02
Show Gist options
  • Save koush/884471 to your computer and use it in GitHub Desktop.
Save koush/884471 to your computer and use it in GitHub Desktop.
/*
* UrlImageCache.java
*
* Copyright 2010, BuddyTV. All Rights Reserved
* Created 12/13/2010 Mike Markley
*/
package com.buddytv.android.utilities;
import android.graphics.drawable.Drawable;
public final class UrlImageCache extends WeakReferenceHashTable<String, Drawable> {
private static UrlImageCache mInstance = new UrlImageCache();
public static UrlImageCache getInstance() {
return mInstance;
}
private UrlImageCache() {
}
}
package com.buddytv.android.utilities;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Hashtable;
import com.buddytv.android.Helper;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ImageView;
public final class UrlImageViewHelper {
private static final String LOGTAG = "UrlImageViewHelper";
public static int copyStream(InputStream input, OutputStream output) throws IOException
{
byte[] stuff = new byte[1024];
int read = 0;
int total = 0;
while ((read = input.read(stuff)) != -1)
{
output.write(stuff, 0, read);
total += read;
}
return total;
}
public static void setUrlDrawable(final ImageView imageView, final String url, int defaultResource) {
if (Helper.isNullOrEmpty(url)) {
imageView.setImageDrawable(null);
return;
}
final UrlImageCache cache = UrlImageCache.getInstance();
Drawable d = cache.get(url);
if (d != null) {
//Log.i(LOGTAG, "Cache hit on: " + url);
final Drawable newImage = d;
imageView.post(new Runnable() {
public void run() {
imageView.setImageDrawable(newImage);
}
});
return;
}
final String filename = "" + url.hashCode() + ".png";
if (imageView.getContext().getFileStreamPath(filename).exists()) {
try {
FileInputStream fis = imageView.getContext().openFileInput(filename);
final Bitmap bitmap = BitmapFactory.decodeStream(fis);
BitmapDrawable drawable = new BitmapDrawable(bitmap);
imageView.setImageDrawable(drawable);
cache.put(url, drawable);
Log.i(LOGTAG, "File Cache hit on: " + url);
return;
}
catch (Exception ex) {
}
}
// null it while it is downloading
if (defaultResource == 0)
imageView.setImageDrawable(null);
else
imageView.setImageResource(defaultResource);
// since listviews reuse their views, we need to
// take note of which url this view is waiting for.
// This may change rapidly as the list scrolls or is filtered, etc.
//Log.i(LOGTAG, "Waiting for " + url);
mPendingViews.put(imageView, url);
ArrayList<ImageView> currentDownload = mPendingDownloads.get(url);
if (currentDownload != null) {
// Also, multiple vies may be waiting for this url.
// So, let's maintain a list of these views.
// When the url is downloaded, it sets the imagedrawable for
// every view in the list. It needs to also validate that
// the imageview is still waiting for this url.
currentDownload.add(imageView);
return;
}
final ArrayList<ImageView> downloads = new ArrayList<ImageView>();
downloads.add(imageView);
mPendingDownloads.put(url, downloads);
AsyncTask<Void, Void, Drawable> downloader = new AsyncTask<Void, Void, Drawable>() {
@Override
protected Drawable doInBackground(Void... params) {
try {
//Log.i(LOGTAG, "Downloading image: " + url);
URLConnection conn = new URL(url).openConnection();
int len = conn.getContentLength();
if (len < 0)
len = 0;
final InputStream is = conn.getInputStream();
final Configuration configuration = new Configuration();
configuration.setToDefaults();
Options opts = new Options();
// set the SampleSize to a value larger than 1 to get the image to
// be scaled. This also saves space on decoding in BitmapFactory
opts.inSampleSize = 2;
FileOutputStream fos = imageView.getContext().openFileOutput(filename, Context.MODE_PRIVATE);
copyStream(is, fos);
FileInputStream fis = imageView.getContext().openFileInput(filename);
final Bitmap bitmap = BitmapFactory.decodeStream(fis);
//Log.i(LOGTAG, String.format("Downloaded bitmap (%dx%d): %s", bitmap.getWidth(), bitmap.getHeight(), url));
return new BitmapDrawable(bitmap);
//final Resources resources = new Resources(manager, metrics, configuration);
//BitmapDrawable b = new BitmapDrawable(resources, bitmap);
// Drawable d = Drawable.createFromStream(is, "src name");
//return (Drawable) b;
}
catch (Exception ex) {
Log.e(LOGTAG, "Exception during Image download of " + url, ex);
return null;
}
}
protected void onPostExecute(Drawable result) {
mPendingDownloads.remove(url);
cache.put(url, result);
for (ImageView iv: downloads) {
// validate the url it is waiting for
String pendingUrl = mPendingViews.get(iv);
if (!url.equals(pendingUrl)) {
//Log.i(LOGTAG, "Ignoring out of date request ot update view for " + url);
continue;
}
mPendingViews.remove(iv);
if (result != null) {
final Drawable newImage = result;
final ImageView imageView = iv;
imageView.post(new Runnable() {
public void run() {
imageView.setImageDrawable(newImage);
}
});
}
}
}
};
downloader.execute();
}
private static Hashtable<ImageView, String> mPendingViews = new Hashtable<ImageView, String>();
private static Hashtable<String, ArrayList<ImageView>> mPendingDownloads = new Hashtable<String, ArrayList<ImageView>>();
}
package com.buddytv.android.utilities;
import java.lang.ref.WeakReference;
import java.util.Hashtable;
public class WeakReferenceHashTable<K,V> {
Hashtable<K, WeakReference<V>> mTable = new Hashtable<K, WeakReference<V>>();
public V put(K key, V value) {
WeakReference<V> old = mTable.put(key, new WeakReference<V>(value));
if (old == null)
return null;
return old.get();
}
public V get(K key) {
WeakReference<V> val = mTable.get(key);
if (val == null)
return null;
V ret = val.get();
if (ret == null)
mTable.remove(key);
return ret;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment