Bitmap三级缓存+二次采样+质量压缩

一. Bitmap三级缓存

为什么要用Bitmap三级缓存呢?

  1. 没有缓存的弊端:费流量,加载速度慢
  2. 加入缓存的优点:省流量,支持离线浏览

原理
在这里插入图片描述

  1. 首先我们需要设置SD卡权限和网络权限
	<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.INTERNET"/>
  1. 操作内存工具类:提供从内存中读写的方法,内存不能持久保存,可能过一会就会被回收掉
public class CacheUtils {
//  获取手机最大内存
    static long maxSize = Runtime.getRuntime().maxMemory();

//  实例化一个内存对象
    static LruCache<String, Bitmap> lruCache = new LruCache<String, Bitmap>((int)(maxSize/8)){
//      返回每个图片的大小
        @Override
        protected int sizeOf(String key, Bitmap value) {
            return value.getByteCount();
        }
    };

    public static void setBitmap(String key,Bitmap bitmap){
        lruCache.put(key,bitmap);
    }

    public static Bitmap getBitmap(String key){
        return lruCache.get(key);
    }
}
  1. 操作SD卡工具类:提供从SD卡中读写的方法
public class SDUtils {
//  将bitmap存储到SD卡中
    public static void setBitmap(String path, Bitmap bitmap){
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
            try {
                bitmap.compress(Bitmap.CompressFormat.JPEG,100,new FileOutputStream(path));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

//  根据路径获取bitmap对象
    public static Bitmap getBitmap(String path) {
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
             return BitmapFactory.decodeFile(path);
        }
        return null;
    }
}
  1. 网络下载工具类:提供下载图片的方法
public class NetUtlis {
//  通过网络获取bitmap对象
    public static Bitmap getBitmap(final String url) {
        Bitmap bitmap = null;
        try {
            bitmap = new MyTask().execute(url).get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bitmap;
    }

    static class MyTask extends AsyncTask<String,Integer,Bitmap> {

        @Override
        protected Bitmap doInBackground(String... strings) {
            try {
                URL url = new URL(strings[0]);
                HttpURLConnection http = (HttpURLConnection) url.openConnection();
                if (http.getResponseCode() == 200) {
                    InputStream is = http.getInputStream();
                    Bitmap bitmap = BitmapFactory.decodeStream(is);
                    return bitmap;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }
}

  1. 使用三个工具类完成Bitmap的三级缓存
//	获取图片按钮
 	button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
//              从内存获取
                Bitmap bitmap = CacheUtils.getBitmap("1703A");
                if (bitmap == null) {
//                  从SD卡获取
                    bitmap = SDUtils.getBitmap("/sdcard/Pictures/1703A.jpg");
                    if (bitmap == null) {
//                      从网络上获取
                        bitmap = NetUtlis.getBitmap("http://pic1.win4000.com/wallpaper/e/50d80458e1373.jpg");
                        if (bitmap == null) {
                            Toast.makeText(MainActivity.this, "没有网络", Toast.LENGTH_SHORT).show();
                        }else {
//                          将图片显示在ImageView上,并给SD卡以及内存中备份
                            imageView.setImageBitmap(bitmap);
                            SDUtils.setBitmap("/sdcard/Pictures/1703A.jpg",bitmap);
                            CacheUtils.setBitmap("1703A",bitmap);
                            Toast.makeText(MainActivity.this, "从网络上获取到的图片", Toast.LENGTH_SHORT).show();
                        }
                    }else {
//                      将图片显示在ImageView上,并给内存备份
                        imageView.setImageBitmap(bitmap);
                        CacheUtils.setBitmap("1703A",bitmap);
                        Toast.makeText(MainActivity.this, "从SD卡中获取到的图片", Toast.LENGTH_SHORT).show();
                    }
                }else {
//                  将图片显示在ImageView上
                    imageView.setImageBitmap(bitmap);
                    Toast.makeText(MainActivity.this, "从内存中获取到的图片", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

二. Bitmap二次采样

在这里插入图片描述
第一次:获得缩放比例 ,是2的幂次
第二次:根据缩放比例进行压缩

public class Main5Activity extends AppCompatActivity {
    Button bt;
    ImageView imageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        bt=findViewById(R.id.bt);
        imageView=findViewById(R.id.iv);
        bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //网络获取一张大图,进行二次采样之后再放到ImageView
                //https://cdn.duitang.com/uploads/item/201211/24/20121124230042_Bfhim.jpeg
                try {
                    Bitmap bitmap = new MyTask().execute("https://cdn.duitang.com/uploads/item/201211/24/20121124230042_Bfhim.jpeg").get();
                    imageView.setImageBitmap(bitmap);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }

            }
        });
    }
    class MyTask extends AsyncTask<String,Object,Bitmap>{

        @Override
        protected Bitmap doInBackground(String... strings) {
            try {
                URL url = new URL(strings[0]);
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                if(urlConnection.getResponseCode()==200){
                    InputStream inputStream = urlConnection.getInputStream();
                    //将inputStream流存储起来
                    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                    byte[] bytes = new byte[1024];
                    int len=0;
                    while((len=inputStream.read(bytes))!=-1){
                        byteArrayOutputStream.write(bytes,0,len);
                    }
                    //桶:网络的图片都放在数组里面了
                    byte[] data = byteArrayOutputStream.toByteArray();
                    //TODO 1:第一次采样:只采边框 计算压缩比例
                    BitmapFactory.Options options = new BitmapFactory.Options();
                    options.inJustDecodeBounds=true;//设置只采边框
                    BitmapFactory.decodeByteArray(data,0,data.length,options);//采样
                    int outWidth = options.outWidth;//获得原图的宽
                    int outHeight = options.outHeight;//获得原图的高
                    //计算缩放比例
                    int size=1;
                    while(outWidth/size>100||outHeight/size>100){
                        size*=2;
                    }
                    //TODO 2:第二次采样:按照比例才像素
                    options.inJustDecodeBounds=false;//设置只采边框为fasle
                    options.inSampleSize=size;//设置缩放比例
                    Bitmap bitmap=BitmapFactory.decodeByteArray(data,0,data.length,options);//采样
                    return  bitmap;
                }

            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

}

三. Bitmap质量压缩

方法介绍 Bitmap.compress(CompressFormat format, int quality, OutputStream stream)
参数一:Bitmap被压缩成的图片格式
参数二:压缩的质量控制,范围0~100
参数三:输出流

//	判断SD卡是否挂载
	if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
//			获得SD卡的根路径
            File file=Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
            File file1=new File(file,name);
            try {
                bitmap.compress(Bitmap.CompressFormat.JPEG,50,new FileOutputStream(file1));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值