5 Apr 2013

Load large images from server using image Loader class in android | Image Loader Class | Display image from server | Decode image from server.

There is major problem of "Bitmap out of memory"  while load large images from server. here there is Image loader class for load large image efficiently. i have set tag in loader class for image display like

                                pass int value (1,2,3)
                                1 = thumbImage (ScaleType.FIT_XY)
                                2 = fullImage (ScaleType.FIT_XY)
                                3 = fullImage (ScaleType.FIT_START)








Main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <ImageView
        android:id="@+id/imgPhoto"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"       
        android:contentDescription="@string/app_name"
        android:scaleType="center"
        >
    </ImageView>

</RelativeLayout>

animation_loding.xml: This is the animation while loading images from server. Put couple images in drawable.

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false" >

    <item
        android:drawable="@drawable/new1"
        android:duration="50"/>
    <item
        android:drawable="@drawable/new2"
        android:duration="50"/>
    <item
        android:drawable="@drawable/new3"
        android:duration="50"/>
    <item
        android:drawable="@drawable/new4"
        android:duration="50"/>
    <item
        android:drawable="@drawable/new5"
        android:duration="50"/>
    <item
        android:drawable="@drawable/new6"
        android:duration="50"/>
    <item
        android:drawable="@drawable/new7"
        android:duration="50"/>
    <item
        android:drawable="@drawable/new8"
        android:duration="50"/>
    <item
        android:drawable="@drawable/new9"
        android:duration="50"/>
    <item
        android:drawable="@drawable/new10"
        android:duration="50"/>
    <item
        android:drawable="@drawable/new11"
        android:duration="50"/>
    <item
        android:drawable="@drawable/new12"
        android:duration="50"/>

</animation-list>


Image Loader Class:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Collections;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;

public class ImageLoader
{
       MemoryCache memoryCache = new MemoryCache();
       FileCache fileCache;
       private Map<ImageView, String> imageViews = Collections
       .synchronizedMap(new WeakHashMap<ImageView, String>());
       ExecutorService executorService;
       Context mContext;

       Bitmap bitmap;
       AnimationDrawable frameAnimation;
       private int i_size = 320;
       public ImageLoader(Context context)
       {
              fileCache = new FileCache(context);
              mContext = context;
              executorService = Executors.newFixedThreadPool(5);
       }

       private int mTag = 0;

       /**
        * LoadImage method for load image from web
        *@param url
        *@param imageView
        *@param tag
        *                         pass int value (1,2,3) for<br/>
        *                         1 = thumbImage (ScaleType.FIT_XY),<br/>
        *                         2 = fullImage (ScaleType.FIT_XY),<br/>
        *                         3 = fullImage (ScaleType.FIT_START)
        */
       public synchronized void DisplayImage(String url, ImageView imageView, int tag)
       {

              this.mTag = tag;
              if(mTag == 1 || mTag == 4)
              {
                     i_size =Constant.MAX_ThumbImage_SIZE;
              }
              else
              {
                     i_size =Constant.MAX_Image_SIZE;
              }
              imageViews.put(imageView, url);
              bitmap = memoryCache.get(url);
              if (bitmap != null)
              {                   
                     Log.i("memoryCache", "bitmap");
                     imageView.setImageBitmap(bitmap);
              }
              else
              {
                     Log.i("memoryCache_touch", "bitmap null");
                     queuePhoto(url, imageView);

                     frameAnimation = (AnimationDrawable) mContext.getResources().getDrawable(R.anim.animation_loding);
                     imageView.setScaleType(ScaleType.CENTER);
                     imageView.setImageDrawable(frameAnimation);

                     Timer timer = new Timer();
                     timer.schedule(new TimerTask()
                     {
                           @Override
                           public void run()
                           {
                                  frameAnimation.start();
                           }
                     }, 0);
              }
       }

       private void queuePhoto(String url, ImageView imageView)
       {
              PhotoToLoad p = new PhotoToLoad(url, imageView);
              //executor.execute(new PhotosLoader(p));
              executorService.submit(new PhotosLoader(p));
       }

