Monday, 12 August 2013

Efficient android image downloader to over come error java.lang.OutOfMemoryError: bitmap size exceeds VM budget

ImageDownloader :

public class ImageDownloader {

Map<String,Bitmap> imageCache;
private Bitmap defaultIcon;

public ImageDownloader(){
imageCache = new HashMap<String, Bitmap>();

}

//download function
public void download(String url, ImageView imageView,Bitmap defaultImg) {
    if (cancelPotentialDownload(url, imageView)) {
   
    this.defaultIcon=defaultImg;
    //Caching code right here
    String filename = String.valueOf(url.hashCode());
    File f = new File(getCacheDirectory(imageView.getContext()), filename);

     // Is the bitmap in our memory cache?
    Bitmap bitmap = null;
   
     bitmap = (Bitmap)imageCache.get(f.getPath());
   
     if(bitmap == null){
   
     bitmap = BitmapFactory.decodeFile(f.getPath());
   
     if(bitmap != null){
     imageCache.put(f.getPath(), bitmap);
     }
   
     }
     //No? download it
     if(bitmap == null){
     BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
   
     DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task,null,defaultImg);
     imageView.setImageDrawable(downloadedDrawable);
     imageView.setBackgroundDrawable(null);
     task.execute(url);
     }else{
     //Yes? set the image
     imageView.setImageBitmap(bitmap);
     imageView.setBackgroundDrawable(null);
     }
    }
}

//cancel a download (internal only)
private static boolean cancelPotentialDownload(String url, ImageView imageView) {
   BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);

   if (bitmapDownloaderTask != null) {
       String bitmapUrl = bitmapDownloaderTask.url;
       if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
           bitmapDownloaderTask.cancel(true);
       } else {
           // The same URL is already being downloaded.
           return false;
       }
   }
   return true;
}

//gets an existing download if one exists for the imageview
private static BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView) {
   if (imageView != null) {
       Drawable drawable = imageView.getDrawable();
       if (drawable instanceof DownloadedDrawable) {
           DownloadedDrawable downloadedDrawable = (DownloadedDrawable)drawable;
           return downloadedDrawable.getBitmapDownloaderTask();
       }
   }
   return null;
}

//our caching functions
// Find the dir to save cached images
private static File getCacheDirectory(Context context){
String sdState = android.os.Environment.getExternalStorageState();
File cacheDir;
   
if (sdState.equals(android.os.Environment.MEDIA_MOUNTED)) {
File sdDir = android.os.Environment.getExternalStorageDirectory();

//TODO : Change your diretcory here
cacheDir = new File(sdDir,"data/tac/images");
}
else
cacheDir = context.getCacheDir();

if(!cacheDir.exists())
cacheDir.mkdirs();
return cacheDir;
}

private void writeFile(Bitmap bmp, File f) {
 FileOutputStream out = null;

 try {
   out = new FileOutputStream(f);
   bmp.compress(Bitmap.CompressFormat.PNG, 80, out);
 } catch (Exception e) {
   e.printStackTrace();
 }
 finally {
   try { if (out != null ) out.close(); }
   catch(Exception ex) {}
 }
}
///////////////////////

//download asynctask
    public class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {
    private String url;
        private final WeakReference<ImageView> imageViewReference;

        public BitmapDownloaderTask(ImageView imageView) {
            imageViewReference = new WeakReference<ImageView>(imageView);
   
        }

        @Override
        // Actual download method, run in the task thread
        protected Bitmap doInBackground(String... params) {
             // params comes from the execute() call: params[0] is the url.
        url = (String)params[0];
             return downloadBitmap(params[0]);
        }

        @Override
        // Once the image is downloaded, associates it to the imageView
        protected void onPostExecute(Bitmap bitmap) {
            if (isCancelled()) {
                bitmap = null;
            }

            if (imageViewReference != null) {
                ImageView imageView = imageViewReference.get();
                BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
                // Change bitmap only if this process is still associated with it
                if (this == bitmapDownloaderTask) {
                    imageView.setImageBitmap(bitmap);
                   
                    //cache the image
                   
                   
                    String filename = String.valueOf(url.hashCode());
            File f = new File(getCacheDirectory(imageView.getContext()), filename);
           
            imageCache.put(f.getPath(), bitmap);
           
                    writeFile(bitmap, f);
                }
            }
        }
       
       
    }
   
//    static class DownloadedDrawable extends ColorDrawable {
//        private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference;
//
//        public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) {
//          super(Color.TRANSPARENT);
//            bitmapDownloaderTaskReference =
//                new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask);
//        }
//
//        public BitmapDownloaderTask getBitmapDownloaderTask() {
//            return bitmapDownloaderTaskReference.get();
//        }
//    }
   
    private static class DownloadedDrawable extends BitmapDrawable {
        private final WeakReference<BitmapDownloaderTask>
           bitmapDownloaderTaskReference;

        private DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask,
           Resources resources, Bitmap bitmap) {
            super(resources, bitmap); // you'll have to provide these
            bitmapDownloaderTaskReference =
                new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask);
        }

        public BitmapDownloaderTask getBitmapDownloaderTask() {
            return bitmapDownloaderTaskReference.get();
        }
    }
   
    //the actual download code
    static Bitmap downloadBitmap(String url) {
    url=url.replace(" ", "%20");
    HttpParams params = new BasicHttpParams();
    params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
    HttpClient client = new DefaultHttpClient(params);
        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;
                try {
                    inputStream = entity.getContent();
                    final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                    return bitmap;
                } finally {
                    if (inputStream != null) {
                        inputStream.close();
                    }
                    entity.consumeContent();
                }
            }
        } catch (Exception e) {
            // Could provide a more explicit error message for IOException or IllegalStateException
            getRequest.abort();
            Log.w("ImageDownloader", "Error while retrieving bitmap from " + url + e.toString());
        } finally {
            if (client != null) {
                //client.close();
            }
        }
        return null;
    }
}

How to use:


ImageDownloader downloader = new ImageDownloader();

downloader.download(stringUrl,
imageViewProfile, defaultImgBitmap);

No comments:

Post a Comment