1、网络缓存 从网络获取资源(异步加载) 2、本地缓存 从本地获取数据(File存储) 3、内存缓存 从内存获取数据(LruCache)
主要是用到了LruCache这个类,这个类比较适合用来缓存图片,它会将强引用对象放在LinkedHashMap中,当缓存数据大小达到预定值的时候会将在该集合中比较少使用的对象从内存中移除。
package com.example.administrator.downloadimgdemo.utils; import android.graphics.Bitmap; import android.util.LruCache; /** * Created by Administrator on 2017/5/4. */ public class MemoryCacheUtil { private LruCache<String, Bitmap> mLruCache; public MemoryCacheUtil() { // maxMemory 是允许的最大值 ,超过这个最大值,则会回收 int maxMemory = (int) Runtime.getRuntime().maxMemory(); int cacheSize = maxMemory / 8; mLruCache = new LruCache<String, Bitmap>(cacheSize) { /** * 计算每张图片的大小 * @param key * @param bitmap * @return */ @Override protected int sizeOf(String key, Bitmap bitmap) { return bitmap.getByteCount(); } }; } /** * 通过url从内存中获取图片 * * @param url */ public Bitmap getBitmapFromMemory(String url) { return mLruCache.get(url); } /** * 设置Bitmap到内存 * * @param url * @param bitmap */ public void setBitmapToMemory(String url, Bitmap bitmap) { if (getBitmapFromMemory(url) == null) { mLruCache.put(url, bitmap); // 设置图片 } } /** * 从缓存中删除指定的Bitmap * * @param key */ public void removeBitmapFromMemory(String key) { mLruCache.remove(key); } }使用对应的键和值将数据put进集合中,使用get方法再取出来
将网络上获取下来的数据,保存在本地文件中.
package com.example.administrator.downloadimgdemo.utils; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Environment; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; /** * Created by Administrator on 2017/5/4. */ public class LocalCacheUtil { private String cachePath; public LocalCacheUtil(Context context, String uniqueName) { cachePath = getCacheDirString(context, uniqueName); } /** * 设置Bitmap数据到本地 * * @param url * @param bitmap */ public void setBitmapToLocal(String url, Bitmap bitmap) { FileOutputStream fos = null; try { String fileName = MD5Encoder.encode(url); File file = new File(cachePath, fileName); File parentFile = file.getParentFile();//获取上级所有目录 if (!parentFile.exists()) { // 如果文件不存在,则创建文件夹 parentFile.mkdirs(); } 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(); } } } } /** * 通过url获取Bitmap * * @param url */ public Bitmap getBitmapFromLocal(String url) { try { File file = new File(cachePath, MD5Encoder.encode(url)); if (file.exists()) { // 如果文件存在 Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(file)); //Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); return bitmap; } } catch (Exception e) { e.printStackTrace(); } return null; } /*获取缓存目录的路径:String类型*/ private String getCacheDirString(Context context, String uniqueName) { File file = null; if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) { file = new File(context.getExternalCacheDir(), uniqueName); //file = new File(Environment.getExternalStorageDirectory(), uniqueName); } else { file = new File(context.getCacheDir(), uniqueName); } if (!file.exists()) { file.mkdirs(); } return file.getAbsolutePath(); } }用于生成保存的文件名:
package com.example.administrator.downloadimgdemo.utils; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * Created by Administrator on 2017/5/4. */ public class MD5Encoder { public static String encode(String pwd) { StringBuffer sb = new StringBuffer(); try { MessageDigest digest = MessageDigest.getInstance("MD5"); byte[] bytes = digest.digest(pwd.getBytes("UTF-8")); for (int i = 0; i < bytes.length; i++) { String s = Integer.toHexString(0xff & bytes[i]); if (s.length() == 1) { sb.append("0" + s); } else { sb.append(s); } } } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return sb.toString(); } }通过url从网络上获取资源数据,通过异步AsyncTask拉取数据,同时,如果成功拉取到数据,将数据保存在本地和内存中一份。
package com.example.administrator.downloadimgdemo.utils; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.widget.ImageView; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; /** * Created by Administrator on 2017/5/4. */ public class NetCacheUtil { private MemoryCacheUtil mMemoryCacheUtil; private LocalCacheUtil mLocalCacheUtil; public NetCacheUtil(MemoryCacheUtil mMemoryCacheUtil, LocalCacheUtil mLocalCacheUtil) { this.mMemoryCacheUtil = mMemoryCacheUtil; this.mLocalCacheUtil = mLocalCacheUtil; } /** * 获取服务端数据 * * @param ivPhoto * @param url */ public void getBitmapFromInternet(ImageView ivPhoto, String url) { new BitmapAsyncTask().execute(ivPhoto, url); // 开启AsyncTask } /** * 第一个泛型:参数类型 第二个泛型:更新进度的泛型, 第三个泛型是OnPostExecute的结果 * Object : 传入的参数类型 * Void : 进度 * Bitmap : 返回类型 */ private class BitmapAsyncTask extends AsyncTask<Object, Void, Bitmap> { private ImageView ivPhoto; private String url; /** * 运行在子线程中:请求数据 * * @param params * @return */ @Override protected Bitmap doInBackground(Object... params) { ivPhoto = (ImageView) params[0]; // 获取两个参数 url = (String) params[1]; Bitmap bitmap = downloadBitmap(url); // 从网络上加载图片 return bitmap; } /** * 在主线程中执行 用于更新界面 * * @param bitmap */ @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); if (bitmap != null) { ivPhoto.setImageBitmap(bitmap); // 为ImageView设置图片 System.out.println("从网络获取图片..."); // 将获取到的图片加载到本地 mLocalCacheUtil.setBitmapToLocal(url, bitmap); // 将获取到的图片加载到内存 mMemoryCacheUtil.setBitmapToMemory(url, bitmap); } } } /** * 根据url从网络上获取图片 * * @param imageUrl 图片路径 * @return */ private Bitmap downloadBitmap(String imageUrl) { HttpURLConnection conn = null; try { URL url = new URL(imageUrl); conn = (HttpURLConnection) url.openConnection(); // 打开连接 conn.setReadTimeout(5000); // 设置读取超时时间 conn.setConnectTimeout(5000); // 设置连接超时时间 conn.setRequestMethod("GET"); // 设置请求方式 conn.connect(); // 开始连接 if (conn.getResponseCode() == 200) { // 访问成功 InputStream is = conn.getInputStream(); // 获取流数据 // 对图片进行压缩处理 BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2; // 图片的宽高都为原来的一半(分辨率) Bitmap bitmap = BitmapFactory.decodeStream(is, null, options); // 将流数据转成Bitmap对象 return bitmap; } else { // 访问失败 return null; } } catch (Exception e) { e.printStackTrace(); } finally { if (conn != null) { conn.disconnect(); // 断开连接 } } return null; } }工具类:MyBitmapUtil:三级缓存的工具类
package com.example.administrator.downloadimgdemo.utils; import android.content.Context; import android.graphics.Bitmap; import android.widget.ImageView; /** * Created by Administrator on 2017/5/4. */ public class MyBitmapUtil { private MemoryCacheUtil mMemoryCacheUtil = null; // 内存缓存(lrucache) private LocalCacheUtil mLocalCacheUtil = null; // 本地缓存(file) private NetCacheUtil mNetCacheUtil = null; // 网络缓存 public MyBitmapUtil(Context context, String uniqueName) { mMemoryCacheUtil = new MemoryCacheUtil(); mLocalCacheUtil = new LocalCacheUtil(context,uniqueName); mNetCacheUtil = new NetCacheUtil(mMemoryCacheUtil, mLocalCacheUtil); } /** * 将图片资源设置给控件 * * @param url * @param ivPhoto */ public void display(String url, ImageView ivPhoto) { Bitmap bitmap = null; // 1.判断内存中是否有缓存 bitmap = mMemoryCacheUtil.getBitmapFromMemory(url); // 从内存中获取Bitmap if (bitmap != null) { ivPhoto.setImageBitmap(bitmap); // 设置图片 System.out.println("从内存获取图片..."); return; } // 2.判断本地是否有缓存 bitmap = mLocalCacheUtil.getBitmapFromLocal(url); // 从本地缓存中获取Bitmap if (bitmap != null) { ivPhoto.setImageBitmap(bitmap); // 设置本地图片 mMemoryCacheUtil.setBitmapToMemory(url, bitmap); // 设置图片到内存 System.out.println("从本地获取图片..."); return; } // 3.从网络获取数据 mNetCacheUtil.getBitmapFromInternet(ivPhoto, url); // 设置图片 } }参考:
Android — 简单实现三级缓存LruCache