       public Bitmap getBitmap(String url)
       {
              File f = fileCache.getFile(url);
              // from SD cache
              Bitmap b = decodeFile(f);
              if (b != null)
                     return b;

              // from web
              try {
                     Bitmap bitmap = null;
                     URL imageUrl = new URL(url);
                     HttpURLConnection conn = (HttpURLConnection) imageUrl
                     .openConnection();
                     conn.setConnectTimeout(30000);
                     conn.setReadTimeout(30000);
                     conn.setInstanceFollowRedirects(true);
                     InputStream is = conn.getInputStream();
                     OutputStream os = new FileOutputStream(f);
                     Utils.CopyStream(is, os);
                     os.close();
                     bitmap = decodeFile(f);
                     return bitmap;
              }
              catch (Throwable ex)
              {
                     ex.printStackTrace();
                     if(ex instanceof OutOfMemoryError)
                           memoryCache.clear();
                     return null;
              }

       }

       // decodes image and scales it to reduce memory consumption
       public Bitmap decodeFile(File f)
       {
              try
              {
                     BitmapFactory.Options o = new BitmapFactory.Options();
                     o.inJustDecodeBounds = true;
                     FileInputStream stream1=new FileInputStream(f);
                     BitmapFactory.decodeStream(stream1,null,o);
                     stream1.close();

                     //Find the correct scale value. It should be the power of 2.
                     final int REQUIRED_SIZE=i_size;
                     int width_tmp=o.outWidth, height_tmp=o.outHeight;
                     int scale=1;
                     while(true){
                           if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
                                  break;
                           width_tmp/=2;
                           height_tmp/=2;
                           scale*=2;
                     }

                     //decode with inSampleSize
                     BitmapFactory.Options o2 = new BitmapFactory.Options();
                     o2.inSampleSize=scale;
                     FileInputStream stream2=new FileInputStream(f);
                     Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2);
                     stream2.close();
                     return bitmap;
              }catch (Throwable e) {
                     // TODO: handle exception
                     e.printStackTrace();
                     if(e instanceof OutOfMemoryError)
                           memoryCache.clear();
                     return null;
              }
       }

       // Task for the queue
       private class PhotoToLoad
       {
              public String url;
              public ImageView imageView;

              public PhotoToLoad(String u, ImageView i)
              {
                     url = u;
                     imageView = i;
              }
       }

       class PhotosLoader implements Runnable
       {
              PhotoToLoad photoToLoad;

              PhotosLoader(PhotoToLoad photoToLoad)
              {
                     this.photoToLoad = photoToLoad;
              }

              @Override
              public void run()
              {
                     if (imageViewReused(photoToLoad))
                           return;

                     Bitmap bmp = getBitmap(photoToLoad.url);
                     if(bmp != null)
                     {
                           memoryCache.put(photoToLoad.url, bmp);
                           if (imageViewReused(photoToLoad))
                                  return;
                           BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);
                           Activity a = (Activity) photoToLoad.imageView.getContext();
                           a.runOnUiThread(bd);
                     }
              }
       }

       boolean imageViewReused(PhotoToLoad photoToLoad)
       {
              String tag = imageViews.get(photoToLoad.imageView);
              if (tag == null || !tag.equals(photoToLoad.url))
                     return true;
              return false;
       }

       // Used to display bitmap in the UI thread
       class BitmapDisplayer implements Runnable
       {
              Bitmap bitmap;
              PhotoToLoad photoToLoad;

              public BitmapDisplayer(Bitmap b, PhotoToLoad p)
              {
                     bitmap = b;
                     photoToLoad = p;
              }

              public void run()
              {
                     if (imageViewReused(photoToLoad))
                           return;
                     if (bitmap != null)
                     {
                           photoToLoad.imageView.setBackgroundResource(0);
                           photoToLoad.imageView.setImageBitmap(bitmap);
                           if(mTag==1 || mTag == 2)
                           {
                                  photoToLoad.imageView.setScaleType(ScaleType.FIT_XY); 
                           }
                           else if (mTag == 4)
                           {
                                  photoToLoad.imageView.setScaleType(ScaleType.FIT_CENTER);
                           }
                           else if (mTag == 5)
                           {
                                  photoToLoad.imageView.setScaleType(ScaleType.CENTER_CROP);   
                           }
                           else
                           {
                                  photoToLoad.imageView.setScaleType(ScaleType.FIT_START);
                           }     
                     }
                     else
                     {
                           Drawable drawable = mContext.getResources().getDrawable(R.drawable.no_image);
                           photoToLoad.imageView.setImageDrawable(drawable);
                     }
              }
       }

       public void clearCache()
       {
              memoryCache.clear();
              fileCache.clear();
       }

}

