안드로이드에서 원격지에 이미지를 읽어오는 방식은 다양한 방식이 있습니다. 하지만 안드로이드 자체의 문제인지 3G환경 이하에서 이미지를 제대로 못 읽어오거나 현재의 동작에 영향을 주지 않는 별도의 쓰레드에서 동작하게 하는것은 쉽지 않습니다.
간단하게 사용할 수 있는 비동기 이미지 다운로더를 공개합니다. 구글 안드로이드 블로그에서 봤었던 다운로더에 제가 단순하게 만든 캐싱 기능을 추가하였습니다.
ImageDownloader.java
[code]public class ImageDownloader
{
public static final int IMGAE_CACHE_LIMIT_SIZE = 50;
public static HashMap<String, Bitmap> mImageCache = new HashMap<String, Bitmap>();
public static void download(String url, ImageView imageView)
{
Bitmap cachedImage = mImageCache.get(url);
if(cachedImage != null)
{
imageView.setImageBitmap(cachedImage);
}
else if(cancelPotentialDownload(url, imageView))
{
if(mImageCache.size() > IMGAE_CACHE_LIMIT_SIZE)
{
mImageCache.clear();
}
ImageDownloaderTask task = new ImageDownloaderTask(url, imageView);
DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task);
imageView.setImageDrawable(downloadedDrawable);
task.execute(url);
}
}
private static boolean cancelPotentialDownload(String url, ImageView imageView)
{
ImageDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
if(bitmapDownloaderTask != null)
{
String bitmapUrl = bitmapDownloaderTask.url;
if((bitmapUrl == null) || (!bitmapUrl.equals(url)))
{
bitmapDownloaderTask.cancel(true);
}
else
{
return false;
}
}
return true;
}
private static ImageDownloaderTask getBitmapDownloaderTask(ImageView imageView)
{
if(imageView != null)
{
Drawable drawable = imageView.getDrawable();
if(drawable instanceof DownloadedDrawable)
{
DownloadedDrawable downloadedDrawable = (DownloadedDrawable) drawable;
return downloadedDrawable.getBitmapDownloaderTask();
}
}
return null;
}
static class DownloadedDrawable extends ColorDrawable
{
private final WeakReference<ImageDownloaderTask> bitmapDownloaderTaskReference;
public DownloadedDrawable(ImageDownloaderTask bitmapDownloaderTask)
{
super(Color.TRANSPARENT);
bitmapDownloaderTaskReference = new WeakReference<ImageDownloaderTask>(bitmapDownloaderTask);
}
public ImageDownloaderTask getBitmapDownloaderTask()
{
return bitmapDownloaderTaskReference.get();
}
}[/code]
ImageDownloaderTask.java
[code]public class ImageDownloaderTask extends AsyncTask<String, Void, Bitmap>
{
public String url;
public String targetUrl;
private WeakReference<ImageView> imageViewReference;
public ImageDownloaderTask(String url, ImageView imageView)
{
this.targetUrl = url;
this.imageViewReference = new WeakReference<ImageView>(imageView);
}
@Override
protected Bitmap doInBackground(String… params)
{
return downloadBitmap(params[0]);
}
@Override
protected void onPostExecute(Bitmap bitmap)
{
if(isCancelled())
{
bitmap = null;
}
if(imageViewReference != null)
{
ImageView imageView = imageViewReference.get();
ImageDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
if(this == bitmapDownloaderTask)
{
ImageDownloader.mImageCache.put(targetUrl, bitmap);
imageView.setImageBitmap(bitmap);
}
}
}
private ImageDownloaderTask getBitmapDownloaderTask(ImageView imageView)
{
if(imageView != null)
{
Drawable drawable = imageView.getDrawable();
if(drawable instanceof DownloadedDrawable)
{
DownloadedDrawable downloadedDrawable = (DownloadedDrawable) drawable;
return downloadedDrawable.getBitmapDownloaderTask();
}
}
return null;
}
static Bitmap downloadBitmap(String url)
{
final HttpClient client = new DefaultHttpClient();
final HttpGet getRequest = new HttpGet(url);
try
{
HttpResponse response = client.execute(getRequest);
final int statusCode = response.getStatusLine().getStatusCode();
if(statusCode != HttpStatus.SC_OK)
{
Log.w(“ImageDownloader”, “Error ” + statusCode + ” while retrieving bitmap from ” + url);
return null;
}
final HttpEntity entity = response.getEntity();
if(entity != null)
{
InputStream inputStream = null;
//BitmapFactory.Options options = new BitmapFactory.Options();
//options.inSampleSize = 2;
try
{
inputStream = entity.getContent();
final Bitmap bitmap = BitmapFactory.decodeStream(new FlushedInputStream(inputStream));
//final Bitmap bitmap = BitmapFactory.decodeStream(new FlushedInputStream(inputStream), null, options);
return bitmap;
}
finally
{
if(inputStream != null)
{
inputStream.close();
}
entity.consumeContent();
}
}
}
catch(Exception e)
{
getRequest.abort();
}
return null;
}
static class FlushedInputStream extends FilterInputStream
{
public FlushedInputStream(InputStream inputStream)
{
super(inputStream);
}
@Override
public long skip(long n) throws IOException
{
long totalBytesSkipped = 0L;
while(totalBytesSkipped < n)
{
long bytesSkipped = in.skip(n – totalBytesSkipped);
if(bytesSkipped == 0L)
{
int bytes = read();
if(bytes < 0)
{
break; // we reached EOF
}
else
{
bytesSkipped = 1; // we read one byte
}
}
totalBytesSkipped += bytesSkipped;
}
return totalBytesSkipped;
}
}
}[/code]
1364820185.zip