工作中图片的三级缓存机制介绍

本文详细介绍了一种在Android应用中实现图片缓存的有效方法,采用内存-本地-网络的三层缓存策略,以提高图片加载效率并减少网络流量消耗。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现在android应用中不可避免的要使用图片,有些图片是可以变化的,需要每次启动时从网络拉取,这种场景在目前市场的应用以及纯图片应用(比如百度美拍)中比较多。
实现图片缓存也不难,需要有相应的cache策略。这里我采用 内存(memory)-本地(local)-网络(Internet) 三层cache机制,其实网络不算cache。
当根据url向网络拉取图片的时候,先从本应用内存中找,如果内存中没有,再从本地缓存文件中查找,如果缓存文件中也没有,再从网络上通过http请求拉取图 片。在键值对(key-value)中,这个图片缓存的key是图片url的hash值,value就是bitmap。所以,按照这个逻辑,只要一个 url被下载过,其图片就被缓存起来了。

三级缓存的比较:
-内存缓存,优先加载,速度最快
-本地缓存,次优先加载,速度快
-网络缓存,不优先加载,速度慢,浪费流量。

现在我们来看看怎么去实现这个缓存。

首先是网络缓存的类:

/**
 * 
 * 从网络下载图片
 * @lly
 *
 */
public class NetCacheUtils {
    private LocalCacheUtils mlocalcacheutils;
    private MemoryCacheUtils mmemorycacheutils;

    public NetCacheUtils(LocalCacheUtils localcacheutils, MemoryCacheUtils memorycacheutils) {
        mlocalcacheutils=localcacheutils;
        mmemorycacheutils=memorycacheutils;
    }

    public void getBitmapFromNet(ImageView iv_photo, String url) {
        // TODO Auto-generated method stub
        BitmapTask bitmaptask=new BitmapTask();
        bitmaptask.execute(iv_photo,url);//开启AsyncTask,参数在doInBackground获取
    }
    /*AsyncTask  异步任务即做一些简单的异步处理  ;是handle与线程池的封装
     * 第一个泛型:参数类型泛型
     * 第二个泛型:更新进度泛型
     * 第三个泛型:onProgressUpdate的返回结果的泛型
     * 
     */
    
    class BitmapTask extends AsyncTask<Object, Void, Bitmap>{

        private ImageView pic;
        private String murl;
        /**
         * 后台耗时方法在此执行,子线程
         */
        @Override
        protected Bitmap doInBackground(Object... params) {
            pic = (ImageView) params[0];
            murl = (String) params[1];
            
            pic.setTag(murl);//将图片与url绑定
            return downloadBitmap(murl);
        }
        /**
         * 更新进度,主线程
         */
        @Override
        protected void onProgressUpdate(Void... values) {
            // TODO Auto-generated method stub
            super.onProgressUpdate(values);
        }
        /**
         * 后台耗时方法结束之后,在此执行,主线程
         */
        @Override
        protected void onPostExecute(Bitmap result) {
            if(result!=null){
                
                String tag = (String) pic.getTag();
                if(tag.equals(murl)){
                    pic.setImageBitmap(result);
                }
                
            }
            mlocalcacheutils.setBitmapTolocal(murl, result);
            mmemorycacheutils.setBitmapTomemory(murl, result);
            System.out.println("从网络上加载图片啦");
            
        }
    }

    /**
     * 
     * 下载图片
     * @return 
     */
    private Bitmap downloadBitmap(String url){
        HttpURLConnection conn=null;
        try {
            conn=(HttpURLConnection) new URL(url)
            .openConnection();
            
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);
            conn.setRequestMethod("GET");
            conn.connect();
            
            int responseCode = conn.getResponseCode();//响应码
            
            if(responseCode==200){//表示成功连接
                InputStream inputStream = conn.getInputStream();
                Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                return bitmap;
            }
            
        } catch (IOException e) {
            
            e.printStackTrace();
        }
        finally{
            conn.disconnect();
        }
        return null;
        
    }
}

本地缓存的实现:

