package com.teleca.jamendo.widget; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.concurrent.RejectedExecutionException; import com.teleca.jamendo.MyApplication; import com.teleca.jamendo.util.ImgCache; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.util.AttributeSet; import android.util.Log; import android.widget.ImageView; import android.widget.ListView; /** * ImageView extended class allowing easy downloading * of remote images * * @author Lukasz Wisniewski */ public class MyImageView extends ImageView{ /** * Maximum number of unsuccesful tries of downloading an image */ private static int MAX_FAILURES = 3; public MyImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public MyImageView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public MyImageView(Context context) { super(context); init(); } /** * Sharable code between constructors */ private void init(){ } /** * Remote image location */ private String mUrl; /** * Currently successfully grabbed url */ private String mCurrentlyGrabbedUrl; /** * Remote image download failure counter */ private int mFailure; /** * Position of the image in the mListView */ private int mPosition; /** * ListView containg this image */ private ListView mListView; /** * Default image shown while loading or on url not found */ private Integer mDefaultImage; /** * Loads image from remote location * * @param url eg. http://random.com/abz.jpg */ public void setImageUrl(String url){ if(mListView == null && mCurrentlyGrabbedUrl != null && mCurrentlyGrabbedUrl.equals(url)){ // do nothing image is grabbed & loaded, we are golden return; } if(mUrl != null && mUrl.equals(url)){ mFailure++; if(mFailure > MAX_FAILURES){ Log.e(MyApplication.TAG, "Failed to download "+url+", falling back to default image"); loadDefaultImage(); return; } } else { mUrl = url; mFailure = 0; } ImgCache imageCache = MyApplication.getInstance().getImageCache(); if(imageCache.isCached(url)){ this.setImageBitmap(imageCache.get(url)); } else { try{ new DownloadTask().execute(url); } catch (RejectedExecutionException e) { // do nothing, just don't crash } } } /** * Sets default local image shown when remote one is unavailable * * @param resid */ public void setDefaultImage(Integer resid){ mDefaultImage = resid; } /** * Loads default image */ private void loadDefaultImage(){ if(mDefaultImage != null) setImageResource(mDefaultImage); } /** * Loads image from remote location in the ListView * * @param url eg. http://random.com/abz.jpg * @param position ListView position where the image is nested * @param listView ListView to which this image belongs */ public void setImageUrl(String url, int position, ListView listView){ mPosition = position; mListView = listView; setImageUrl(url); } /** * Asynchronous image download task * * @author Lukasz Wisniewski */ class DownloadTask extends AsyncTask<String, Void, String>{ private String mTaskUrl; @Override public void onPreExecute() { loadDefaultImage(); super.onPreExecute(); } @Override public String doInBackground(String... params) { mTaskUrl = params[0]; InputStream stream = null; URL imageUrl; Bitmap bmp = null; try { imageUrl = new URL(mTaskUrl); try { stream = imageUrl.openStream(); bmp = BitmapFactory.decodeStream(stream); try { if(bmp != null){ MyApplication.getInstance().getImageCache().put(mTaskUrl, bmp); Log.d(MyApplication.TAG, "Image cached "+mTaskUrl); } else { Log.w(MyApplication.TAG, "Failed to cache "+mTaskUrl); } } catch (NullPointerException e) { Log.w(MyApplication.TAG, "Failed to cache "+mTaskUrl); } } catch (IOException e) { Log.w(MyApplication.TAG, "Couldn't load bitmap from url: " + mTaskUrl); } finally { try { if(stream != null){ stream.close(); } } catch (IOException e) {} } } catch (MalformedURLException e) { e.printStackTrace(); } return mTaskUrl; } @Override public void onPostExecute(String url) { super.onPostExecute(url); // target url may change while loading if(!mTaskUrl.equals(mUrl)) return; Bitmap bmp = MyApplication.getInstance().getImageCache().get(url); if(bmp == null){ Log.w(MyApplication.TAG, "Trying again to download " + url); MyImageView.this.setImageUrl(url); } else { // if image belongs to a list update it only if it's visible if(mListView != null) if(mPosition < mListView.getFirstVisiblePosition() || mPosition > mListView.getLastVisiblePosition()) return; MyImageView.this.setImageBitmap(bmp); mCurrentlyGrabbedUrl = url; } } }; }