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

现在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 也是采用了三级缓存的思路。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring三级缓存是Spring框架内部的缓存机制,与Spring缓存机制并不直接相关。但是,Spring缓存机制可以用于对Bean的缓存,以提高应用程序的性能。下面介绍如何在Spring三级缓存使用Spring缓存机制。 1. 配置缓存管理器:在Spring配置文件配置缓存管理器。例如,使用Ehcache作为缓存管理器,可以在配置文件添加以下内容: ``` <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"> <property name="cacheManager" ref="ehcache"/> </bean> <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="classpath:ehcache.xml"/> </bean> ``` 2. 在需要缓存的方法上添加缓存注解:在需要缓存的方法上添加缓存注解,例如@Cacheable注解。例如: ``` @Service public class UserServiceImpl implements UserService { @Override @Cacheable(value = "userCache", key = "#userId") public User getUserById(String userId) { // 从数据库获取用户信息 User user = userDao.getUserById(userId); return user; } } ``` 3. 注入缓存管理器:在需要使用缓存的类注入缓存管理器。例如: ``` @Service public class UserServiceImpl implements UserService { @Autowired private CacheManager cacheManager; ... } ``` 4. 获取缓存对象:在需要使用缓存的方法,通过缓存管理器获取缓存对象,然后从缓存对象获取缓存数据。例如: ``` @Service public class UserServiceImpl implements UserService { @Autowired private CacheManager cacheManager; @Override public User getUserById(String userId) { Cache userCache = cacheManager.getCache("userCache"); ValueWrapper valueWrapper = userCache.get(userId); if (valueWrapper != null) { User user = (User) valueWrapper.get(); return user; } else { User user = userDao.getUserById(userId); userCache.put(userId, user); return user; } } } ``` 在使用Spring缓存机制时,需要注意缓存的key值的生成方式,可以使用SpEL表达式来指定。此外,需要根据具体的业务需求来决定缓存的策略,例如缓存的有效时间、缓存的清除策略等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值