MD5工具:
package com.bwie.dongchangqi.tinkertest; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * Created by Administrator on 2018/1/19 0019. */ public class Md5Utils { /* * 1.一个运用基本类的实例 * MessageDigest 对象开始被初始化。该对象通过使用 update 方法处理数据。 * 任何时候都可以调用 reset 方法重置摘要。 * 一旦所有需要更新的数据都已经被更新了,应该调用 digest 方法之一完成哈希计算。 * 对于给定数量的更新数据,digest 方法只能被调用一次。 * 在调用 digest 之后,MessageDigest 对象被重新设置成其初始状态。 */ public static String md5(String context) { try { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(context.getBytes());//update处理 byte[] encryContext = md.digest();//调用该方法完成计算 int i; StringBuffer buf = new StringBuffer(""); for (int offset = 0; offset < encryContext.length; offset++) {//做相应的转化(十六进制) i = encryContext[offset]; if (i < 0) i += 256; if (i < 16) buf.append("0"); buf.append(Integer.toHexString(i)); } return buf.toString();// 32位的加密 } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null; } }二次采样:
package com.bwie.dongchangqi.tinkertest; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import java.io.FileDescriptor; import java.io.InputStream; /** * Created by Administrator on 2018/1/19 0019. */ public class ImageResizer { private static final String TAG = "ImageResizer"; public static Bitmap compressBitmap(FileDescriptor fd, int targetWidth, int targetHeight) { Bitmap bitmap = null; if (targetWidth == 0 || targetHeight == 0) { bitmap = BitmapFactory.decodeFileDescriptor(fd); return bitmap; } BitmapFactory.Options options = new BitmapFactory.Options(); // 一开始的时候只加载图片的宽高信息 options.inJustDecodeBounds = true; // 加载图片,将宽高信息放到option里面 BitmapFactory.decodeFileDescriptor(fd, null, options); // 取出图片的原始宽高信息 int outWidth = options.outWidth; int outHeight = options.outHeight; // 对缩放比例进行计算 int inSampleSize = getResizerRate(outWidth, outHeight, targetWidth, targetHeight); // 设置缩放比例 options.inSampleSize = inSampleSize; // 加载图片的具体内容,不再只是加载宽高信息 options.inJustDecodeBounds = false; // 设置图片输出的色彩模式-RGB_565 options.inPreferredConfig = Bitmap.Config.RGB_565; // 对图片按我们计算出的比例进行加载 bitmap = BitmapFactory.decodeFileDescriptor(fd, null, options); return bitmap; } public static Bitmap compressBitmap(InputStream inputStream, int targetWidth, int targetHeight) { Bitmap bitmap = null; if (targetWidth == 0 || targetHeight == 0) { bitmap = BitmapFactory.decodeStream(inputStream); return bitmap; } BitmapFactory.Options options = new BitmapFactory.Options(); // 一开始的时候只加载图片的宽高信息 options.inJustDecodeBounds = true; // 加载图片,将宽高信息放到option里面 BitmapFactory.decodeStream(inputStream, null, options); // 取出图片的原始宽高信息 int outWidth = options.outWidth; int outHeight = options.outHeight; // 对缩放比例进行计算 int inSampleSize = getResizerRate(outWidth, outHeight, targetWidth, targetHeight); // 设置缩放比例 options.inSampleSize = inSampleSize; // 加载图片的具体内容,不再只是加载宽高信息 options.inJustDecodeBounds = false; // 设置图片输出的色彩模式-RGB_565 options.inPreferredConfig = Bitmap.Config.RGB_565; // 对图片按我们计算出的比例进行加载 bitmap = BitmapFactory.decodeStream(inputStream, null, options); return bitmap; } public static Bitmap compressBitmap(String filePath, int targetWidth, int targetHeight) { Bitmap bitmap = null; if (targetWidth == 0 || targetHeight == 0) { bitmap = BitmapFactory.decodeFile(filePath); return bitmap; } BitmapFactory.Options options = new BitmapFactory.Options(); // 一开始的时候只加载图片的宽高信息 options.inJustDecodeBounds = true; // 加载图片,将宽高信息放到option里面 BitmapFactory.decodeFile(filePath, options); // 取出图片的原始宽高信息 int outWidth = options.outWidth; int outHeight = options.outHeight; // 对缩放比例进行计算 int inSampleSize = getResizerRate(outWidth, outHeight, targetWidth, targetHeight); // 设置缩放比例 options.inSampleSize = inSampleSize; // 加载图片的具体内容,不再只是加载宽高信息 options.inJustDecodeBounds = false; // 设置图片输出的色彩模式-RGB_565 options.inPreferredConfig = Bitmap.Config.RGB_565; // 对图片按我们计算出的比例进行加载 bitmap = BitmapFactory.decodeFile(filePath, options); return bitmap; } /** * 计算图片的压缩比例 * * @return */ private static int getResizerRate(int outWidth, int outHeight, int targetWidth, int targetHeight) { // 谷歌官方推荐,压缩比例应该是2的指数次方 int inSampleSize = 1; // 只要我们的图片宽高还大于目标的宽高,就做除2操作,一直到满足我们的尺寸条件 while (targetWidth < outWidth / inSampleSize || targetHeight < outHeight / inSampleSize) { inSampleSize *= 2; } return inSampleSize; } }
LruCache类直接用本地文件吧,
ImageLoader三级缓存加载图片:
package com.bwie.dongchangqi.tinkertest; import android.content.Context; import android.graphics.Bitmap; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.support.v4.util.LruCache; import android.text.TextUtils; import android.util.Log; import android.widget.ImageView; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import okhttp3.Call; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; /** * Created by WuXirui * Create Time: 2018/1/4 * Description: */ public class ImageLoader { private static final String TAG = "ImageLoader"; // 当前app可用内存空间 private static int MAX_VALUABLE_MEMORY = (int) (Runtime.getRuntime().maxMemory() / 1024); // 当前可用内存的1/8作为内存缓存空间 private static int MAX_MEMORY_SIZE = MAX_VALUABLE_MEMORY / 8; // 磁盘缓存空间 private static int MAX_DISK_SIZE = 50 * 1024 * 1024; // 核心线程数 private static int CORE_THREAD_SIZE = 0; // 最大线程数 private static int MAX_THREAD_SIZE = Integer.MAX_VALUE; // 存活时间 private static long KEEPALIVE_TIME = 60L; // 磁盘缓存的索引 private static int FLAG_DISK_INDEX = 0; // 流的buffer值 private static int CACHE_BUFFER = 8 * 1024; private static final int MESSAGE_RECEIVE_RESULT = 0x123; private static volatile ImageLoader instance; private Context context; private LruCache<String, Bitmap> memoryCache; private DiskLruCache diskCache; // 磁盘缓存路径 private File cacheDic; // 加载的线程池 private static ThreadPoolExecutor threadPoolExecutor; static { threadPoolExecutor = new ThreadPoolExecutor(CORE_THREAD_SIZE, MAX_THREAD_SIZE, KEEPALIVE_TIME, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); } private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case MESSAGE_RECEIVE_RESULT: ResultLoader result = (ResultLoader) msg.obj; ImageView imageView = result.imageView; Bitmap bitmap = result.bitmap; // if (bitmap != null) { // imageView.setImageBitmap(bitmap); // } if (imageView.getTag().equals(result.url)) { if (bitmap != null) { imageView.setImageBitmap(bitmap); } } break; } } }; private ImageLoader(Context context) { this.context = context; Log.i(TAG, "ImageLoader: size=" + MAX_MEMORY_SIZE); memoryCache = new LruCache<String, Bitmap>(MAX_MEMORY_SIZE) { @Override protected int sizeOf(String key, Bitmap value) { return value.getRowBytes() * value.getHeight() / 1024; } }; cacheDic = getCacheDic(context); try { diskCache = DiskLruCache.open(cacheDic, 1, 1, MAX_DISK_SIZE); } catch (IOException e) { e.printStackTrace(); } } public static ImageLoader getInstance(Context context) { if (instance == null) { synchronized (ImageLoader.class) { if (null == instance) { instance = new ImageLoader(context); } } } return instance; } private File getCacheDic(Context context) { // 如果SD卡可用,就缓存在SD卡中 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { return context.getExternalCacheDir(); } else { // SD卡不可用,就存在机身存储中 return context.getCacheDir(); } } public void display(ImageView imageView, String url) { display(imageView, url, 0, 0); } public void display(final ImageView imageView, final String url, final int targetWidth, final int targetHeight) { // 防止图片错位,添加标识 imageView.setTag(url); // 判断当前内存中是否有这个缓存了 Bitmap bitmap = hasBitmapInMemory(url); if (bitmap != null) { Log.i(TAG, "内存缓存1"); imageView.setImageBitmap(bitmap); return; } // 内存缓存中没有这个缓存 Runnable runnable = new Runnable() { @Override public void run() { Log.i(TAG, "线程加载"); Bitmap bmp = loadBitmap(imageView, url, targetWidth, targetHeight); ResultLoader result = new ResultLoader(imageView, url, bmp); Message msg = handler.obtainMessage(); msg.what = MESSAGE_RECEIVE_RESULT; msg.obj = result; msg.sendToTarget(); } }; threadPoolExecutor.execute(runnable); } /** * 加载图片 * * @param url */ private Bitmap loadBitmap(ImageView imageView, String url, int targetWidth, int targetHeight) { // 再进行一次内存之中的判断 Bitmap bitmap = hasBitmapInMemory(url); if (bitmap != null) { Log.i(TAG, "内存缓存2"); return bitmap; } // 如果内存缓存中没有图片,就从磁盘缓存中读取 bitmap = getBitmapFromDisk(url, targetWidth, targetHeight); if (bitmap != null) { Log.i(TAG, "磁盘缓存"); return bitmap; } // 如果磁盘缓存中没有图片,就从网络获取 try { bitmap = getBitmapFromHttp(url, targetWidth, targetHeight); if (bitmap != null) { Log.i(TAG, "网络缓存"); return bitmap; } } catch (Exception e) { e.printStackTrace(); return null; } return null; } /** * 从网络中获取图片 * * @param url * @return */ private Bitmap getBitmapFromHttp(String url, int targetWidth, int targetHeight) throws Exception { // 下载图片完成之后保存到磁盘之中,然后从磁盘缓存中取 String uniqueKey = getUniqueKey(url); Log.i(TAG, "uniqueKey: " + uniqueKey); DiskLruCache.Editor edit = diskCache.edit(uniqueKey); OutputStream outputStream = edit.newOutputStream(FLAG_DISK_INDEX); if (downloadUrlToDiskCache(url, outputStream)) { diskCache.flush(); edit.commit(); Bitmap bitmap = getBitmapFromDisk(url, targetWidth, targetHeight); memoryCache.put(uniqueKey, bitmap); return bitmap; } else { return null; } } /** * 下载网络图片并保存到磁盘缓存的输出流 * * @param url * @param outputStream */ private boolean downloadUrlToDiskCache(String url, OutputStream outputStream) throws Exception { OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url(url) .get() .build(); Call call = client.newCall(request); Response response = call.execute(); InputStream inputStream = response.body().byteStream(); BufferedOutputStream bos = new BufferedOutputStream(outputStream); BufferedInputStream bis = new BufferedInputStream(inputStream); int length = 0; byte[] buffer = new byte[CACHE_BUFFER]; while ((length = bis.read(buffer, 0, buffer.length)) != -1) { bos.write(buffer, 0, length); } bos.flush(); bos.close(); bis.close(); inputStream.close(); outputStream.close(); return true; } /** * 从磁盘缓存中取数据 * * @param url * @return */ private Bitmap getBitmapFromDisk(String url, int targetWidth, int targetHeight) { String uniqueKey = getUniqueKey(url); Log.i(TAG, "getBitmapFromDisk: uniqueKey:" + uniqueKey); if (!TextUtils.isEmpty(uniqueKey)) { try { DiskLruCache.Snapshot snapshot = diskCache.get(uniqueKey); if (snapshot == null) { return null; } InputStream inputStream = snapshot.getInputStream(FLAG_DISK_INDEX); FileInputStream fis = (FileInputStream) snapshot.getInputStream(FLAG_DISK_INDEX); FileDescriptor fd = fis.getFD(); // Bitmap bitmap = BitmapFactory.decodeStream(inputStream); Bitmap bitmap = ImageResizer.compressBitmap(fd, targetWidth, targetHeight); if (bitmap == null) { Log.i(TAG, "bitmap is null "); } // 写入到内存缓存中 saveBitmapToMemoryCache(url, bitmap); return bitmap; } catch (IOException e) { e.printStackTrace(); return null; } } return null; } /** * 保存bitmap到内存缓存中 * * @param url * @param bitmap */ private void saveBitmapToMemoryCache(String url, Bitmap bitmap) { if (hasBitmapInMemory(url) == null && bitmap != null) { String uniqueKey = getUniqueKey(url); Log.i(TAG, "saveBitmapToMemoryCache: 11111"); memoryCache.put(uniqueKey, bitmap); Log.i(TAG, "saveBitmapToMemoryCache: " + memoryCache.get(uniqueKey)); } } /** * 查询内存缓存中是否有这个缓存 * * @param url * @return */ private Bitmap hasBitmapInMemory(String url) { String uniqueKey = getUniqueKey(url); if (!TextUtils.isEmpty(uniqueKey)) { return memoryCache.get(uniqueKey); } return null; } /** * 获取url的唯一标示 * * @param text * @return */ private String getUniqueKey(String text) { return Md5Utils.md5(text); } private static class ResultLoader { private ImageView imageView; private String url; private Bitmap bitmap; public ResultLoader(ImageView imageView, String url, Bitmap bitmap) { this.imageView = imageView; this.url = url; this.bitmap = bitmap; } } }