Android – Load images from web and caching

Posted August 27, 2012
Problem: How do i load images from web and caching (storing images inside local storage)?
Description:

Have you gone through my previous article for Loading Remote Images in android?, actually it was the solution for loading images from web but not caching into the local storage so that it has to load image every times, instead here in this article i am going to show you code/demo for loading images from web as well as to cache images in local also, so that whenever image has to be loaded it will check and load image from local if cached already.



Solution:

MainActivity.java

package com.technotalkative.loadwebimage;import com.technotalkative.loadwebimage.R;import com.technotalkative.loadwebimage.imageutils.ImageLoader;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.widget.ImageView;public class MainActivity extends Activity {private ImageView imgView;private ImageLoader imgLoader;private String strURL = "http://technotalkative.com/android.jpg";    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);            imgView = (ImageView) findViewById(R.id.imageView1);    imgLoader = new ImageLoader(this);    }     public void btnLoadImageClick(View v){        imgLoader.DisplayImage(strURL, imgView);    }}

ImageLoader.java
Using DisplayImage(Url, ImageView) method of ImageLoader class, you can load and cache image. You just need to provide the web url of image and the imageview in which you want to display loaded image.

package com.technotalkative.loadwebimage.imageutils;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;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.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.widget.ImageView;import com.technotalkative.loadwebimage.R;public class ImageLoader {        MemoryCache memoryCache=new MemoryCache();    FileCache fileCache;    private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>());    ExecutorService executorService;         public ImageLoader(Context context){        fileCache=new FileCache(context);        executorService=Executors.newFixedThreadPool(5);    }        final int stub_id=R.drawable.ic_launcher;    public void DisplayImage(String url, ImageView imageView)    {        imageViews.put(imageView, url);        Bitmap bitmap=memoryCache.get(url);        if(bitmap!=null)            imageView.setImageBitmap(bitmap);        else        {            queuePhoto(url, imageView);            imageView.setImageResource(stub_id);        }    }            private void queuePhoto(String url, ImageView imageView)    {        PhotoToLoad p=new PhotoToLoad(url, imageView);        executorService.submit(new PhotosLoader(p));    }        private 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    private Bitmap decodeFile(File f){        try {            //decode image size            BitmapFactory.Options o = new BitmapFactory.Options();            o.inJustDecodeBounds = true;            BitmapFactory.decodeStream(new FileInputStream(f),null,o);                        //Find the correct scale value. It should be the power of 2.            final int REQUIRED_SIZE=70;            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;            return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);        } catch (FileNotFoundException e) {}        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);            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.setImageBitmap(bitmap);            else                photoToLoad.imageView.setImageResource(stub_id);        }    }    public void clearCache() {        memoryCache.clear();        fileCache.clear();    }}

These are the required classes for loading image asynchronously and caching into the local memory storage.
1) MemoryCache
2) FileCache
3) Utils

MemoryCache.java

package com.technotalkative.loadwebimage.imageutils;import java.util.Collections;import java.util.Iterator;import java.util.LinkedHashMap;import java.util.Map;import java.util.Map.Entry;import android.graphics.Bitmap;import android.util.Log;public class MemoryCache {    private static final String TAG = "MemoryCache";    private Map<String, Bitmap> cache=Collections.synchronizedMap(            new LinkedHashMap<String, Bitmap>(10,1.5f,true));//Last argument true for LRU ordering    private long size=0;//current allocated size    private long limit=1000000;//max memory in bytes    public MemoryCache(){        //use 25% of available heap size        setLimit(Runtime.getRuntime().maxMemory()/4);    }        public void setLimit(long new_limit){        limit=new_limit;        Log.i(TAG, "MemoryCache will use up to "+limit/1024./1024.+"MB");    }    public Bitmap get(String id){        try{            if(!cache.containsKey(id))                return null;            //NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78             return cache.get(id);        }catch(NullPointerException ex){            ex.printStackTrace();            return null;        }    }    public void put(String id, Bitmap bitmap){        try{            if(cache.containsKey(id))                size-=getSizeInBytes(cache.get(id));            cache.put(id, bitmap);            size+=getSizeInBytes(bitmap);            checkSize();        }catch(Throwable th){            th.printStackTrace();        }    }        private void checkSize() {        Log.i(TAG, "cache size="+size+" length="+cache.size());        if(size>limit){            Iterator<Entry<String, Bitmap>> iter=cache.entrySet().iterator();//least recently accessed item will be the first one iterated              while(iter.hasNext()){                Entry<String, Bitmap> entry=iter.next();                size-=getSizeInBytes(entry.getValue());                iter.remove();                if(size<=limit)                    break;            }            Log.i(TAG, "Clean cache. New size "+cache.size());        }    }    public void clear() {        try{            //NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78             cache.clear();            size=0;        }catch(NullPointerException ex){            ex.printStackTrace();        }    }    long getSizeInBytes(Bitmap bitmap) {        if(bitmap==null)            return 0;        return bitmap.getRowBytes() * bitmap.getHeight();    }}

FileCache.java
Using FileCache, we will create TTImages_cache folder for caching images into it. Also to load image if synced already. We can use clear() method of FileCache class to clear synced images.

package com.technotalkative.loadwebimage.imageutils;import java.io.File;import android.content.Context;public class FileCache {        private File cacheDir;        public FileCache(Context context){        //Find the dir to save cached images        if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))            cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"TTImages_cache");        else            cacheDir=context.getCacheDir();        if(!cacheDir.exists())            cacheDir.mkdirs();    }        public File getFile(String url){        //I identify images by hashcode. Not a perfect solution, good for the demo.        String filename=String.valueOf(url.hashCode());        //Another possible solution (thanks to grantland)        //String filename = URLEncoder.encode(url);        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();    }}

Utils.java

package com.technotalkative.loadwebimage.imageutils;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){}    }}

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <Button        android:id="@+id/btnLoadImage"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerHorizontal="true"        android:onClick="btnLoadImageClick"        android:text="Load Image" />    <ImageView        android:id="@+id/imageView1"        android:layout_width="match_parent"        android:layout_height="200dp"        android:layout_centerInParent="true"        android:padding="10dp"        android:scaleType="fitXY"        android:src="@drawable/ic_launcher" /></RelativeLayout>

Note:
Don’t forget to include INTERNET and WRITE_EXTERNAL_STORAGE permission in AndroidManifest.xml

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

更多相关文章

  1. 代码中设置drawableleft
  2. android 3.0 隐藏 系统标题栏
  3. Android开发中activity切换动画的实现
  4. Android(安卓)学习 笔记_05. 文件下载
  5. Android中直播视频技术探究之—摄像头Camera视频源数据采集解析
  6. 技术博客汇总
  7. android 2.3 wifi (一)
  8. AndRoid Notification的清空和修改
  9. Android中的Chronometer

随机推荐

  1. Android下如何调试程序
  2. 基于移动平台的多媒体框架——移植SDL到A
  3. 浅谈Android之Binder原理介绍(一)
  4. [Android(安卓)Pro] Android应用性能测试
  5. [Android进阶]Android消息机制
  6. Android中使用到的四种类型的PNG图片
  7. App测试中ios和Android的区别
  8. android 中webview基本使用的方法小结
  9. Android使用NFC模拟M卡实现 (三)
  10. Android(安卓)Service生命周期及用法