Android图片优化问题总结
2015-12-05 14:11
423 查看
众所周知,android端开发 图片问题一直都是比较重视的
图片处理好不好直接关系到内存和性能的好坏
本人也在查阅相关的资料,根据自己的理解做的总结 不足 错误之处还请大家留言改正.....
图片性能之三级缓存篇
1. 什么是图片的三级缓存?
图片的三级缓存主要是指在内存,文件和网络
2.三级缓存的具体实现
大家都知道图片要是从网络获取的话不仅速度慢,消耗流量多,用户体验不好
所以我们通常采用的方法就是分别从内存中,假如内存中不存在 此时就要从本地缓存文件中查询(自定义目录)
当本地文件不存在的时候我们才考虑去网络上加载图片
从网络上获取图片之后再把图片缓存到本地再由本地到内存 最后在展现在用户的面前
总体流程就是
代码如下:
(暂时没时间写代码以后再补)
图片之性能优化篇
图片的优化其实就是内存的优化 处理不好就会引来OOM异常甚至程序崩溃
android中加载图片是个很浪费内存的事情,因此我查询了很多的方法,一下列举几种比较常用的
1.图片的缩放
1).BitmapFactory和BitmapFactory.Options。
首先从服务器获取到图片,我们可以获取到图片的宽高信息,再获取当前手机的宽和高可以通过
根据图片和手机屏幕的宽高比进行缩放
2).使用Bitmap加Matrix来缩放
2.图片的config设置
图片的内存大小除了跟大小有关系还跟材质有关系
可以通过设置config属性来改变图片的大小,达到减少内存的目的
3.图片的强引用,软引用,弱引用,虚引用(Strong
Reference,SoftReference,WeakReference,PhantomReference)(Android3.0以后不支持)
首先将一下这四种引用的区别
强引用(Strong Reference):
强引用是我们编写代码最常见的引用了,比如String a="",简单说强引用就是你不把他置为空,android系统内存不足的时候,系统也不会主动的回收该内存(打死也不回收)
软引用(Soft Reference)
软引用是即使对象没置为空,一旦android系统检测到内存不足的时候,就会把你干掉(不足就干掉)
弱引用(WeakReference)
弱引用就是一旦存储的强引用被删除,该弱引用的对象也将被回收(要死一起死)
虚引用(PhantomReference)
虚引用就是用完一次就回收(一次性筷子)
当然现在android就算使用软引用也没什么效果,在3.0后android推出了LruCache类专门用来缓存图片
4.当然就是你自己的代码规范问题
图片对象用完要及时置为空,可以采用分批加载图片和一次不要加载太多图片到内存,
图片之压缩篇
相信很多小伙伴都会遇到将图片上传到服务器,或者保存到本地,然而图片太大,上传流量消耗大,上传慢
占用空间大,该怎么解决呢? 自然要涉及到图片的压缩 注明:此篇是参照别的博客所写
1.图片存在的几种形式
1).文件形式(即以二进制形式存在于硬盘上)
2).流的形式(即以二进制形式存在于内存中)
3).Bitmap形式
这三种形式的区别: 文件形式和流的形式对图片体积大小并没有影响,也就是说,如果你手机SD卡上的如果是100K,那么通过流的形式读到内存中,也一定是占100K的内存,注意是流的形式,不是Bitmap的形式,当图片以Bitmap的形式存在时,其占用的内存会瞬间变大,
我试过500K文件形式的图片加载到内存,以Bitmap形式存在时,占用内存将近10M,当然这个增大的倍数并不是固定的
检测图片三种形式大小的方法:
文件形式: file.length()
流的形式: 讲图片文件读到内存输入流中,看它的byte数
Bitmap: bitmap.getByteCount()
特点是: File形式的图片确实被压缩了, 但是当你重新读取压缩后的file为 Bitmap是,它占用的内存并没有改变
[java] view
plaincopy
public static void compressBmpToFile(Bitmap bmp,File file){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int options = 80;//个人喜欢从80开始,
bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
while (baos.toByteArray().length / 1024 > 100) {
baos.reset();
options -= 10;
bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
}
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write(baos.toByteArray());
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
方法说明: 该方法是压缩图片的质量, 注意它不会减少图片的像素,比方说, 你的图片是300K的, 1280*700像素的, 经过该方法压缩后, File形式的图片是在100以下, 以方便上传服务器, 但是你BitmapFactory.decodeFile到内存中,变成Bitmap时,它的像素仍然是1280*700, 计算图片像素的方法是 bitmap.getWidth()和bitmap.getHeight(),
图片是由像素组成的, 每个像素又包含什么呢? 熟悉PS的人知道, 图片是有色相,明度和饱和度构成的.
该方法的官方文档也解释说, 它会让图片重新构造, 但是有可能图像的位深(即色深)和每个像素的透明度会变化,JPEG onlysupports opaque(不透明), 也就是说以jpeg格式压缩后, 原来图片中透明的元素将消失.所以这种格式很可能造成失真
既然它是改变了图片的显示质量, 达到了对File形式的图片进行压缩, 图片的像素没有改变的话, 那重新读取经过压缩的file为Bitmap时, 它占用的内存并不会少.(不相信的可以试试)
因为: bitmap.getByteCount() 是计算它的像素所占用的内存, 请看官方解释: Returns the number of bytes used to store
this bitmap's pixels.
2. 将图片从本地读到内存时,进行压缩 ,即图片从File形式变为Bitmap形式
特点: 通过设置采样率, 减少图片的像素, 达到对内存中的Bitmap进行压缩
先看一个方法: 该方法是对内存中的Bitmap进行质量上的压缩, 由上面的理论可以得出该方法是无效的, 而且也是没有必要的,因为你已经将它读到内存中了,再压缩多此一举,
尽管在获取系统相册图片时,某些手机会直接返回一个Bitmap,但是这种情况下, 返回的Bitmap都是经过压缩的, 它不可能直接返回一个原声的Bitmap形式的图片, 后果可想而知
[java] view
plaincopy
private Bitmap compressBmpFromBmp(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int options = 100;
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
while (baos.toByteArray().length / 1024 > 100) {
baos.reset();
options -= 10;
image.compress(Bitmap.CompressFormat.JPEG, options, baos);
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
return bitmap;
}
再看一个方法:
[java] view
plaincopy
private Bitmap compressImageFromFile(String srcPath) {
BitmapFactory.Options newOpts = new BitmapFactory.Options();
newOpts.inJustDecodeBounds = true;//只读边,不读内容
Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
newOpts.inJustDecodeBounds = false;
int w = newOpts.outWidth;
int h = newOpts.outHeight;
float hh = 800f;//
float ww = 480f;//
int be = 1;
if (w > h && w > ww) {
be = (int) (newOpts.outWidth / ww);
} else if (w < h && h > hh) {
be = (int) (newOpts.outHeight / hh);
}
if (be <= 0)
be = 1;
newOpts.inSampleSize = be;//设置采样率
newOpts.inPreferredConfig = Config.ARGB_8888;//该模式是默认的,可不设
newOpts.inPurgeable = true;// 同时设置才会有效
newOpts.inInputShareable = true;//。当系统内存不够时候图片自动被回收
bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
// return compressBmpFromBmp(bitmap);//原来的方法调用了这个方法企图进行二次压缩
//其实是无效的,大家尽管尝试
return bitmap;
}
方法说明: 该方法就是对Bitmap形式的图片进行压缩, 也就是通过设置采样率, 减少Bitmap的像素, 从而减少了它所占用的内存
图片处理好不好直接关系到内存和性能的好坏
本人也在查阅相关的资料,根据自己的理解做的总结 不足 错误之处还请大家留言改正.....
图片性能之三级缓存篇
1. 什么是图片的三级缓存?
图片的三级缓存主要是指在内存,文件和网络
2.三级缓存的具体实现
大家都知道图片要是从网络获取的话不仅速度慢,消耗流量多,用户体验不好
所以我们通常采用的方法就是分别从内存中,假如内存中不存在 此时就要从本地缓存文件中查询(自定义目录)
当本地文件不存在的时候我们才考虑去网络上加载图片
从网络上获取图片之后再把图片缓存到本地再由本地到内存 最后在展现在用户的面前
总体流程就是
代码如下:
(暂时没时间写代码以后再补)
图片之性能优化篇
图片的优化其实就是内存的优化 处理不好就会引来OOM异常甚至程序崩溃
android中加载图片是个很浪费内存的事情,因此我查询了很多的方法,一下列举几种比较常用的
1.图片的缩放
1).BitmapFactory和BitmapFactory.Options。
首先从服务器获取到图片,我们可以获取到图片的宽高信息,再获取当前手机的宽和高可以通过
<span style="white-space:pre"> <span style="font-size:12px;"> </span></span><span style="font-size:18px;">int screenWidth = 0; int screenHeight = 0; Display display = getWindowManager().getDefaultDisplay(); screenWidth = display.getWidth(); screenHeight = display.getHeight();</span>
根据图片和手机屏幕的宽高比进行缩放
</pre><p><pre name="code" class="java"> <span style="font-size:18px;"> <span style="white-space:pre"> </span>Options opts=new BitmapFactory.Options(); opts.inSampleSize=(图片的宽度/屏幕的宽度+图片的高度/屏幕的高度)/2; BitmapFactory.decodeFile("图片路径", opts);</span>
2).使用Bitmap加Matrix来缩放
<span style="white-space:pre"> </span>/* 设置图片缩小的比例 */ double scale=0.8; /* 计算出这次要缩小的比例 */ scaleWidth=(float) (scaleWidth*scale); scaleHeight=(float) (scaleHeight*scale); /* 产生reSize后的Bitmap对象 */ Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); Bitmap resizeBmp = Bitmap.createBitmap(bmp,0,0,bmpWidth, bmpHeight,matrix,true);
2.图片的config设置
图片的内存大小除了跟大小有关系还跟材质有关系
可以通过设置config属性来改变图片的大小,达到减少内存的目的
opts.inPreferredConfig=Bitmap.Config.ALPHA_8; opts.inPreferredConfig=Bitmap.Config.ARGB_4444; opts.inPreferredConfig=Bitmap.Config.ARGB_8888; opts.inPreferredConfig=Bitmap.Config.RGB_565;
3.图片的强引用,软引用,弱引用,虚引用(Strong
Reference,SoftReference,WeakReference,PhantomReference)(Android3.0以后不支持)
首先将一下这四种引用的区别
强引用(Strong Reference):
强引用是我们编写代码最常见的引用了,比如String a="",简单说强引用就是你不把他置为空,android系统内存不足的时候,系统也不会主动的回收该内存(打死也不回收)
软引用(Soft Reference)
软引用是即使对象没置为空,一旦android系统检测到内存不足的时候,就会把你干掉(不足就干掉)
弱引用(WeakReference)
弱引用就是一旦存储的强引用被删除,该弱引用的对象也将被回收(要死一起死)
虚引用(PhantomReference)
虚引用就是用完一次就回收(一次性筷子)
当然现在android就算使用软引用也没什么效果,在3.0后android推出了LruCache类专门用来缓存图片
4.当然就是你自己的代码规范问题
图片对象用完要及时置为空,可以采用分批加载图片和一次不要加载太多图片到内存,
图片之压缩篇
相信很多小伙伴都会遇到将图片上传到服务器,或者保存到本地,然而图片太大,上传流量消耗大,上传慢
占用空间大,该怎么解决呢? 自然要涉及到图片的压缩 注明:此篇是参照别的博客所写
1.图片存在的几种形式
1).文件形式(即以二进制形式存在于硬盘上)
2).流的形式(即以二进制形式存在于内存中)
3).Bitmap形式
这三种形式的区别: 文件形式和流的形式对图片体积大小并没有影响,也就是说,如果你手机SD卡上的如果是100K,那么通过流的形式读到内存中,也一定是占100K的内存,注意是流的形式,不是Bitmap的形式,当图片以Bitmap的形式存在时,其占用的内存会瞬间变大,
我试过500K文件形式的图片加载到内存,以Bitmap形式存在时,占用内存将近10M,当然这个增大的倍数并不是固定的
检测图片三种形式大小的方法:
文件形式: file.length()
流的形式: 讲图片文件读到内存输入流中,看它的byte数
Bitmap: bitmap.getByteCount()
二.常见的压缩方式
1. 将图片保存到本地时进行压缩, 即将图片从Bitmap形式变为File形式时进行压缩,特点是: File形式的图片确实被压缩了, 但是当你重新读取压缩后的file为 Bitmap是,它占用的内存并没有改变
[java] view
plaincopy
public static void compressBmpToFile(Bitmap bmp,File file){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int options = 80;//个人喜欢从80开始,
bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
while (baos.toByteArray().length / 1024 > 100) {
baos.reset();
options -= 10;
bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
}
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write(baos.toByteArray());
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
方法说明: 该方法是压缩图片的质量, 注意它不会减少图片的像素,比方说, 你的图片是300K的, 1280*700像素的, 经过该方法压缩后, File形式的图片是在100以下, 以方便上传服务器, 但是你BitmapFactory.decodeFile到内存中,变成Bitmap时,它的像素仍然是1280*700, 计算图片像素的方法是 bitmap.getWidth()和bitmap.getHeight(),
图片是由像素组成的, 每个像素又包含什么呢? 熟悉PS的人知道, 图片是有色相,明度和饱和度构成的.
该方法的官方文档也解释说, 它会让图片重新构造, 但是有可能图像的位深(即色深)和每个像素的透明度会变化,JPEG onlysupports opaque(不透明), 也就是说以jpeg格式压缩后, 原来图片中透明的元素将消失.所以这种格式很可能造成失真
既然它是改变了图片的显示质量, 达到了对File形式的图片进行压缩, 图片的像素没有改变的话, 那重新读取经过压缩的file为Bitmap时, 它占用的内存并不会少.(不相信的可以试试)
因为: bitmap.getByteCount() 是计算它的像素所占用的内存, 请看官方解释: Returns the number of bytes used to store
this bitmap's pixels.
2. 将图片从本地读到内存时,进行压缩 ,即图片从File形式变为Bitmap形式
特点: 通过设置采样率, 减少图片的像素, 达到对内存中的Bitmap进行压缩
先看一个方法: 该方法是对内存中的Bitmap进行质量上的压缩, 由上面的理论可以得出该方法是无效的, 而且也是没有必要的,因为你已经将它读到内存中了,再压缩多此一举,
尽管在获取系统相册图片时,某些手机会直接返回一个Bitmap,但是这种情况下, 返回的Bitmap都是经过压缩的, 它不可能直接返回一个原声的Bitmap形式的图片, 后果可想而知
[java] view
plaincopy
private Bitmap compressBmpFromBmp(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int options = 100;
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
while (baos.toByteArray().length / 1024 > 100) {
baos.reset();
options -= 10;
image.compress(Bitmap.CompressFormat.JPEG, options, baos);
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
return bitmap;
}
再看一个方法:
[java] view
plaincopy
private Bitmap compressImageFromFile(String srcPath) {
BitmapFactory.Options newOpts = new BitmapFactory.Options();
newOpts.inJustDecodeBounds = true;//只读边,不读内容
Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
newOpts.inJustDecodeBounds = false;
int w = newOpts.outWidth;
int h = newOpts.outHeight;
float hh = 800f;//
float ww = 480f;//
int be = 1;
if (w > h && w > ww) {
be = (int) (newOpts.outWidth / ww);
} else if (w < h && h > hh) {
be = (int) (newOpts.outHeight / hh);
}
if (be <= 0)
be = 1;
newOpts.inSampleSize = be;//设置采样率
newOpts.inPreferredConfig = Config.ARGB_8888;//该模式是默认的,可不设
newOpts.inPurgeable = true;// 同时设置才会有效
newOpts.inInputShareable = true;//。当系统内存不够时候图片自动被回收
bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
// return compressBmpFromBmp(bitmap);//原来的方法调用了这个方法企图进行二次压缩
//其实是无效的,大家尽管尝试
return bitmap;
}
方法说明: 该方法就是对Bitmap形式的图片进行压缩, 也就是通过设置采样率, 减少Bitmap的像素, 从而减少了它所占用的内存
相关文章推荐
- 百度地图使用注意事项
- Android 实现广告Banner循环轮播
- Android 实现广告Banner循环轮播
- Android自定义View的实现总结
- Android中使用HorizontalScrollView横向滑动布局
- Android之如何使用junit
- android camera系统3A模式及其状态转换(二)
- android camera系统3A模式及其状态转换(一)
- android .9文件的一点处理
- Android动画大总结
- android项目apk打包及反编译
- 上百个Android开源项目分享
- Android 中的 Service 三种启动方式
- android camera HAL v3.0中元数据及其控制
- android项目双击或者多击的实现
- android 蓝牙4.2.2分析研究
- Android 中的 Service 全面总结
- Android Service与Activity之间通信的几种方式
- ListView异步加载图片,完美实现图文混排
- Android群英传-拼图游戏puzzle-代码设计和实现