[Java/Android] 원격지 이미지 다운로드 (Remote Image Downloader)

안드로이드에서 원격지에 이미지를 읽어오는 방식은 다양한 방식이 있습니다. 하지만 안드로이드 자체의 문제인지 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