Spring を使い始める前に、自分で Web イメージ ローダーを実装していました。画像や認証 (後者は追加可能) に Spring が必要ないと仮定すると、私が使用する次のクラスに似たものが機能するはずです。SimpleBitmapCache
クラスは LruCache (サポート パッケージで利用可能) の単なるラッパーであり、キャッチして処理するためgetBitmapSafely
のラッパーであることに注意してください(特定のポイントまで再帰的に増加し、最終的にはあきらめます)。BitmapFactory.decodeStream()
OutOfMemoryError
inSampleSize
import android.graphics.Bitmap;
import android.graphics.drawable.AnimationDrawable;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.ImageView;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.net.HttpURLConnection;
import java.net.URL;
@Singleton
public class WebImageLoader {
private static final String TAG = WebImageLoader.class.getSimpleName();
protected SimpleBitmapCache simpleBitmapCache;
protected Pattern cachedImagePattern;
@Inject
public WebImageLoader(SimpleBitmapCache simpleBitmapCache) {
this.simpleBitmapCache = simpleBitmapCache;
}
public void fetchImageForImageView(ImageView imageView, URL url,
int maxWidth, int maxHeight, ImageView.ScaleType scaleType) {
// Sanity check: Does the request make sense?
if (imageView == null)
Log.w(TAG, "imageView doesn't exist!", new Exception());
if (url == null)
Log.w(TAG, "No URL to load!", new Exception());
if (imageView == null || url == null)
return;
// Set a tag so the downloader will set the image automatically, and so that only the correct picture is shown.
imageView.setTag(url);
// We only need to start the Downloader if the Bitmap isn't cached
if (!isBitmapCached(url)) {
new Downloader(imageView, url, scaleType).execute();
} else {
imageView.setScaleType(scaleType);
imageView.setImageBitmap(getBitmapFromCache(url));
}
}
public void clearCache() {
simpleBitmapCache.clear();
}
private boolean isBitmapCached(URL url) {
return (simpleBitmapCache != null) && (simpleBitmapCache.contains(url));
}
private Bitmap getBitmapFromCache(URL url) {
return (Bitmap) simpleBitmapCache.get(url);
}
private void setBitmapIntoCache(Bitmap bitmap, URL url) {
if (simpleBitmapCache != null) {
simpleBitmapCache.put(url, bitmap);
}
}
private class Downloader extends AsyncTask<Void, Void, Bitmap> {
protected final static int DEFAULT_ATTEMPTS = 3;
protected final static long SLEEP_TIME = 3000;
private final static String TAG = Downloader.class.getSimpleName();
protected WeakReference<ImageView> imageViewRef;
protected ImageView.ScaleType finalScaleType;
protected URL url;
public Downloader(final ImageView imageView, URL url, ImageView.ScaleType scaleType) {
this.imageViewRef = new WeakReference<ImageView>(imageView);
this.url = url;
if (scaleType == null)
this.finalScaleType = ImageView.ScaleType.FIT_CENTER;
else
this.finalScaleType = scaleType;
// Set a download animation
imageView.setScaleType(ImageView.ScaleType.CENTER);
imageView.setImageResource(android.R.drawable.stat_sys_download);
AnimationDrawable animation = (AnimationDrawable)imageView.getDrawable();
imageView.post(animation);
}
@Override
protected Bitmap doInBackground(Void... params) {
return downloadBitmap(url);
}
@Override
protected void onPostExecute(Bitmap bitmap) {
// Update the cache
setBitmapIntoCache(bitmap, url);
ImageView imageView = imageViewRef.get();
if (imageView != null) {
// Let's verify if that ImageView wasn't recycled
if (imageView.getTag() != null && imageView.getTag().equals(url)) {
imageView.setScaleType(finalScaleType);
imageView.setImageBitmap(bitmap);
imageView.setTag(null); // because it WILL be recycled later
}
}
}
protected Bitmap downloadBitmap(URL url) {
return downloadBitmap(url, DEFAULT_ATTEMPTS);
}
protected Bitmap downloadBitmap(URL url, int attemptsLeft) {
Bitmap bitmap = null;
InputStream is = null;
HttpURLConnection connection = null;
int responseCode = -1;
attemptsLeft--;
//Log.v(TAG, "Downloading "+url);
try {
connection = (HttpURLConnection) url.openConnection();
} catch (IOException e) {
Log.e(TAG, "Failed to open HttpConnection for "+url.getPath(), e);
}
if (connection != null) {
try {
responseCode = connection.getResponseCode();
} catch (IOException e) {
Log.e(TAG, "Failed to get response code for "+connection.getURL(), e);
}
if (200 == responseCode) {
try {
is = connection.getInputStream();
} catch (IOException e) {
Log.e(TAG, "Failed to open InputStream for "+connection.getURL(), e);
}
// Finally create the bitmap from the InputStream
if (is != null) {
try {
bitmap = ImageUtil.getBitmapSafely(is, 1);
} catch (ImageUtil.BitmapTooLargeException e) {
Log.e(TAG, "Giving up on decoding "+connection.getURL());
}
}
} else if (responseCode != -1) {
if (responseCode == 404)
Log.d(TAG, "Image not found: "+url.toString());
else
Log.e(TAG, "Unexpected response code "+responseCode+" for "+connection.getURL());
}
}
if (bitmap == null && responseCode == -1 && attemptsLeft > 0) {
try {
Thread.sleep(SLEEP_TIME);
} catch (InterruptedException e) {
Log.w(TAG, "Download interrupted: "+url.getPath(), e);
return bitmap;
}
Log.d(TAG, "Retrying download of "+url.getPath());
return downloadBitmap(url, attemptsLeft);
}
return bitmap;
}
}
}