Android图片的三级缓存demo

Android图片的三级缓存demo

三级缓存概述

1,网络缓存, 不优先加载, 速度慢,浪费流量
2,本地缓存, 次优先加载, 速度快
3,内存缓存, 优先加载, 速度最快

缓存策略

首次加载时,通过网络来获取数据,将数据保存至本地和内存中
再次加载时,优先访问内存中的缓存,若内存中没有,则加载本地中的缓存

缓存的封装

ThreeLevelCache.java类
通过ThreeLevelCache.instance(this).display(mIv,url);即可调用
代码如下:

public class ThreeLevelCache {

    private static ThreeLevelCache mInstance;
    private NetworkCatche mNetworkCatche;
    private LocalCache mLocalCache;
    private MemoryCache mMemoryCache;

    public static ThreeLevelCache instance(Context context){
        if(null == mInstance){
            synchronized (ThreeLevelCache.class){
                if(null == mInstance) {
                    mInstance = new ThreeLevelCache(context);
                }
            }
        }
        return mInstance;
    }

    private ThreeLevelCache(Context context){
        mMemoryCache = new MemoryCache();
        mLocalCache = new LocalCache(context);
        mNetworkCatche = new NetworkCatche(mMemoryCache,mLocalCache);
    }

    public void display(ImageView iv, String url){
        iv.setImageResource(R.mipmap.ic_launcher);
        Bitmap bm;
        //get cache form memory
        bm = mMemoryCache.getBitmapCacheFromMemory(url);
        if(null != bm){
            iv.setImageBitmap(bm);
            Log.d("song--->","get cache form memory");
            return;
        }

        //get cache form local
        bm = mLocalCache.getBitmapCacheFromLocal(url);
        if(null != bm){
            iv.setImageBitmap(bm);
            Log.d("song--->","get cache form local");
            return;
        }

        //get cache form net
        mNetworkCatche.getBitmapFromNet(iv,url);
    }

}

网络缓存

从网络获取数据,获取成功之后对数据进行压缩。然后缓存到本地和内存中。
代码如下:

public class NetworkCatche {

    private MemoryCache mMemoryCache;
    private LocalCache mLocache;

    public NetworkCatche(MemoryCache memoryCache, LocalCache localCache) {
        mMemoryCache = memoryCache;
        mLocache = localCache;
    }

    public void getBitmapFromNet(ImageView iv, String url) {
        new BitmapTast().execute(iv,url);
    }

    class BitmapTast extends AsyncTask<Object,Void,Bitmap>{

        private ImageView iv;
        private String url;

        /**
         * do in thread
         * @param objects o
         * @return bitmap
         */
        @Override
        protected Bitmap doInBackground(Object... objects) {
            iv = (ImageView) objects[0];
            url = (String) objects[1];
            return downLoadBitmap(url);
        }

        /**
         * update progress
         * @param values v
         */
        @Override
        protected void onProgressUpdate(Void... values) {
            super.onProgressUpdate(values);
        }

        /**
         * call after doInBackground
         * @param bitmap bm
         */
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            if(null != bitmap){
                iv.setImageBitmap(bitmap);
                Log.d("song--->","first get data form net");

                //add cache to Local
                mLocache.setBitmapCacheFromLocal(url,bitmap);
                //add cache to memory
                mMemoryCache.setBitmapCacheFromMemory(url,bitmap);
            }
        }
    }

    /**
     * get bitmap form net
     * @param url image url
     * @return bitmap of image
     */
    private Bitmap downLoadBitmap(String url) {

        HttpURLConnection conn = null;
        try {
            conn = (HttpURLConnection) new URL(url).openConnection();
            conn.setConnectTimeout(5*1000);
            conn.setReadTimeout(5*1000);
            conn.setRequestMethod("GET");
            conn.connect();

            int responseCode = conn.getResponseCode();
            if(200 == responseCode){//200 == request  respon ok
                //压缩图片
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inSampleSize = 2;//取样压缩原来的1/2
                options.inPreferredConfig = Bitmap.Config.ARGB_4444;
                return BitmapFactory.decodeStream(conn.getInputStream(),null,options);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            conn.disconnect();
        }

        return null;
    }

}

