Ⅰ 在android开发中加载的图片太大,有好几十兆,应该怎么办
如果图片太大会造成OOM内存溢出的错误,需要用Bitmap的压缩机制。
解决方案:
1.使用BitmapFactory.decodeStream替代createBitmap方法
原因是该方法直读取图片字节,调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap。
2.使用压缩读取技术
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imageSdUri, options);
final int height = options.outHeight;
final int width = options.outWidth;
options.inSampleSize = 1;
int w = 320;
int h = 480;
h = w*height/width;//计算出宽高等比率
int a = options.outWidth/ w;
int b = options.outHeight / h;
options.inSampleSize = Math.max(a, b);
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(imageSdUri, options);
3.及时释放Bitamp
Bitmap对象在不使用时,我们应该先调用recycle()释放内存,然后才它设置为null.虽然recycle()从源码上看,调用它应该能立即释放Bitmap的主要内存,但是测试结果显示它并没能立即释放内存。但是我它应该还是能大大的加速Bitmap的主要内存的释放。
Ⅱ Android 高效内存-图片内存使用优化
内容整理自网络。
在做内存优化的时候,我们发现除了解决内存泄露问题,剩下的就只有想办法减少真实的内存占用。而在App中,大部分内存可能被我们图片占用了,所以减少图片的内存占用可以带来直接的效果。本文就简单介绍一张图片到底占用多少内存,我们先假设我们有一张图片时** 600 * 800** 的,图片占用空间大小假设是** 100KB**。
图片内存大小跟占用空间大小有什么关系?
占用空间的大小不是图片占用内存的大小,一些初学者可能会误解一下。占用空间是在磁盘上占用的空间,内存大小是加载到内存中占用的内存大小。两个只是单位是一样的,本质不是一个概念。
一张图片到底占用多少内存呢?(ARGB_8888编码)
1. 图片占用内存的计算公式: 图片高度 * 图片宽度 * 一个像素占用的内存大小
2. 所以上面的图片占用内存是:**800 * 600 * 4 byte = 1875KB = 1.83M **
上面的计算公式中,为什么是4byte呢?文章后面有总结哦
图片所在目录对内存的影响?
在Android中,图片的存放目录和手机的屏幕密度影响图片最终的大小,举个例子:
假设我们的图片放到 xhdpi 目录下,那么我们本文中的图片占用的内存大小如下:
屏幕密度为2的设备:800 * 600 * 4byte = 1.83M
屏幕密度为3的设备:800 * 1.5 * 600 * 1.5 * 4byte = 1.83 * 2.25M =** 4.12M**
所以,计算图片占用内存大小的时候,要考虑图片所在的目录跟设备密度,这两个因素其实影响的是图片的高宽,android会对图片进行拉升跟压缩。
总结
1. 图片确实很占用内存,内存优化先考虑图片内存占用;
2. 一定要避免使用大图片,这就是.9图很有用的原因之一;
3. 图片的大小对内存的影响是正比关系;
4. 本文只是简单的告知读者怎么计算图片的内存大小。
大图: 440 * 336 小图: 220 * 168 资源目录: xhdpi
小图的高宽都是大图的1/2-->小图是原图的1/4
界面效果:
测试设备: Coolpad 8676-M01 5.1 density=2.0
测试前准备操作: 同一款设备,设置图片前后多次调用gc直到内存短时间内保持稳定不再变化
内存使用情况: 下图依次是 初始内存,大图内存,小图内存
大图占用内存: 11.23 MB - 10.66 MB = 0.57 MB
小图占用内存: 10.81 MB - 10.66 MB = 0.15 MB
大图小图内存关系: 0.15 MB * 4 = 0.60 MB 约等于 0.57 MB (这是统计工具的误差,理论上就是相等的)
同样的方式在另外一台设备小米4c上得到的结果如下:
测试设备: Xiaomi Mi-4c V8.2.1.0.LXKCNDL 5.1.1 density=3.0
大图占用内存: 13.22 MB - 11.95 MB = 1.27 MB
小图占用内存: 12.27 MB - 11.95 MB = 0.32 MB
大图小图内存关系: 0.32 MB * 4 = 1.28 MB 约等于 1.27 MB
结论: 由此可见大图比小图占用更多的内存,图片大小(分辨率)与占用内存成正比关系
备注: 图片在硬盘上占用的磁盘空间大小,与在内存中占用的内存大小完全不一样,不是一个概念,不要混淆
根据上文中图片大小与内存的关系,可以更加深刻的理解Android中.9图片的作用,它不但能减少apk的体积,还能减少图片占用内存。
有些时候我们根本不需要图片,而是自己绘制背景,可以在自定义View的onDraw中绘制背景,当然最方便的还是使用系统的Drawable,绘制部分交给系统去完成。
下面测试图片与Drawable的内存占用对比
原始图片大小: 482 * 482
界面效果:
测试设备: Xiaomi Mi-4c V8.2.1.0.LXKCNDL 5.1.1
测试前准备操作: 同一款设备,设置背景前后多次调用gc直到内存短时间内保持稳定不再变化
内存使用情况: 下图依次是 初始内存,使用图片占用的内存,使用Drawable占用的内存,使用onDraw绘制占用的内存
使用图片占用内存: 13.97 MB - 11.97 MB = 2.00 MB
使用Drawable占用内存: 11.97 MB - 11.97 MB = 0.00 MB (不会是0,有误差,只是很少)
使用onDraw绘制占用内存: 11.98 MB - 11.97 MB = 0.01 MB
结论: 绘制背景,或者使用系统提供Drawable作为背景,会大大减少内存占用
Drawable参考资料:
Drawable实战解析:Android XML shape 标签使用详解(apk瘦身,减少内存好帮手)
Android GradientDrawable(shape标签定义)静态使用和动态使用(圆角,渐变实现)
“让你的图片最小化”一节中描述的方法:使用尽可能小的图,使用.9,自己绘制背景或者使用Drawable来绘制背景
加载大图片时需要对图片进行压缩,使用等比例压缩方法直接在内存中处理图片
这样做要注意的是,图片质量会变差,inSampleSize设置的值越大,图片质量就越差。
有时候我们取得一张图片,也许只是为了获得这个图片的一些信息,比如图片的width、height等信息,不需要显示到界面上,这个时候我们可以不把图片加载到内存中。
由于Android外层是使用java,而底层使用的是C语言为图片对象分配的内存空间。所以我们的外部虽然看起来释放了,但里层却并不一定完全释放了,我们使用完图片后最好再释放掉里层的内存空间。
RGB(ARGB)
RGB色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。在Android中还有包含透明度Alpha的颜色模型,即ARGB。
YUV
YUV,分为三个分量,“Y”表示明亮度(Luminance或Luma),也就是灰度值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。
YUV的原理是把亮度与色度分离,研究证明,人眼对亮度的敏感超过色度。利用这个原理,可以把色度信息减少一点,人眼也无法查觉这一点。
主要用于电视系统以及模拟视频领域,它将亮度信息(Y)与色彩信息(UV)分离,没有UV信息一样可以显示完整的图像,只不过是黑白的,这样的设计很好地解决了彩色电视机与黑白电视的兼容问题
YUV的存储中与RGB格式最大不同在于,RGB格式每个点的数据是连继保存在一起的。即R,G,B是前后不间隔的保存在2-4byte空间中。而YUV的数据中为了节约空间,U,V分量空间会减小。每一个点的Y分量独立保存,但连续几个点的U,V分量是保存在一起的,(反正人眼一般也看不出区别).这几个点合起来称为macro-pixel, 这种存储格式称为Packed格式。另外一种存储格式是把一幅图像中Y,U,V分别用三个独立的数组表示。这种模式称为planar模式。
CMYK
CMYK也称作印刷色彩模式,顾名思义就是用来印刷的。印刷四分色模式是彩色印刷时采用的一种套色模式,利用色料的三原色混色原理,加上黑色油墨,共计四种颜色混合叠加,形成所谓“全彩印刷”。四种标准颜色是:
CMYK和RGB相比有一个很大的不同:RGB模式是一种发光的色彩模式,你在一间黑暗的房间内仍然可以看见屏幕上的内容;CMYK是一种依靠反光的色彩模式,我们是怎样阅读报纸的内容呢?是由阳光或灯光照射到报纸上,再反射到我们的眼中,才看到内容。它需要有外界光源,如果你在黑暗房间内是无法阅读报纸的。只要是在印刷品上看到的图像,就是CMYK模式表现的。比如期刊、杂志、报纸、宣传画等,都是印刷出来的,那么就是CMYK模式的了。
CMYK原色与叠加之后的颜色对比
在不考虑透明度的情况下,一个像素点的颜色值在计算机中的表示方法有以下3种:
在Java中,float类型的变量占32位,int类型的变量占32位,short和char类型的变量都在16位,因此可以看出,用浮点数表示法编码一个像素的颜色,内存占用量是96位即12字节;而用24位整数表示法编码,只要一个int类型变量,占用4个字节(高8位空着,低24位用于表示颜色);用16位整数表示法编码,只要一个short类型变量,占2个字节;因此可以看出采用整数表示法编码颜色值,可以大大节省内存,当然,颜色质量也会相对低一些。在Android中获取Bitmap的时候一般也采用整型编码。
回想一下Android的BitmapConfig类中,有ARGB_8888、ARGB_4444、RGB565等常量,现在可以知道它们分别代表了什么含义。同时也可以计算一张图片在内存中可能占用的大小,比如采用ARGB_8888编码载入一张1920 1200的图片,大概就会占用1920 1200*4/1024/1024=8.79MB的内存。
采用低内存占用量的编码方式,比如Bitmap.Config.ARGB_4444比Bitmap.Config.ARGB_8888更省内存;
1920 1200的图片:*
ARGB_8888:1920 1200 4/1024/1024=8.79MB
ARGB_4444,RGB565:1920 1200 2/1024/1024=4.39MB
在Android中,对图片的使用一定要关注,大多数情况下,占用内存多,OOM发生都是因为图片资源使用不当。不要盲目加一个大图到Android项目中,能使用.9进来使用,而且.9图本身尽可能小,另外能使用绘制实现就不要加一个图片资源。有些时候,在不影响用户体验的情况下,可以降低图片素材质量,比如不需要透明度的就不要了,有些透明度用肉眼看不出来。
Ⅲ android oom是什么意思
Android oom 有时出现很频繁,这一般不是Android设计的问题,一般是我们的问题。
就我的经验而言,出现oom,无非主要是以下几个方面:
一、加载对象过大
二、相应资源过多,没有来不及释放。
解决这样的问题,也有一下几个方面:
一:在内存引用上做些处理,常用的有软引用、强化引用、弱引用
二:在内存中加载图片时直接在内存中做处理,如:边界压缩.
三:动态回收内存
四:优化Dalvik虚拟机的堆内存分配
五:自定义堆内存大小
Ⅳ 图片压缩的三种方式
1、等比压缩,等比压缩是保持原图长宽比例的压缩,只是图片变小,展示的还是原图的所有内容(区别于第二种通过Matrix压缩,可以选取图片的一部分,类似于上传头像时,让你在图上选一块zoom的形式)。等比压缩用的的主要是BitmapFactory.Options,通过options缩放比例的设置,来生成缩略图:
2、通过Matrix进行更加灵活的缩放:这种方式主要是通过构建缩放矩阵和Bitmap.createBitmap方法来实现灵活缩放,宽和高缩放的比例可以不一致,而且通过Bitmap.createBitmap方法创建出来的是新的位图,这个位图可以是选取原图的一部分,而不是对原图进行整体缩放!类似于上传头像时,让你在原图上扣下来一块的效果,控制非常灵活。
3、无损压缩,无损压缩是说图片大小和清晰度看上去和原图没有什么差别,但是确实size缩小了,这里缩小的原理是牺牲了分辨率等其他直观看不到的东西,看起来和原图一样,但是一放大就立马失真了,不会和原图一样放大很多才会逐渐变得不清晰。无损压缩后的图片像素并不会减少,而Bitmap占用内存的定义就是像素点占的内存,所以以Bitmap的方式加载到内存中时,和压缩前占用的内存是同样大的,原来会oom的图片,质量压缩后同样会oom;但是,质量压缩后将流输出到文件中,文件的size会大幅度减小,所以质量压缩特别适合在 Android 端进行图片上传的时候进行图片压缩,既能保持上传后的清晰度,又能减小size。另外质量压缩不是可以无限缩小的,降低到一定程度,就算把quality设置的再小,size也不会再降低了。另外这种方式最好返回保存压缩后的图片保存的文件路径,而不要直接返回Bitmap,示例就懒得改了。
一张图片处理过程,建议先进行等比压缩或者Matrix压缩后,再进行质量压缩,这样组合使用,不管是生成缩略图还是图片上传,效果都不错
Ⅳ Android黑科技,图片终极压缩
一、支持自定义配置、不失真和批量处理
二、图片上传为什么要压缩
1、图片服务器空间限制,磁盘昂贵
2、网络不稳定,大文件需要断点续传
3、尽可能避免安卓OOM异常
4、后台约定的规则<200KB
5、需要上传原图的应用有医院临床项目、金融银行
三、图片压缩流程
1、递归每张图片
2、设置图片格式 Bitmap.CompressFormat.JPG
png, jpg,webp
3、质量压缩bitmap.compress(format,quality,baos)
由于png是无损压缩,所以设置quality无效(不适合作为缩略图)
采样率压缩BitmapFactory.Options.inSampleSize
缩小图片分辨率,减少所占用磁盘空间和内存大小
缩放压缩canvas.drawBitmap(bitmap, null,rectF,null)
减少图片的像素,降低所占用磁盘空间大小和内存大小,可用于缓存缩略图
JNI调用JPEG库
Android的图片引擎使用的是阉割版的skia引擎,去掉了图片压缩中的哈夫曼算法
4、像素修复
5、返回压缩
6、完成压缩
demo: https://github.com/ApeCold/Learn_Compress_Sample
参考:
Luban框架 https://github.com/Curzibn/Luban
缺点
1、当没有设定压缩路径时,抛异常无闪退
2、源码中,压缩比率固定值60,无法修改
3、压缩配置,参数不太适应真实项目需求
4、不能指定压缩大小,比如100KB以内
https://github.com/zettsu/Compressor
Ⅵ android图片压缩避免OOM
简单吹下牛:很多app都会要加载图片,但是如果不压缩图片就很容易OOM,
个人看来OOM 出现原因总的来说分为两种:
一种是内存溢出(好像在扯淡,OOM本身就是内存溢出)
另一种是:图片过大,一个屏幕显示不完全造成,似乎也是一。。 如有错误纯属扯淡;
为了避免上面的情况:加载图片的时候可以进行压缩,上传的时候要可以进行压缩,在图片不可见的时候进行回收(onDetach()),再吹一句 用了fresco+压缩之后加载图片完全没问题了。
一、质量压缩方法:
privateBitmap compressImage(Bitmap image) {
ByteArrayOutputStream baos =newByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG,100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
intoptions =100;
while( baos.toByteArray().length /1024>100) {//循环判断如果压缩后图片是否大于100kb,大于继续压缩
baos.reset();//重置baos即清空baos
image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中
options -=10;//每次都减少10
}
ByteArrayInputStream isBm =newByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
Bitmap bitmap = BitmapFactory.decodeStream(isBm,null,null);//把ByteArrayInputStream数据生成图片
returnbitmap;
}
二、图片按比例大小压缩方法(根据Bitmap图片压缩)
privateBitmap comp(Bitmap image) {
ByteArrayOutputStream baos =newByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG,100, baos);
if( baos.toByteArray().length /1024>1024) {//判断如果图片大于1M,进行压缩避免在生成图片(BitmapFactory.decodeStream)时溢出
baos.reset();//重置baos即清空baos
image.compress(Bitmap.CompressFormat.JPEG,50, baos);//这里压缩50%,把压缩后的数据存放到baos中
}
ByteArrayInputStream isBm =newByteArrayInputStream(baos.toByteArray());
BitmapFactory.Options newOpts =newBitmapFactory.Options();
//开始读入图片,此时把options.inJustDecodeBounds 设回true了
newOpts.inJustDecodeBounds =true;
Bitmap bitmap = BitmapFactory.decodeStream(isBm,null, newOpts);
newOpts.inJustDecodeBounds =false;
intw = newOpts.outWidth;
inth = newOpts.outHeight;
//现在主流手机比较多是800*480分辨率,所以高和宽我们设置为
floathh = 800f;//这里设置高度为800f
floatww = 480f;//这里设置宽度为480f
//缩放比。由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
intbe =1;//be=1表示不缩放
if(w > h && w > ww) {//如果宽度大的话根据宽度固定大小缩放
be = (int) (newOpts.outWidth / ww);
}elseif(w < h && h > hh) {//如果高度高的话根据宽度固定大小缩放
be = (int) (newOpts.outHeight / hh);
}
if(be <=0)
be =1;
newOpts.inSampleSize = be;//设置缩放比例
//重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
isBm =newByteArrayInputStream(baos.toByteArray());
bitmap = BitmapFactory.decodeStream(isBm,null, newOpts);
returncompressImage(bitmap);//压缩好比例大小后再进行质量压缩
}
Ⅶ 图片压缩那些事
我们在项目开发过程中,可能或多或少的都会有对图片操作,而且一般情况在app当中涉及到内存泄露、或者apk体积增大等方面,绝大部分原因就是图片的问题,要么图片体积比较大、或者一次加载图片比较多等等,所以个人觉得,只要想对app瘦身、减小app体积、避免内存泄露等等这些问题,同时,为了避免OOM内存泄露,几乎所有的app都会对大图片进行压缩的,这点是毋庸置疑的,所以说只要把图片处理好,可以说就已经解决了绝大部分的问题,那么这篇文章就来针对图片压缩的原因、常见图片压缩方法做一个简单的总结。
文件和流的形式对图片体积大小没影响,也就是说,如果手机SD卡上的是100k,以流的形式读到内存中也是100k,如果图片以Bitmap形式存在,内存会瞬间增大;
文件形式:file.length()
流的形式:将图片文件读到 内存输入流中,看它的byte数;
Bitmap:bitmap.getByteCount()
如果图片是要上传的,那么 几M大小肯定不行,所以就必须得压缩;
如果图片要显示在android 设备上,ImageView最终是要加载bitmap对象的,所以就要考虑单个 Bitmap对象占用多少内存;
bitmap内存大小 = 图片长度 * 图片宽度 * 单位像素占用字节数
bitmap常见有2种编码方式,ARGB_8888、RGB——565,前者每个像素点是4byte(字节),后者是2个byte(字节),ARGB_8888比较常用。
1080 * 1920 * 4 = 7.9M
保持原图长宽比例的压缩,只是图片变小,展示的还是原图的所有内容,用的是BitmapFactory.Options,通过options设置缩放比例,生成缩略图;
inSimpleSize(采样率):
优点:效率较高,解析速度快;
缺点:inSimpleSize取值只能是 2的次方数,不能精确指定图片大小;
宽高缩放比例可以不一致,通过Bitmap.createBitmap()方法创建出新的位图,这个位图可以选取图片一部分,而不是整体压缩,类似于QQ上传头像,让你在图片上选择任何一块 zoom的形式,控制非常灵活;
意思就是图片大小、清晰度和原图看上去没什么区别,但是大小缩小了,缩小原理就是牺牲了分辨率等其他直观看不到的东西,看上去和原图一样,但是放大立马失真,不像原图只有放大后才会不清晰
Ⅷ 说说在 Android 中如何压缩图片
目前存在两种压缩图片方式:
而图片有三种存在形式:
bigmap 在内存中的大小是按像素计算的,也就是width * height,所以如果需要在 Android 中显示照片,那么就必须进行按比例压缩,避免因为内存消耗过大,导致 APP 退出。
是不是很简单呀 O(∩_∩)O哈哈~
Ⅸ Android图片压缩-大小与质量压缩以及图片保存
一、前言:
2.质量压缩
注意:
第二次压缩之前都要先清空 baos.reset(); 再进行压缩 image.compress(Bitmap.CompressFormat.JPEG, quality, baos);
有时候我们采用质量压缩没有效果,有可能是每次压缩的质量过小,所以我们可以尝试修改压缩质量(quality)是10;
quality压缩机提示,0-100。0表示压缩
小尺寸,100意味着最大质量的压缩。一些
格式,如无损的PNG,将忽略质量设定;
3.混合方式压缩
链接: https://www.jianshu.com/p/12835d5ebc72