Android图片内存优化-Android 8.0上通过HARDWARE模式加载图片

背景

Android上内存优化可以做的有很多,其中图片的内存优化往往是最先考虑的几个方面之一,主要源于图片的内存占用多。

分析

  1. 一张Bitmap的内存占用大小跟什么有关系?
    图片在内存中的大小的计算方式是:图片长(px) x 图片宽(px) x 单位像素占用的字节数
    Android中不同的图片格式,他的单位像素占用的字节数不同。
    图片格式总共有四种:
    Bitmap.Config = ALPHA_8 一个像素占1个字节
    Bitmap.Config = ARGB_4444 一个像素占2个字节
    Bitmap.Config = ARGB_8888 一个像素占4个字节(默认)
    Bitmap.Config = ARGB_565 一个像素占2个字节

项目中普遍使用的都是png图片,png图片是支持透明度的,而对于一些没有用到透明度的场景,这部分内存是一样会加载,造成额外的内存开销。
一张图片,去掉透明度的方式加载(8888换成565),内存占用降低一半。

  1. 图片的内存是否还可以有优化空间?
    通过对图片加载流程的梳理,了解到一般应用绘制图片,内存会在应用heap和GPU上都存一份,android 8.0上支持Hardware Bitmap,Hardware Bitmap对应的像素数据是存储在显存中,并对图片仅在屏幕上绘制的场景做了优化。简而言之,它把图片的内存只在GPU上存一份,而不需要应用本身的副本,这样的话,理论上通过Hardware方式加载一张图片,内存占用可以比原来少一半。
    Hardware详见:https://developer.android.com/reference/android/graphics/Bitmap.Config

验证方案

对于带有透明度的图片,统一通过Hardware方式加载。

如果是用Glide图片框架的,可以通过以下方式设置
RequestOptions options.set(Downsampler.ALLOW_HARDWARE_CONFIG, true);

Demo上测试通过普通方式和Hardware方式加载一张全屏的图片作为对比,

  1. 测试场景:
    加载图片后看主进程内存情况
  2. 测试方式:
    adb shell dumpsys meminfo xxx
  3. 测试数据:
  4. 测试结论:
    通过测试Demo数据展示,图片的内存在Native Heap中,Hardware方式加载相比8888加载内存确实少了大约一半。

注意事项

哪些情况不能使用HARDWARE?
在显存中存储像素数据意味着这些数据不容易访问到,在某些情况下可能会发生异常。已知的情形列举如下:
• 在 Java 中读写像素数据,包括:
• Bitmap#getPixel
• Bitmap#getPixels
• Bitmap#copyPixelsToBuffer
• Bitmap#copyPixelsFromBuffer
• 在本地 (native) 代码中读写像素数据
• 使用软件画布 (software Canvas) 渲染:
Canvas canvas = new Canvas(normalBitmap)
canvas.drawBitmap(hardwareBitmap, 0, 0, new Paint());
• 在绘制位图的 View 上使用软件层 (software layer type) (例如,绘制阴影)
ImageView imageView = …
imageView.setImageBitmap(hardwareBitmap);
imageView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

参考

  • 硬件位图

你可能感兴趣的:(Android图片内存优化-Android 8.0上通过HARDWARE模式加载图片)