本地缓存

同过数据的url进行MD5加密作为文件名缓存到本地。
代码如下:

public class LocalCache {

    private Context mContext;
    public LocalCache(Context ctx){
        mContext = ctx;
    }
    /**
     * get cache form local
     * @param url cache url
     * @return bitmap
     */
    public Bitmap getBitmapCacheFromLocal(String url) {
        String name = null;
        try {
            name = MD5Encoder.encode(url);
            File file = new File(getCachePath(),name);
            if(file.exists()) {
                //return BitmapFactory.decodeStream(new FileInputStream(file));
                return BitmapFactory.decodeFile(file.getAbsolutePath());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * save bitmap to local
     * @param url bitmap url
     * @param bitmap bitmap
     */
    public void setBitmapCacheFromLocal(String url, Bitmap bitmap) {

        String name ;
        FileOutputStream fos = null;

        try {
            name = MD5Encoder.encode(url);
            File file = new File(getCachePath(),name);
            File parentFile = file.getParentFile();
            if(!parentFile.exists())
                parentFile.mkdirs();
            //save bitmap to local file
            fos = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.JPEG,100,fos);
            Log.d("song--->","save cache to local");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * get cache path
     * @return path
     */
    private String getCachePath(){
        String state = Environment.getExternalStorageState();
        String path = "LocalCache/"+mContext.getPackageName()+"/data";
        File dir;
        if(!TextUtils.isEmpty(state) && Environment.MEDIA_MOUNTED.equals(state)){
            //has sdCard
            dir = new File(Environment.getExternalStorageDirectory(),path);
        } else {
            //no scCard
            dir = new File(mContext.getCacheDir(),path);
        }
        return dir.getAbsolutePath();
    }

}

内存缓存

Android 虚拟机默认分配给每个应用 16M的内存空间,真机会比16M大。
内存缓存使用LruCache

public class MemoryCache {

    private LruCache<String,Bitmap> mLruCach;

    public MemoryCache(){
        long maxMemory = Runtime.getRuntime().maxMemory()/8;
        mLruCach = new LruCache<String, Bitmap>((int)maxMemory){
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return  value.getByteCount();
            }
        };
    }

    public Bitmap getBitmapCacheFromMemory(String url) {
        return  mLruCach.get(url);
    }

    public void setBitmapCacheFromMemory(String url, Bitmap bitmap) {
        mLruCach.put(url,bitmap);
        Log.d("song--->","save cache to memory");
    }
}

MD5Encoder

MD5Encoder是从网上找的,顺便也贴出来,代码如下:

class MD5Encoder {

    /**
     * encode
     * @param string source string
     * @return encode string
     * @throws Exception e
     */
    public static String encode(String string) throws Exception{
        String MD5 = "MD5";
        String UTF_8 = "UTF-8";
        byte[] hash = MessageDigest.getInstance(MD5).digest(string.getBytes(UTF_8));
        StringBuffer hex = new StringBuffer(hash.length * 2);
        for(byte b:hash){
            if((b & 0xFF)<0x10){
                hex.append("0");
            }
            hex.append(Integer.toHexString(b & 0xFF));
        }
        return hex.toString();
    }
}

Tips网络权限和SDcard的读写权限

记得在配置文件AndroidManifest.xml里面给以下权限:

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

demo地址

感兴趣的可以去下载玩玩,点击传送

文章参考
https://blog.csdn.net/lovoo/article/details/51456515
https://blog.csdn.net/ChatHello/article/details/70573351

猜你喜欢

转载自blog.csdn.net/Song_74110/article/details/80876435