package com.andrewshu.android.reddit.threads; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.ref.SoftReference; import java.net.MalformedURLException; import java.util.HashMap; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import android.app.ListActivity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.util.Log; import android.view.View; import android.widget.ImageView; import com.andrewshu.android.reddit.R; import com.andrewshu.android.reddit.common.util.StringUtils; import com.andrewshu.android.reddit.things.ThingInfo; import com.andrewshu.android.reddit.threads.ShowThumbnailsTask.ThumbnailLoadAction; public class ShowThumbnailsTask extends AsyncTask<ThumbnailLoadAction, ThumbnailLoadAction, Void> { private ListActivity mActivity; private HttpClient mClient; private Integer mDefaultThumbnailResource; private static HashMap<String, SoftReference<Bitmap>> cache = new HashMap<String, SoftReference<Bitmap>>(); private static final String TAG = "ShowThumbnailsTask"; public ShowThumbnailsTask(ListActivity activity, HttpClient client, Integer defaultThumbnailResource) { this.mActivity = activity; this.mClient = client; this.mDefaultThumbnailResource = defaultThumbnailResource; } public static class ThumbnailLoadAction { public ThingInfo thingInfo; public ImageView imageView; // prefer imageView; if it's null, use threadIndex public int threadIndex; public ThumbnailLoadAction(ThingInfo thingInfo, ImageView imageView, int threadIndex) { this.thingInfo = thingInfo; this.imageView = imageView; this.threadIndex = threadIndex; } } @Override protected Void doInBackground(ThumbnailLoadAction... thumbnailLoadActions) { for (ThumbnailLoadAction thumbnailLoadAction : thumbnailLoadActions) { loadThumbnail(thumbnailLoadAction.thingInfo); publishProgress(thumbnailLoadAction); } return null; } // TODO use external storage cache if present private void loadThumbnail(ThingInfo thingInfo) { if ("default".equals(thingInfo.getThumbnail()) || "self".equals(thingInfo.getThumbnail()) || StringUtils.isEmpty(thingInfo.getThumbnail())) { thingInfo.setThumbnailResource(mDefaultThumbnailResource); } else { SoftReference<Bitmap> ref; Bitmap bitmap; ref = cache.get(thingInfo.getThumbnail()); if (ref != null) { bitmap = ref.get(); if (bitmap != null) { thingInfo.setThumbnailBitmap(bitmap); return; } } bitmap = readBitmapFromNetwork(thingInfo.getThumbnail()); ref = new SoftReference<Bitmap>(bitmap); cache.put(thingInfo.getThumbnail(), ref); thingInfo.setThumbnailBitmap(ref.get()); } } private InputStream fetch(String urlString) throws MalformedURLException, IOException { HttpGet request = new HttpGet(urlString); HttpResponse response = mClient.execute(request); return response.getEntity().getContent(); } private Bitmap readBitmapFromNetwork( String url ) { if (url == null) return null; InputStream is = null; BufferedInputStream bis = null; Bitmap bmp = null; try { // http://blog.donnfelker.com/2010/04/29/android-odd-error-in-defaulthttpclient/ if (!url.startsWith("http://") && !url.startsWith("https://")) url = "http://" + url; is = fetch(url); bis = new BufferedInputStream(is); bmp = BitmapFactory.decodeStream(bis); } catch (MalformedURLException e) { Log.e(TAG, "Bad ad URL", e); } catch (IOException e) { Log.e(TAG, "Could not get remote ad image", e); } finally { try { if( is != null ) is.close(); if( bis != null ) bis.close(); } catch (IOException e) { Log.w(TAG, "Error closing stream."); } } return bmp; } @Override protected void onProgressUpdate(ThumbnailLoadAction... thumbnailLoadActions) { for (ThumbnailLoadAction thumbnailLoadAction : thumbnailLoadActions) refreshThumbnailUI(thumbnailLoadAction); } private void refreshThumbnailUI(ThumbnailLoadAction thumbnailLoadAction) { ImageView imageView = null; if (thumbnailLoadAction.imageView != null) { imageView = thumbnailLoadAction.imageView; } else { if (isCurrentlyOnScreenUI(thumbnailLoadAction.threadIndex)) { int positionOnScreen = thumbnailLoadAction.threadIndex - mActivity.getListView().getFirstVisiblePosition(); View v = mActivity.getListView().getChildAt(positionOnScreen); if (v != null) { View thumbnailImageView = v.findViewById(R.id.thumbnail); if (thumbnailImageView != null) { imageView = (ImageView) thumbnailImageView; } } } } if (imageView != null) { ThingInfo thingInfo = thumbnailLoadAction.thingInfo; if (thingInfo.getThumbnailBitmap() != null) imageView.setImageBitmap(thingInfo.getThumbnailBitmap()); else if (thingInfo.getThumbnailResource() != null) imageView.setImageResource(thingInfo.getThumbnailResource()); } } private boolean isCurrentlyOnScreenUI(int position) { return position >= mActivity.getListView().getFirstVisiblePosition() && position <= mActivity.getListView().getLastVisiblePosition(); } }