Bitmap三级缓存+二次采样

Bitmap三级缓存

一.为什么使用Bitmap三级缓存?

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

二.原理

在这里插入图片描述
思路:
1.从内存获取图片,如果存在,则显示;如果不存在,则从SD卡中获取图片
2.从SD卡中获取图片,如果文件中存在,显示,并且添加到内存中,否则开启网络下载图片

三.代码

(1).添加读写SD卡的权限和网络权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>

(2)操作内存工具类:提供从内存中读写的方法,内存不能持久保存,可能过一会就会被回收掉

 //Lrucache存储工具类
public class LruUtils {
    //TODO 1:实例化LruCache对象
    private LruCache<String,Bitmap> lruCache;
    private long max=Runtime.getRuntime().maxMemory();//获得手机的最大内存
    public LruUtils(){
        lruCache=new LruCache<String,Bitmap>((int)max/8){//给内存大小,一般是最大内存的1/8
            //重写该方法返回每个对象的大小
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return value.getByteCount();
            }
        };
    }
    //TODO 2:读图片
    public Bitmap getBitmap(String key){
        return lruCache.get(key);
    }
    //TODO 3:存图片
    public  void setBitmap(String key,Bitmap bitmap){
        lruCache.put(key,bitmap);
    }
}

(3).操作SD卡工具类:提供从SD卡中读写的方法

//TODO 读图片和写图片
public class SDUtils {
    //TODO 1:存图片:bitmap.compress()
    public static void setBitmap(String name,Bitmap bitmap){
        //获取路径存储图片
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
            File file=Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
            File file1=new File(file,name);
            //存储图片:bitmap对象---->SD卡
            try {
                //参数一 图片的格式 参数二 图片质量 0-100  参数三:输出流
                bitmap.compress(Bitmap.CompressFormat.JPEG,100,new FileOutputStream(file1));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
    //TODO 2:读图片:BitmapFactory.decodeFile()
    public static Bitmap getBitmap(String name){
        //获取路径存储图片
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
            File file=Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
            File file1=new File(file,name);
            //读取图片:SD卡-----Bitmap
            return BitmapFactory.decodeFile(file1.getAbsolutePath());
	}
        return null;
    }
}

(3).网络下载工具类:提供下载图片的方法

//网络获取工具类
public class NetUtils {
    //TODO 获取网络图片
    public static Bitmap getBitmap(String url) throws ExecutionException, InterruptedException {
         return new MyTask().execute(url).get();//get方法获取执行完毕返回的结果Bitmap对象
    }
    static class MyTask extends AsyncTask<String,String,Bitmap>{
        @Override
        protected Bitmap doInBackground(String... strings) {
            String imageUrl = strings[0];
            HttpURLConnection conn = null;
            try {
                URL url = new URL(imageUrl);
                conn = (HttpURLConnection) url.openConnection(); // 打开连接
                conn.setReadTimeout(5000); // 设置读取超时时间
                conn.setConnectTimeout(5000); // 设置连接超时时间
                conn.setRequestMethod("GET"); // 设置请求方式
                if (conn.getResponseCode() == 200) {
                    InputStream is = conn.getInputStream(); // 获取流数据
                    Bitmap bitmap = BitmapFactory.decodeStream(is); // 将流数据转成Bitmap对象
                    return bitmap;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (conn != null) {
                    conn.disconnect(); // 断开连接
                }
            }
            return null;
        }
    }
}

(4).使用三个工具类完成Bitmap的三级缓存

 /*
一。三级缓存
1.运行内存:LruUtils(创建实例,存,读)
2.文件SD
3.网络请求
* */
public class MainActivity extends AppCompatActivity {
    private ImageView imageView;
    private  LruUtils lruUtils= new LruUtils();//TODO 注意:同一个内存对象
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView=findViewById(R.id.image);
    }
    public void click(View view) throws ExecutionException, InterruptedException {
        //TODO 1:先从运行内存中读取
        Bitmap bitmap=lruUtils.getBitmap("宋定行");
        if(bitmap!=null){//有图片
            imageView.setImageBitmap(bitmap);
            Toast.makeText(this, "图片来自内存", Toast.LENGTH_SHORT).show();
        }else{
            //TODO 2:若内存没有去SD卡
            bitmap=SDUtils.getBitmap("宋定行.jpg");
            if(bitmap!=null){
                imageView.setImageBitmap(bitmap);
                Toast.makeText(this, "图片从SD卡来de", Toast.LENGTH_SHORT).show();
                //向内存中存储一下
                lruUtils.setBitmap("宋定行",bitmap);
            }else{
                //TODO 3:运行内存和SD卡都没有图片,接下来网络获取
                bitmap=NetUtils.getBitmap("http://upload.cbg.cn/2015/1126/1448506973451.jpg");
                if(bitmap!=null){
                    imageView.setImageBitmap(bitmap);
                    Toast.makeText(this, "图片从网络获取", Toast.LENGTH_SHORT).show();
                    //将图片再放到SD卡和内存中
                    SDUtils.setBitmap("宋定行.jpg",bitmap);
                    lruUtils.setBitmap("宋定行",bitmap);
                }else{
                    Toast.makeText(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的质量压缩

1.方法介绍

Bitmap.compress(CompressFormat format, int quality, OutputStream stream)

参数一:Bitmap被压缩成的图片格式

参数二:压缩的质量控制,范围0~100

参数三:输出流

2.案例:将一张Bitmap图片采用50%质量压缩到SD卡中

//判断SD卡是否挂载
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
  //获得SD卡的跟路径
            File file=Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
            File file1=new File(file,name);
            //存储图片:bitmap对象---->SD卡
            try {
                //参数一 图片的格式 参数二 图片质量 0-100  参数三:输出流
                bitmap.compress(Bitmap.CompressFormat.JPEG,50,new FileOutputStream(file1));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
      }

猜你喜欢

转载自blog.csdn.net/TimPika/article/details/92591078