android--图片的简单处理

  这里讲图片的简单处理,主要是讲图片的压缩缓存

  图片压缩:
为什么需要进行图片压缩?
大图片的加载会导致内存溢出,出现OOM问题。
图片压缩的实现思路:二次采样
1、首先将图片的边框下载下来,获得图片原始的宽和高
2、然后计算出压缩比例
3、最后重新加载图片,通过压缩比例对图片进行压缩
核心代码:
/**
     * 将输入流转化为字节数组
     *
     * @param inputStream
     * @return
     * @throws IOException
     */
    public static byte[] streamToByteArray(InputStream inputStream) throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, len);
        }
        outputStream.flush();
        //关掉资源
        inputStream.close();
        //返回字节数组
        return outputStream.toByteArray();
    }

    /**
     * 压缩图片
     *
     * @param data       图片的字节数组
     * @param destWidth  目标的宽度
     * @param destHeight 目标的高度
     * @return 压缩后的图片
     */
    public static Bitmap zipBitmap(byte[] data, int destWidth, int destHeight) {
        //创建图片参数
        BitmapFactory.Options options = new BitmapFactory.Options();
        //设置只加载边框
        options.inJustDecodeBounds = true;
        //第一次采样,加载图片的边框
        BitmapFactory.decodeByteArray(data, 0, data.length, options);
        //获得原始图片的高和宽、
        int width = options.outWidth;
        int height = options.outHeight;
        //计算压缩比例
        int sampleSize = 1;
        while (width / sampleSize > destWidth || height / sampleSize > destHeight) {
            sampleSize *= 2;
        }
        //重新设置参数,加载边框
        options.inJustDecodeBounds = false;
        //压缩比例
        options.inSampleSize = sampleSize;
        //图片格式
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
        //第二次采样,获得压缩后的图片
        Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
        return bitmap;
    }
