[Java/Android] DIP to Pixel, Pixel to DIP 변환 유틸리티

안드로이드에서는 기본적으로 화면 해상도에 의존적이지 않는 화면 구성을 하여야만 합니다. 하지만 동적으로 UI를 구축한다거나 또는 복잡한 레이아웃에서는 그것이 쉽지가 않죠. 그경우엔 픽셀 단위의 글을 자유자재로 DIP으로 혹은 그 반대로 변환할 수 있어야 합니다. 다음은 간단히 사용할 수 있는 예제입니다.

[code]public class DisplayUtil
{
  private static final float DEFAULT_HDIP_DENSITY_SCALE = 1.5f;
  /**
   * 픽셀단위를 현재 디스플레이 화면에 비례한 크기로 반환합니다.
   *
   * @param pixel 픽셀
   * @return 변환된 값 (DP)
   */
  public static int DPFromPixel(int pixel)
  {
    Context context = BaseApplication.getContext();
    float scale = context.getResources().getDisplayMetrics().density;
    
    return (int)(pixel / DEFAULT_HDIP_DENSITY_SCALE * scale);
  }
 
  /**
   * 현재 디스플레이 화면에 비례한 DP단위를 픽셀 크기로 반환합니다.
   *
   * @param  DP 픽셀
   * @return 변환된 값 (pixel)
   */
  public static int PixelFromDP(int DP)
  {
    Context context = BaseApplication.getContext();
    float scale = context.getResources().getDisplayMetrics().density;
    
    return (int)(DP / scale * DEFAULT_HDIP_DENSITY_SCALE);
  }
}[/code]

[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