一. Bitmap三级缓存
为什么要用Bitmap三级缓存呢?
- 没有缓存的弊端:费流量,加载速度慢
- 加入缓存的优点:省流量,支持离线浏览
原理
- 首先我们需要设置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"/>
- 操作内存工具类:提供从内存中读写的方法,内存不能持久保存,可能过一会就会被回收掉
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);
}
}
- 操作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;
}
}
- 网络下载工具类:提供下载图片的方法
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;
}
}
}
- 使用三个工具类完成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();
}
}