* 三级缓存设计步骤:
* 从内存中取图片
*
* 从本地文件中取图片
* 向内存中保持一份
*
* 请求网络图片,获取图片,显示到控件上(Hanlder,postion):
* 向内存 存一份
* 向本地文件中存一份
因此我们的储存的逻辑是从网络请求开始写的,第二步实现本地缓存,第三步最后实现内存缓存。
其中从内存缓存中获取最快,本地缓存次之,网络请求垫底。
因为网络缓存中需要,向内存 存一份,向本地文件中存一份,因此需要把内存和本地缓存的工具类实例传进来。
public class NetCacheUtils {
//请求图片成功
public static final int SUCESS = 1;
public static final int FAIL = 2;
//本地缓存工具类
private final LocalCacheUtels localCacheUtils;
//内存缓存工具类
private final MemoryCacheUtils memoryCacheUtils;
//线程池服务类
private ExecutorService service;
public NetCacheUtils( LocalCacheUtels localCacheUtels, MemoryCacheUtils memoryCacheUtils) {
this.localCacheUtils = localCacheUtels;
this.memoryCacheUtils = memoryCacheUtils;
}
//联网请求得到图片
public void getBitmapFromNet(String imageUrl, int position) {
service= Executors.newFixedThreadPool(10);
service.execute(new MyRunnable(imageUrl,position));
}
class MyRunnable implements Runnable{
private final int position;
private String imageUrl;
public MyRunnable(String imageUrl, int position) {
this.imageUrl = imageUrl;
this.position = position;
}
@Override
public void run() {
//子线程
//请求网络图片
try {
HttpURLConnection connection = (HttpURLConnection) new URL(imageUrl).openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(4000);
connection.setReadTimeout(4000);
connection.connect();//可写 可不写
int code = connection.getResponseCode();
if (code == 200){
InputStream is = connection.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(is);
//在内存中缓存一份
memoryCacheUtils.putBitmap(imageUrl,bitmap);
//在本地中缓存一份
localCacheUtils.putBitmap(imageUrl,bitmap);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//该工具类直接复制粘贴 即可使用
public class MD5Encoder {
public static String encode(String string) throws Exception {
byte[] hash = MessageDigest.getInstance("MD5").digest(string.getBytes("UTF-8"));
StringBuilder hex = new StringBuilder(hash.length * 2);
for (byte b : hash) {
if ((b & 0xFF) < 0x10) {
hex.append("0");
}
hex.append(Integer.toHexString(b & 0xFF));
}
return hex.toString();
}
}
class LocalCacheUtels {
private final MemoryCacheUtils memoryCacheUtils;
//传入内存缓存工具类实例
public LocalCacheUtels(MemoryCacheUtils memoryCacheUtils) {
this.memoryCacheUtils = memoryCacheUtils;
}
/**
* 获取储存图片
* @param imageUrl
* @return
*/
public Bitmap getBitmapFromUrl(String imageUrl) {
//判断sd卡是否可用
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
try {
String fileName = MD5Encoder.encode(imageUrl);
File file = new File("/data/data/com.coderpig.beijingnews/beijingnews/",fileName);
if (file.exists()){
FileInputStream is = new FileInputStream(file);
Bitmap bitmap = BitmapFactory.decodeStream(is);
if (bitmap!=null){
memoryCacheUtils.putBitmap(imageUrl,bitmap);
LogUtil.e("从本地保存到内存中");
}
return bitmap;
}
} catch (Exception e) {
e.printStackTrace();
LogUtil.e("图片本地获取失败");
}
}
return null;
}
/**
* 根据Url 保存图片
* @param imageUrl:url
* @param bitmap:图片
*/
public void putBitmap(String imageUrl, Bitmap bitmap) {
//保存图片在 /mnt/sdcard/beijingnews/http://。。。。。
///data/data/com.coderpig.beijingnews/beijingnews
//判断sd卡是否可用
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
try {
String fileName = MD5Encoder.encode(imageUrl);
//LogUtil.e("图片保存地址是:" + Environment.getExternalStorageDirectory().toString());
File file = new File("/data/data/com.coderpig.beijingnews/beijingnews/",fileName);
if (!file.exists()){
file.createNewFile();
}
//保存图片
bitmap.compress(Bitmap.CompressFormat.PNG,100,new FileOutputStream(file));
LogUtil.e("图片本地缓存--成功");
} catch (Exception e) {
e.printStackTrace();
LogUtil.e("图片本地缓存--失败");
}
}
}
}
不得不提一下LruCache是面试常客,知道怎么用,却不知道它是怎么干的,这就出大问题,知其然得知其所以然,下面这篇链接的文章 可以带你进行一次源码层的遨游。
LruCache实现原理分析 作者:胖子爱你520
class MemoryCacheUtils {
private LruCache<String, Bitmap> lruCache;
public MemoryCacheUtils() {
//使用系统分配给应用的内存的八分之一
int maxSize = (int) (Runtime.getRuntime().maxMemory()/8);
lruCache = new LruCache<String, Bitmap>(maxSize){
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes() * value.getHeight();
}
};
}
/**
* 根据url去取
* @param imageUrl
* @return
*/
public Bitmap getBitmapFromUrl(String imageUrl) {
return lruCache.get(imageUrl);
}
/**
* 根据ur保存图片到lrucache集合中
* @param imageUrl
* @param bitmap
*/
public void putBitmap(String imageUrl, Bitmap bitmap) {
lruCache.put(imageUrl,bitmap);
}
}
private MemoryCacheUtils memoryCacheUtils;
public BitmapCacheUtils(){
memoryCacheUtils = new MemoryCacheUtils();
localCacheUtels = new LocalCacheUtels(memoryCacheUtils);
netCacheUtils = new NetCacheUtils(localCacheUtels,memoryCacheUtils);
}
/**
* 三级缓存设计步骤:
* 从内存中取图片
*
* 从本地文件中取图片
* 向内存中保持一份
*
* 请求网络图片,获取图片,显示到控件上(Hanlder,postion):
* 向内存 存一份
* 向本地文件中存一份
* @param imageUrl
* @param position
* @return
*/
public Bitmap getBitmap(String imageUrl, int position) {
//1.从内存中取图片
if (memoryCacheUtils!=null){
Bitmap bitmap = memoryCacheUtils.getBitmapFromUrl(imageUrl);
if (bitmap != null){
LogUtil.e("内存加载图片==成功"+position);
return bitmap;
}
}
//2.从本地文件中取图片
if (localCacheUtels != null){
Bitmap bitmap = localCacheUtels.getBitmapFromUrl(imageUrl);
if (bitmap != null){
LogUtil.e("本地加载图片==成功"+position);
return bitmap;
}
}
//3.请求网络图片,获取图片
netCacheUtils.getBitmapFromNet(imageUrl,position);
return null;
}
}