缓存分类:
1、一级缓存,内存
存取速度快、空间比较小、数据在断电或程序退出后会丢失
App运行时使用该缓存
2、二级缓存,磁盘
存取速度稍慢、空间比较大、数据可以长期保留
App关闭后,下次再使用时可以使用该缓存
一级缓存,内存:
LruCache类:
在内存中实现Lru缓存,以键值对方法存取数据。
用法:
new LruCache(缓存大小)
put(K,V) 保存到缓存中
V get(K) 获得缓存中的数据
核心代码:
    public static final int MAX_SIZE = 10 * 1024 * 1024;

    //一级缓存
    private static LruCache mMemoryCache= new LruCache<>(MAX_SIZE);;
 /**
     * md5加密方法
     * @param url
     * @return
     */
    public static String md5(String url) {
        try {
            //获得md5算法对象
            MessageDigest digest = MessageDigest.getInstance("md5");
            //进行md5加密
            byte[] digest1 = digest.digest(url.getBytes());
            //将加密后的字节转化为16进制的字符串
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < digest1.length; i++) {
                sb.append(Integer.toHexString(digest1[i]));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将图片保存到一级缓冲中
     *
     * @param url
     * @param bitmap
     */
    public static void saveToMemory(String url, Bitmap bitmap) {
        String md5 = md5(url);
        mMemoryCache.put(md5, bitmap);
    }

    /**
     * 从一级缓冲中读取图片
     *
     * @param url
     * @return
     */
    public static Bitmap getFromMemory(String url) {
        return mMemoryCache.get(md5(url));
    }
二级缓存 DiskLruCache类:
第三方库,在磁盘上实现Lru缓存。
导入方法:
compile 'com.jakewharton:disklrucache:2.0.2'
创建方法:
DiskLruCache DiskLruCache.open(File 缓存目录,int 程序版本,int 值的数量,int 缓存大小);
添加权限:
核心代码:
    //二级缓存
    private static DiskLruCache mDiskCacheDiskLruCache.open(getCacheDir(context), getVersionCode(context), 1, MAX_SIZE * 5);

    /**
     * 获得磁盘缓存目录
     *
     * @param context
     * @return
     */
    public static File getCacheDir(Context context) {
        //判断SDcard是否存在
        if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState()) {
            //返回SDcard缓存目录
            return context.getExternalCacheDir();
        }
        //返回当前应用程序的缓存目录
        return context.getCacheDir();
    }

    /**
     * 获得程序版本号
     *
     * @param context
     * @return
     */
    public static int getVersionCode(Context context) {
        int code = 0;
        try {
            code = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return code;
    }

    /**
     * 保存到二级缓存中
     *
     * @param url
     * @param bitmap
     */
    public static void saveToDisk(String url, Bitmap bitmap) {
        try {
            //获得Editor对象
            DiskLruCache.Editor editor = mDiskCache.edit(md5(url));
            //获得输出流
            OutputStream outputStream = editor.newOutputStream(0);
            //将图片保存到流中
            boolean compress = bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
            //判断是否保存成功
            if (compress) {
                //提交保存
                editor.commit();
            } else {
                //退出保存
                editor.abort();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 从二级缓存中读取图片
     *
     * @param url
     * @return
     */
    public static Bitmap readFromDisk(String url) {
        try {
            //获得图片的快照
            DiskLruCache.Snapshot snapshot = mDiskCache.get(md5(url));
            if (snapshot != null) {
                //获得输入流
                InputStream inputStream = snapshot.getInputStream(0);
                //将流转化为图片
                return BitmapFactory.decodeStream(inputStream);
            }
        } catch (Exception e) {

        }
        return null;
    }
实现二级缓存的流程:
1、首先从一级缓存中读取图片,如果找到图片就进行显示
2、如果一级缓存没有,再从二级缓存读取,如果找到图片就进行显示,并将图片保存到一级缓存
3、如果二级缓存没有,就从网络读取,读取图片后,将图片保存到一级和二级缓存中
完整代码,我是写在一个异步任务中:
package com.example.doimageview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Environment;
import android.renderscript.ScriptGroup;
import android.util.Log;
import android.util.LruCache;

import com.jakewharton.disklrucache.DiskLruCache;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * Created by Lenovo on 2017/5/8.
 */

public class LoadImageView {

    public interface OnLoadImageVIewListener {
        void OnLoadIageView(Bitmap bitmap);
    }

    private OnLoadImageVIewListener mListener;

    public void showImageView(String url, int width, int height, OnLoadImageVIewListener listener) {
        this.mListener = listener;
        new MyTask(width, height).execute(url);
    }

    public void showImageView(String url, OnLoadImageVIewListener listener) {
        this.mListener = listener;
        new MyTask().execute(url);
    }

    class MyTask extends AsyncTask {
        //压缩的目标宽度和高度
        private int mWidth;
        private int mHeight;

        public MyTask() {
        }

        public MyTask(int mWidth, int mHeight) {
            this.mHeight = mHeight;
            this.mWidth = mWidth;
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            try {
                //首先从一级缓存中 读取图片
                Bitmap bitmap = getFromMemory(params[0]);
                //如果一级缓存中没有该图片就从二级缓存中读取
                if (bitmap == null) {
                    bitmap = readFromDisk(params[0]);
                    //如果二级缓存中没有该图片就从网络中读取
                    if (bitmap == null) {
                        //得到URL
                        URL url = new URL(params[0]);
                        //获得连接
                        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                        //得到输入流
                        InputStream inputStream = conn.getInputStream();
                        //得到图片
                        if (mWidth == 0 || mHeight == 0) {
                            //不用压缩图片,把输入流转化为图片
                            bitmap = BitmapFactory.decodeStream(inputStream);
                        } else {
                            //压缩图片
                            bitmap = zipBitmap(streamToByteArray(inputStream), mWidth, mHeight);
                        }
                        //关闭流
                        inputStream.close();
                        //从网络加载图片后保存到一级缓存和二级缓存中
                        saveToMemory(params[0], bitmap);
                        saveToDisk(params[0],bitmap);
                    }else{
                        //如果二级缓存不为空,就保存到一级缓存中
                        saveToMemory(params[0],bitmap);
                    }
                }
                //如果不为空,就直接返回图片
                return bitmap;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            if (mListener != null) {
                mListener.OnLoadIageView(bitmap);
            }
        }
    }

    /**
     * 将输入流转化为字节数组
     *
     * @param inputStream
     * @return
     * @throws IOException
     */
    public static byte[] streamToByteArray(InputStream inputStream) throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, len);
        }
        outputStream.flush();
        //关掉资源
        inputStream.close();
        //返回字节数组
        return outputStream.toByteArray();
    }

    /**
     * 压缩图片
     *
     * @param data       图片的字节数组
     * @param destWidth  目标的宽度
     * @param destHeight 目标的高度
     * @return 压缩后的图片
     */
    public static Bitmap zipBitmap(byte[] data, int destWidth, int destHeight) {
        //创建图片参数
        BitmapFactory.Options options = new BitmapFactory.Options();
        //设置只加载边框
        options.inJustDecodeBounds = true;
        //第一次采样,加载图片的边框
        BitmapFactory.decodeByteArray(data, 0, data.length, options);
        //获得原始图片的高和宽、
        int width = options.outWidth;
        int height = options.outHeight;
        //计算压缩比例
        int sampleSize = 1;
        while (width / sampleSize > destWidth || height / sampleSize > destHeight) {
            sampleSize *= 2;
        }
        //重新设置参数,加载边框
        options.inJustDecodeBounds = false;
        //压缩比例
        options.inSampleSize = sampleSize;
        //图片格式
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
        //第二次采样,获得压缩后的图片
        Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
        return bitmap;
    }

    public static final int MAX_SIZE = 10 * 1024 * 1024;

    //一级缓存
    private static LruCache mMemoryCache;
    //二级缓存
    private static DiskLruCache mDiskCache;

    /**
     * 初始化缓存
     *
     * @param context
     */
    public static void initCache(Context context) {
        mMemoryCache = new LruCache<>(MAX_SIZE);
        try {
            mDiskCache = DiskLruCache.open(getCacheDir(context), getVersionCode(context), 1, MAX_SIZE * 5);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获得磁盘缓存目录
     *
     * @param context
     * @return
     */
    public static File getCacheDir(Context context) {
        //判断SDcard是否存在
        if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState()) {
            //返回SDcard缓存目录
            return context.getExternalCacheDir();
        }
        //返回当前应用程序的缓存目录
        return context.getCacheDir();
    }

    /**
     * 获得程序版本号
     *
     * @param context
     * @return
     */
    public static int getVersionCode(Context context) {
        int code = 0;
        try {
            code = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return code;
    }

    /**
     * 保存到二级缓存中
     *
     * @param url
     * @param bitmap
     */
    public static void saveToDisk(String url, Bitmap bitmap) {
        try {
            //获得Editor对象
            DiskLruCache.Editor editor = mDiskCache.edit(md5(url));
            //获得输出流
            OutputStream outputStream = editor.newOutputStream(0);
            //将图片保存到流中
            boolean compress = bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
            //判断是否保存成功
            if (compress) {
                //提交保存
                editor.commit();
            } else {
                //退出保存
                editor.abort();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 从二级缓存中读取图片
     *
     * @param url
     * @return
     */
    public static Bitmap readFromDisk(String url) {
        try {
            //获得图片的快照
            DiskLruCache.Snapshot snapshot = mDiskCache.get(md5(url));
            if (snapshot != null) {
                //获得输入流
                InputStream inputStream = snapshot.getInputStream(0);
                //将流转化为图片
                return BitmapFactory.decodeStream(inputStream);
            }
        } catch (Exception e) {

        }
        return null;
    }


        /**
         * md5加密方法
         * @param url
         * @return
         */
        public static String md5(String url) {
            try {
                //获得md5算法对象
                MessageDigest digest = MessageDigest.getInstance("md5");
                //进行md5加密
                byte[] digest1 = digest.digest(url.getBytes());
                //将加密后的字节转化为16进制的字符串
                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < digest1.length; i++) {
                    sb.append(Integer.toHexString(digest1[i]));
                }
                return sb.toString();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            return null;
        }

        /**
         * 将图片保存到一级缓冲中
         *
         * @param url
         * @param bitmap
         */
        public static void saveToMemory(String url, Bitmap bitmap) {
            String md5 = md5(url);
            mMemoryCache.put(md5, bitmap);
        }

        /**
         * 从一级缓冲中读取图片
         *
         * @param url
         * @return
         */
        public static Bitmap getFromMemory(String url) {
            return mMemoryCache.get(md5(url));
        }
}













你可能感兴趣的:(android)