public class LocalCacheUtils {
    private static final String CACHE_PATH=Environment.getExternalStorageDirectory()
            .getAbsolutePath()+"/zhbj_cache_52";
/**
 * 
 * 从本地读图片
 * @param url
 */
    public Bitmap getBitmapFromlocal(String url){
        try {
            String filename = MD5Encoder.encode(url);
            
            File file=new File(CACHE_PATH, filename);//通过父文件夹与自己的文件名称来创建一个文件
            
            if(file.exists()){
                Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(file));
                return bitmap;
            }
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
        
    }
    
/**
 * 
 * 将图片写到本地
 * @param url
 * @param bitmap
 */
    public void setBitmapTolocal(String url,Bitmap bitmap){
        try {
            String filename = MD5Encoder.encode(url);
            File file=new File(filename);
            File parentFile = file.getParentFile();
            if(!parentFile.exists()){//如果文件夾不存在,則创建
                file.mkdirs();
            }
            //将图片保存到本地
            bitmap.compress(CompressFormat.JPEG, 100, 
                    new FileOutputStream(file));
                
    
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
    
}

接下来是内存缓存的实现:

/**
 * 
 * 内存缓存
 * @lly
 *
 */
public class MemoryCacheUtils {
 
    private HashMap<String, Bitmap> hashlist=new HashMap<String, Bitmap>();
    /**
     * 
     * 从内存中读
     * @param url
     * @return
     */
    public  Bitmap getBitmapFrommemory(String url){
        Bitmap bitmap = hashlist.get(url);
        return bitmap;
    }
    

    /**
     * 
     * 写入内存
     * @param url
     * @param bitmap
     */
    public  void setBitmapTomemory(String url,Bitmap bitmap){
        hashlist.put(url, bitmap);
    }
}

最后是我们自己实现的图片加载工具:

/**
 * 
 * 图片加载工具
 * @lly
 *
 */
public class BitMaputils {
    NetCacheUtils netcache;
    LocalCacheUtils localcacheutils;
    MemoryCacheUtils memorycacheutils;
    public BitMaputils(){
        memorycacheutils=new MemoryCacheUtils();
        localcacheutils=new LocalCacheUtils();
        netcache=new NetCacheUtils(localcacheutils,memorycacheutils);
        
    }
    Bitmap bitmap =null;
    public void display(ImageView iv_photo, String url) {
        iv_photo.setImageResource(R.drawable.news_pic_default);//默认图片,防止图片的复用
        //内存缓存
        bitmap= memorycacheutils.getBitmapFrommemory(url);
        if(bitmap!=null){
            iv_photo.setImageBitmap(bitmap);
            System.out.println("从内存中读取图片");
            return;
        }
        //本地缓存
        bitmap = localcacheutils.getBitmapFromlocal(url);
        if(bitmap!=null){
            iv_photo.setImageBitmap(bitmap);
            memorycacheutils.setBitmapTomemory(url, bitmap);
            System.out.println("从本地读取图片");
            return;//从本地读取就不需要从网络读取了
        }
        
        //网络缓存(第一次)
        netcache.getBitmapFromNet(iv_photo,url);
    }

    
}

 

图片框架:Android-Universal-Image-Loader 也是采用了三级缓存的思路。

用于类似图库,缓存,所困、缩略图 package com.example.cache; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.lang.ref.SoftReference; import java.util.HashMap; import java.util.Map; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapFactory.Options; import android.util.DisplayMetrics; /** * 1.从内存中加载 * 2.本地缓存中加载 * 3.本地加载 * @author Administrator * */ public class LoadCacheImageTool { private Activity activity; private Map<String,SoftReference> cacheMap; public LoadCacheImageTool(Activity activity){ this.activity = activity; this.cacheMap = new HashMap<String, SoftReference>(); } public Bitmap loadCacheImage(String imagePath){ Bitmap bitmap = null; if (cacheMap.containsKey(imagePath)) { bitmap = cacheMap.get(imagePath).get(); if (bitmap!=null) { return bitmap; } } bitmap = loadLocalCacheImage(imagePath); cacheMap.put(imagePath, new SoftReference(bitmap)); return bitmap; } ///mnt/sdcard/bk.png ///mnt/sdcard/cache/bk.png.cache private Bitmap loadLocalCacheImage(String imagePath) { Bitmap bitmap = null; String cacheImagePath = getCacheImagePath(imagePath); File cacheFile = new File(cacheImagePath); if (!cacheFile.exists()) { bitmap = loadLocalBigImage(imagePath); saveToCacheDir(bitmap,cacheImagePath); }else{ try { bitmap = BitmapFactory.decodeStream(new FileInputStream(cacheFile)); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return bitmap; } private String getCacheImagePath(String imagePath) { String cacheDir = new File(imagePath).getParent()+"/cache/"; if (!new File(cacheDir).exists()) { new File(cacheDir).mkdirs(); } String newImageName = new File(imagePath).getName()+".cache"; String newImagePath = cacheDir+newImageNam
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值