文章目录
- 1、oom以及图片优化概念
- 1-1、什么是oom?
- 1-2、图片oom问题产生
- 1-3、图片占用内存计算
- 1-3-1、尺寸压缩
- 1-3-2、质量压缩
- 1-4、bitmap的内存管理
- 2、优化实操代码
- 2-1、原图加载
- 2-2、使用采样率InSampleSize优化
- 2-3、使用inBitmap复用内存
- 3、内存占用和drawable文件夹的关系
- 3-1、mipmap文件夹
- 3-2、分辨率和dpi
- 3-3、图片匹配问题
- 3-4、内存占用和drawable文件夹的关系
- 4、常见图片加载优化
1、oom以及图片优化概念
1-1、什么是oom?
android系统的进程(app级别)有最大内存限制,超过这个限制系统就会抛出oom错误。
1-2、图片oom问题产生
- 一个页面一次性加载过多的图片
- 加载大图片没有进行压缩(尺寸压缩和质量压缩)
- android列表加载大量bitmap没有使用缓存
1-3、图片占用内存计算
1-3-1、尺寸压缩
- inJustDecodeBounds=true 在不加载图片的情况下获取到图片的宽高
- inSampleSize 图片的压缩采样率,压缩比
- 改变imageview的大小 ,不会改变图片的内存大小。
1-3-2、质量压缩
- 常见的png、jeg、webp等格式的图片在设置到ui上之前需要经过解码过程。
- 使用rgb-565替代argb-8888可以降低图片的占用内存,rgb565一个像素占用2个字节,argb-8888一个像素占用4个字节。
- inBitmap实现复用
1-4、bitmap的内存管理
- 在android3.0之前,对于像素数据的支持保存在内存中,所以使用完之后要手动调用recycle回收释放。
- 从android3.0开始,像素数据和位图数据都存贮在dalvik堆中,垃圾处理器会自动回收。
2、优化实操代码
所有操作以加载一个高清壁纸big.jpg为实例,图片防止在sd卡根目录下,6.0以上使用到的权限处理知识,请自行处理。
2-1、原图加载
String sdcard = Environment.getExternalStorageDirectory().getAbsolutePath();
String file = sdcard + "/big.jpg";
Bitmap bitmap = BitmapFactory.decodeFile(file);
tvImageInfo.setText("宽:" + bitmap.getWidth() + "高:" + bitmap.getHeight() + "大小:" + bitmap.getByteCount());
ivImageView.setImageBitmap(bitmap);
2-2、使用采样率InSampleSize优化
String sdcard = Environment.getExternalStorageDirectory().getAbsolutePath();
String file = sdcard + "/big.jpg";
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file, options);
int width = options.outWidth;
options.inSampleSize = width / 200;
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(file, options);
tvImageInfo.setText("宽:" + bitmap.getWidth() + "高:" + bitmap.getHeight() + "大小:" + bitmap.getByteCount());
ivImageView.setImageBitmap(bitmap);
注意比较原图和处理过的图片,可以发现,图片的大小明显变化了。
2-3、使用inBitmap复用内存
BitmapFactory.Options options = new BitmapFactory.Options();
options.inBitmap = 已经存在的bitmap对象
3、内存占用和drawable文件夹的关系
3-1、mipmap文件夹
起初mipmap文件夹刚处理的时候,当时还和同事一起讨论过图标应该放在drawable还是mipmap中,后来查阅资料得到,谷歌建议是将启动图片防止在mipmap中,其他的图片仍然放在drawable文件夹中。
3-2、分辨率和dpi
对于图片适配问题,在最早的时候,是使用每个类型的dpi下各放置一套图片,这样的话,使得apk包很大。当然这种方式目前已经很少见到,现在的方法,大部分都是提供一套最大的图片dpi,来适配全部。android的sdk会根据屏幕尺寸选择对应的资源文件进行渲染,如果sdk检测手机的分辨率为320dpi,系统会优先到xxhdpi文件夹中查找,如果找不到,系统也会去其他文件夹下查找,找到之后系统会自动缩放图片展示到屏幕上。
3-3、图片匹配问题
如果是480hdpi的手机,图片的查找规则如下
首先会查找与手机dpi相对应的文件夹,如果没有找到,则向上查找,没有找到则查找nodpi,如果也没有找到,则又向下查找。
3-4、内存占用和drawable文件夹的关系
同一张图片,放置在不同的目录下,会生成大小不同的bitmap。
APP在查找图片资源的时候遵循先高后低的原则,假设设备的分辨率是xxhdpi,那么查找顺序如下
- 先去drawable-xxhdpi文件夹查找,如果有这张图片就使用,这个时候图片不会缩放
- 如果没有找到,则去更高密度的文件夹下找,例如drawable-xxxhdpi,密度依次递增,如果找到了,图片将会缩小,因为系统认为这些图片都是给高分辨率设备使用的
- 所有高密度文件夹都没有的话,就会去drawable-nodpi文件夹去找,如果有也不会缩放
- 还是没有的话,就会去更低密度的文件夹下面找,xhdpi,hdpi等,密度依次递减,如果找到了,图片将会放大,因为系统认为这个图片是给低分辨率设备使用的
而drawable文件夹默认的dpi为160(等同于mdpi),所以图片将会放大,导致内存增高
4、常见图片加载优化