Android 使用三级缓存实现对图片的加载,提高用户体验

一、概述:
现在android应用中不可避免的要使用图片,有些图片是可以变化的,需要每次启动时从网络拉取,这种场景在有广告位的应用以及纯图片应用(比如百度美拍)中比较多。

现在有一个问题:假如每次启动的时候都从网络拉取图片的话,势必会消耗很多流量。在当前的状况下,对于非wifi用户来说,流量还是很贵的,一个很耗流量的应用,其用户数量级肯定要受到影响。当然,我想,向百度美拍这样的应用,必然也有其内部的图片缓存策略。总之,图片缓存是很重要而且是必须的。

二、实现原理:
实现图片缓存也不难,需要有相应的cache策略。这里我采用 内存-文件-网络 三层cache机制,其中内存缓存包括强引用缓存和软引用缓存(SoftReference),其实网络不算cache,这里姑且也把它划到缓存的层次结构中。当根据url向网络拉取图片的时候,先从内存中找,如果内存中没有,再从缓存文件中查找,如果缓存文件中也没有,再从网络上通过http请求拉取图片。在键值对(key-value)中,这个图片缓存的key是图片url的hash值,value就是bitmap。所以,按照这个逻辑,只要一个url被下载过,其图片就被缓存起来了。

三、如何使用

参数context,imageview,url以及默认站位图

ImageHelper.getInstance().display(mContext,mImageView,data.getImageUrl(),R.drawable.default_banner);

 

上源码............ 可直接cope

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.Handler;
import android.support.v4.util.LruCache;
import android.widget.ImageView;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * 图片三级缓存类
 */
public class ImageHelper {
    // LRUCahce 池子
    private static LruCache<String, Bitmap> mCache;
    private static Handler mHandler;
    private Context mContext;
    private int mDefaultImg;
    @SuppressLint("StaticFieldLeak")
    private static ImageHelper mBannerImageHelper;

    public static ImageHelper getInstance() {
        if (mBannerImageHelper == null) {
            synchronized (ImageHelper.class) {
                if (mBannerImageHelper == null) {
                    mBannerImageHelper = new ImageHelper();
                    init();
                }
            }
        }
        return mBannerImageHelper;
    }

    private static void init() {
        if (mCache == null) {
            // 最大使用的内存空间
            int maxSize = (int) (Runtime.getRuntime().freeMemory() / 4);
            if (maxSize > 0) {
                mCache = new LruCache<String, Bitmap>(maxSize) {
                    @Override
                    protected int sizeOf(String key, Bitmap value) {
                        return value.getRowBytes() * value.getHeight();
                    }
                };
            }
            if (mHandler == null) {
                mHandler = new Handler();
            }
        }

    }

    public void display(Context context, ImageView iv, String url, int defaultImg) {
        this.mDefaultImg = defaultImg;
        this.mContext = context;
        // 1.去内存中取
        if (url != null) {
            Bitmap bitmap = mCache.get(url);
            if (bitmap != null) {
                // 直接显示
                iv.setImageBitmap(bitmap);
                return;
            }
            // 2.去硬盘上取
            bitmap = loadBitmapFromLocal(url);
            if (bitmap != null) {
                // 直接显示
                iv.setImageBitmap(bitmap);
                return;
            }
            iv.setImageResource(mDefaultImg);
            // 3. 去网络获取图片
            new Thread(new ImageLoadTask(iv, url)).start();
        } else {
            iv.setImageResource(mDefaultImg);
        }

    }


    class ImageLoadTask implements Runnable {
        private String mUrl;
        private ImageView iv;
        private ImageLoadTask(ImageView iv, String url) {
            this.mUrl = url;
            this.iv = iv;
        }

        @Override
        public void run() {
            // HttpUrlconnection
            try {
                // 获取连接
                HttpURLConnection conn = (HttpURLConnection) new URL(mUrl).openConnection();
                conn.setConnectTimeout(30 * 1000);// 设置连接服务器超时时间
                conn.setReadTimeout(30 * 1000);// 设置读取响应超时时间
                // 连接网络
                conn.connect();
                // 获取响应码
                int code = conn.getResponseCode();
                if (200 == code) {
                    InputStream is = conn.getInputStream();
                    // 将流转换为bitmap
                    Bitmap bitmap = BitmapFactory.decodeStream(is);
                    // 存储到本地
                    write2Local(mUrl, bitmap);
                    // 存储到内存
                    mCache.put(mUrl, bitmap);
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            display(mContext, iv, mUrl, mDefaultImg);
                        }
                    });
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block0
                e.printStackTrace();
            }
        }
    }

    /**
     * 本地种去去图片
     *
     * @param url
     */
    private Bitmap loadBitmapFromLocal(String url) {
        // 去找文件,将文件转换为bitmap
        String name;
        try {
            name = MD5Encoder.encode(url);
            File file = new File(getCacheDir(), name);
            if (file.exists()) {
                Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
                // 存储到内存
                mCache.put(url, bitmap);
                return bitmap;
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    private void write2Local(String url, Bitmap bitmap) {
        String name;
        FileOutputStream fos = null;
        try {
            name = MD5Encoder.encode(url);
            File file = new File(getCacheDir(), name);
            fos = new FileOutputStream(file);
            // 将图像写到流中
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                    fos = null;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private String getCacheDir() {
        String state = Environment.getExternalStorageState();
        File dir = null;
        if (Environment.MEDIA_MOUNTED.equals(state)) {
            // 有sd卡
            dir = new File(Environment.getExternalStorageDirectory(), "/Android/data/" + mContext.getPackageName() + "/icon");
        } else {
            // 没有sd卡
            dir = new File(mContext.getCacheDir(), "/icon");
        }
        if (!dir.exists()) {
            dir.mkdirs();
        }
        return dir.getAbsolutePath();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值