FileCache:
import java.io.File;
import android.content.Context;

public class FileCache {
   
    private File cacheDir;
   
    public FileCache(Context context){
        if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
            cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"ImageLoader");
        else
            cacheDir=context.getCacheDir();
        if(!cacheDir.exists())
            cacheDir.mkdirs();
    }
   
    public File getFile(String url){
        String filename=String.valueOf(url.hashCode());
        File f = new File(cacheDir, filename);
        return f;
       
    }
   
    public void clear(){
        File[] files=cacheDir.listFiles();
        if(files==null)
            return;
        for(File f:files)
            f.delete();
    }

}

MemoryCache: 
import java.lang.ref.SoftReference;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import android.graphics.Bitmap;

public class MemoryCache {
    private Map<String, SoftReference<Bitmap>> cache=Collections.synchronizedMap(new HashMap<String, SoftReference<Bitmap>>());
   
    public Bitmap get(String id)
    {
        if(!cache.containsKey(id))
            return null;
        SoftReference<Bitmap> ref=cache.get(id);
        return ref.get();
    }
   
    public void put(String id, Bitmap bitmap){
        cache.put(id, new SoftReference<Bitmap>(bitmap));
    }

    public void clear() {
        cache.clear();
    }
}

Utils:  
import java.io.InputStream;
import java.io.OutputStream;

public class Utils {
    public static void CopyStream(InputStream is, OutputStream os)
    {
        final int buffer_size=1024;
        try
        {
            byte[] bytes=new byte[buffer_size];
            for(;;)
            {
              int count=is.read(bytes, 0, buffer_size);
              if(count==-1)
                  break;
              os.write(bytes, 0, count);
            }
        }
        catch(Exception ex){}
    }
}
Constant:  
public class Constant
{

       public static int MAX_Image_SIZE = 320;
       public static int MAX_ThumbImage_SIZE = 125;
}

MainActivity:
import android.app.Activity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.widget.ImageView;

public class MainActivity extends Activity
{

       ImageLoader img_loader;
       ImageView imgPhoto=null;

       @Override
       protected void onCreate(Bundle savedInstanceState)
       {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.main);

              img_loader =new ImageLoader(MainActivity.this);       
              imgPhoto = (ImageView)findViewById(R.id.imgPhoto);           
              getImagesSize();
              img_loader.DisplayImage("http://talkingpointsmemo.com/images/google-android-mascot.jpg",imgPhoto,4);
       }

       private void getImagesSize()
       {            
              DisplayMetrics dm = new DisplayMetrics();
              getWindowManager().getDefaultDisplay().getMetrics(dm);
              int w = dm.widthPixels;
              int h = dm.heightPixels;

              if(w <= 240 && h <= 320)
              {
                     Constant.MAX_ThumbImage_SIZE = 100;
                     Constant.MAX_Image_SIZE = 400;

              }
              else if(w <= 320 && h <= 480)
              {
                     Constant.MAX_ThumbImage_SIZE = 100;
                     Constant.MAX_Image_SIZE = 600;

              }
              else if(w <= 480 && h <= 854)
              {
                     Constant.MAX_ThumbImage_SIZE = 150;
                     Constant.MAX_Image_SIZE = 900;

              }
              else
              {
                     Constant.MAX_ThumbImage_SIZE = 200;
                     Constant.MAX_Image_SIZE = 1000;

              }
       }
} 
Permission:
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />



Download full source code from here ImageLoaderSampleCode

Universal Images loader SampleCode

i will be happy if you will provide your feedback or follow this blog. Any suggestion and help will be appreciated.
Thank you :)


No comments:

Post a Comment