Android网络图片加载三级缓存

2/13/2017来源:iOS开发人气:1144

一、概述

网络图片的加载在Android的开发中是一个必不可少的功能,今天我们就来聊聊网络图片加载三级缓存策略。 所谓的三级缓存策略是指通过网络、本地、内存三级来缓存图片,减少不必要的网络交互,避免浪费流量。

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

二、核心代码

网络图片加载工具类ImageLoader.java

package com.czhappy.helloimageloader; import android.graphics.Bitmap; import android.widget.ImageView; import com.czhappy.helloimageloader.core.LocalCacheUtils; import com.czhappy.helloimageloader.core.MemoryCacheUtils; import com.czhappy.helloimageloader.core.NetCacheUtils; import com.czhappy.helloimageloader.utils.LogUtil; import com.czhappy.helloimageloader.utils.Utils; /** * Description:网络图片加载工具类 * User: chenzheng * Date: 2017/2/11 0011 * Time: 11:21 */ public class ImageLoader { PRivate static ImageLoader mInstance = null; private NetCacheUtils mNetCacheUtils; private LocalCacheUtils mLocalCacheUtils; private MemoryCacheUtils mMemoryCacheUtils; public static ImageLoader getInstance(){ if(mInstance==null){ synchronized (ImageLoader.class){ if(mInstance==null){ mInstance = new ImageLoader(); } } } return mInstance; } private ImageLoader(){ mMemoryCacheUtils=new MemoryCacheUtils(); mLocalCacheUtils=new LocalCacheUtils(); mNetCacheUtils=new NetCacheUtils(mLocalCacheUtils,mMemoryCacheUtils); } /** * 加载网络图片 * @param mImageView * @param url */ public void loadImageView(ImageView mImageView, String url) { mImageView.setImageResource(R.drawable.empty_photo); if(Utils.isEmpty(url)){ return; } Bitmap bitmap; //内存缓存 LogUtil.i("尝试从内存中获取图片..."); bitmap=mMemoryCacheUtils.getBitmapFromMemory(url); if (bitmap!=null){ mImageView.setImageBitmap(bitmap); return; } //本地缓存 LogUtil.i("尝试从本地获取图片..."); bitmap = mLocalCacheUtils.getBitmapFromLocal(url); if(bitmap !=null){ mImageView.setImageBitmap(bitmap); //从本地获取图片后,保存至内存中 mMemoryCacheUtils.setBitmapToMemory(url,bitmap); return; } //网络缓存 LogUtil.i("尝试从网络获取图片..."); mNetCacheUtils.getBitmapFromNet(mImageView,url); } }

内存缓存MemoryCacheUtils.java

package com.czhappy.helloimageloader.core; import android.graphics.Bitmap; import android.util.LruCache; /** * Description: 内存缓存 * User: chenzheng * Date: 2017/2/11 0011 * Time: 11:15 */ public class MemoryCacheUtils { private LruCache<String,Bitmap> mMemoryCache; public MemoryCacheUtils(){ long maxMemory = Runtime.getRuntime().maxMemory()/8;//得到手机最大允许内存的1/8,即超过指定内存,则开始回收 //需要传入允许的内存最大值,虚拟机默认内存16M,真机不一定相同 mMemoryCache=new LruCache<String,Bitmap>((int) maxMemory){ //在每次存入缓存的时候调用,用于计算每个条目的大小 @Override protected int sizeOf(String key, Bitmap value) { int byteCount = value.getByteCount(); return byteCount; } }; } /** * 从内存中读图片 * @param url */ public Bitmap getBitmapFromMemory(String url) { Bitmap bitmap = mMemoryCache.get(url); return bitmap; } /** * 往内存中写图片 * @param url * @param bitmap */ public void setBitmapToMemory(String url, Bitmap bitmap) { mMemoryCache.put(url,bitmap); } }

本地缓存LocalCacheUtils.java

package com.czhappy.helloimageloader.core; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Environment; import com.czhappy.helloimageloader.utils.md5Util; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; /** * Description: 本地缓存 * User: chenzheng * Date: 2017/2/11 0011 * Time: 11:15 */ public class LocalCacheUtils { private static final String CACHE_PATH= Environment.getExternalStorageDirectory().getAbsolutePath()+"/HelloImageLoader"; /** * 从本地读取图片 * @param url */ public Bitmap getBitmapFromLocal(String url){ String fileName = null;//把图片的url当做文件名,并进行MD5加密 try { fileName = MD5Util.GetMD5Code(url); File file=new File(CACHE_PATH,fileName); if(file.exists()){ Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(file)); return bitmap; } } catch (Exception e) { e.printStackTrace(); } return null; } /** * 从网络获取图片后,保存至本地缓存 * @param url * @param bitmap */ public void setBitmapToLocal(String url,Bitmap bitmap){ try { String fileName = MD5Util.GetMD5Code(url);//把图片的url当做文件名,并进行MD5加密 File file=new File(CACHE_PATH,fileName); //通过得到文件的父文件,判断父文件是否存在 File parentFile = file.getParentFile(); if (!parentFile.exists()){ parentFile.mkdirs(); } //把图片保存至本地 bitmap.compress(Bitmap.CompressFormat.JPEG,100,new FileOutputStream(file)); } catch (Exception e) { e.printStackTrace(); } } }

网络缓存NetCacheUtils.java

package com.czhappy.helloimageloader.core; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.widget.ImageView; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; /** * Description: 网络缓存 * User: chenzheng * Date: 2017/2/11 0011 * Time: 11:15 */ public class NetCacheUtils { private LocalCacheUtils mLocalCacheUtils; private MemoryCacheUtils mMemoryCacheUtils; public NetCacheUtils(LocalCacheUtils localCacheUtils, MemoryCacheUtils memoryCacheUtils) { mLocalCacheUtils = localCacheUtils; mMemoryCacheUtils = memoryCacheUtils; } /** * 从网络下载图片 * @param mImageView 显示图片的imageview * @param url 下载图片的网络地址 */ public void getBitmapFromNet(ImageView mImageView, String url) { new BitmapTask().execute(mImageView, url);//启动AsyncTask } /** * AsyncTask就是对handler和线程池的封装 * 第一个泛型:参数类型 * 第二个泛型:更新进度的泛型 * 第三个泛型:onPostExecute的返回结果 */ class BitmapTask extends AsyncTask<Object, Void, Bitmap> { private ImageView mImageView; private String url; /** * 后台耗时操作,存在于子线程中 * @param params * @return */ @Override protected Bitmap doInBackground(Object[] params) { mImageView = (ImageView) params[0]; url = (String) params[1]; return downLoadBitmap(url); } /** * 更新进度,在主线程中 * @param values */ @Override protected void onProgressUpdate(Void[] values) { super.onProgressUpdate(values); } /** * 耗时方法结束后执行该方法,主线程中 * @param result */ @Override protected void onPostExecute(Bitmap result) { if (result != null) { mImageView.setImageBitmap(result); //从网络获取图片后,保存至本地缓存 mLocalCacheUtils.setBitmapToLocal(url, result); //保存至内存中 mMemoryCacheUtils.setBitmapToMemory(url, result); } } } /** * 网络下载图片 * @param url * @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"); int responseCode = conn.getResponseCode(); if (responseCode == 200) { //图片压缩 BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize=2;//宽高压缩为原来的1/2 options.inPreferredConfig=Bitmap.Config.ARGB_4444; Bitmap bitmap = BitmapFactory.decodeStream(conn.getInputStream(),null,options); return bitmap; } } catch (IOException e) { e.printStackTrace(); } finally { conn.disconnect(); } return null; } }

测试类

package com.czhappy.helloimageloaderdemo; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.ImageView; import com.czhappy.helloimageloader.ImageLoader; public class MainActivity extends AppCompatActivity { private ImageView my_image; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); my_image = (ImageView) findViewById(R.id.my_image); } public void beginLoad(View view){ String url = "http://img06.tooopen.com/images/20161112/tooopen_sy_185726882764.jpg"; ImageLoader.getInstance().loadImageView(my_image, url); } }

三、实现效果图

这里写图片描述