Category Archives: Android

[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

[Java/Android] 현재 실행중인 어플리케이션을 백그라운드로 전환하기

현재 실행중인 어플리케이션을 백그라운드로 전화하기 위해서(다른 말로는 즉시 홈스크린을 띄우기 위해서)는 두가지 방법을 사용할 수 있습니다. moveTaskToBack라는 메서드를 사용하거나 Intent를 이용하여 홈을 띄우는 방법이 있습니다.

1. 메서드 활용하기

Activity에서 호출이 가능한 moveTaskToBack(boolean nonRoot)라는 메서드는 인자로 boolean형을 받고 결과값을 boolean형으로 반환합니다. 이 메서드는 현재의 엑티비티가 속해있는 테스크를 백그라운드로 즉시 이동시킵니다. 정상적으로 이동이 되었다면 true가 반환이 되며 이동에 실패할 경우 false가 반환됩니다.

하나의 인자를 받는데 true를 입력할 경우 어떠한 경우라도 상관없이 백그라운드로 이동을 시킵니다. false일 경우 현재의 엑티비티가 루트(root)일 경우에만 백그라운드로 이동시킵니다. 루트라는 말은 태스크의 가장 첫번째(바닥)의 엑티비티임을 뜻합니다.

2. Intent 활용하기

1에서 소개해드린 방법으로도 백그라운드로 전환되지 않는 특정한 상황이 있다고 합니다. 그 경우 다음의 인텐트를 활용하는 방법을 사용하면 100% 전환이 이루어집니다. 1의 방법은 엑티비티를 백그라운드로 넘기는 방법이고 이방법은 홈스크린을 현재의 화면으로 끌고 오는 방법입니다. 간단하게 다음의 코드를 사용하시면 됩니다.

Intent intent = new Intent();
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);

다음은 위의 두가지 방법을 테스트 해볼수 있는 예제 소스를 올려드립니다. [다운로드]

사용자 삽입 이미지