利用BitmapFactory.Options实现图片内存优化

通过设置options.inPreferredConfig控制内存占用

首先准备了一张1280x800的blue_bg.png图片,我们知道这张图片加载到内存默认占用的大小是1280x800x4 = 4096000byte

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.blue_bg);

// 默认情况下 BitmapFactory 使用 Bitmap.Config.ARGB_8888 的存储方式来加载图片内容,而在这种存储模式下,每一个像素需要占用 4 个字节

// 1280x800x4 = 4096000 byte 核算大约4000kb = 4M

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

Log.d("zyl--","bitmap = " + bitmap.getAllocationByteCount() +", ="+bitmap.getByteCount());

}

我们知道可以通过设置options.inPreferredConfig,来设置图片加载时候占用的字节ALPHA_8(1byte),RGB_565(2),ARGB_4444(2),ARGB_8888(4)。

BitmapFactory.Options options = new BitmapFactory.Options();

options.inPreferredConfig = Bitmap.Config.RGB_565;

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.blue_bg,options);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

Log.d("zyl--","bitmap = " + bitmap.getAllocationByteCount() +", ="+bitmap.getByteCount());

}

经过日志分析,发现并没有生效,占用的内存并没有减少一半。大概的原因是

设备加载图片时候,不同android版本对图片编解码的支持不一样

图片的格式也决定了他不能支持通过Bitmap.Config.RGB_565模式去加载,所以会选择默认ARGB_8888模式去加载,所以我们的内存占用并没有减少。

这篇文章会有详细的介绍:文章链接

通过设置不同的inPreferredConfig值真的能减少Bitmap加载时占用的内存么?链接

我们增加一张one.jpg图片做对比,具体代码如下:

BitmapFactory.Options options = new BitmapFactory.Options();

options.inPreferredConfig = Bitmap.Config.RGB_565;

// options.inSampleSize = 2;

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.blue_bg,options);

// 默认情况下 BitmapFactory 使用 Bitmap.Config.ARGB_8888 的存储方式来加载图片内容,而在这种存储模式下,每一个像素需要占用 4 个字节

// 1280x800x4 = 4096000 byte 核算大约4000kb = 4M

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

Log.d("zyl--","bitmap = " + bitmap.getAllocationByteCount() +", ="+bitmap.getByteCount());

}

Bitmap one = BitmapFactory.decodeResource(getResources(), R.drawable.one,options);

// 默认情况下 BitmapFactory 使用 Bitmap.Config.ARGB_8888 的存储方式来加载图片内容,而在这种存储模式下,每一个像素需要占用 4 个字节

// 1280x800x4 = 4096000 byte 核算大约4000kb = 4M

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

Log.d("zyl--","one = " + one.getAllocationByteCount() +", ="+one.getByteCount());

}

通过日志我们发现,jpg图片对于设置inPreferredConfig属性生效了,内存占用减少了一半。进一步证实了图片格式对于inPreferredConfig属性是否生效有一定影响。

通过设置采样率options.inSampleSize来减少图片内存占用

通过设置采样率options.inSampleSize来减少图片内存占用问题。inSampleSize 参数,可以实现 Bitmap 采样压缩,这个参数的含义是宽高维度上每隔 inSampleSize 个像素进行一次采集。

BitmapFactory.Options options = new BitmapFactory.Options();

// options.inPreferredConfig = Bitmap.Config.RGB_565;

options.inSampleSize = 2;

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.blue_bg,options);

// 默认情况下 BitmapFactory 使用 Bitmap.Config.ARGB_8888 的存储方式来加载图片内容,而在这种存储模式下,每一个像素需要占用 4 个字节

// 1280x800x4 = 4096000 byte 核算大约4000kb = 4M

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

Log.d("zyl--","bitmap = " + bitmap.getAllocationByteCount() +", ="+bitmap.getByteCount());

}

通过日志分析,得到当采样率为2的时候,图片占用内存为

: bitmap = 1024000,

内存减少了1/4。

通过设置 Options.inBitmap,使Bitmap 对象重复使用,节省内存

实现点击切换图片的功能,代码如下:

public class MainActivity extends AppCompatActivity {

private int resIndex;

int[] resIds = {R.drawable.one, R.drawable.two};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

TextView hello = findViewById(R.id.hello);

final ImageView iv = findViewById(R.id.iv);

hello.setOnClickListener(new View.OnClickListener() {

@RequiresApi(api = Build.VERSION_CODES.KITKAT)

@Override

public void onClick(View v) {

iv.setImageBitmap(getBitmap());

}

});

reuseBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.one);

}

@RequiresApi(api = Build.VERSION_CODES.KITKAT)

private Bitmap getBitmap() {

return BitmapFactory.decodeResource(getResources(), resIds[resIndex++ % 2], options);

}

以上代码运行后,发现当我们切换图片时,内存情况如图:

内存抖动

每次切换图片都需要通过 BitmapFactory 创建一个新的 Bitmap 对象。当方法执行完毕后,这个 Bitmap 又会被 GC 回收,这就造成不断地创建和销毁比较大的内存对象,从而导致频繁 GC(或者叫内存抖动)。像 Android App 这种面相最终用户交互的产品,如果因为频繁的 GC 造成 UI 界面卡顿,还是会影响到用户体验的。可以在 Android Studio Profiler 中查看内存情况。

使用Options.inBitmap,重复利用已经占用内存的 Bitmap 空间,解决内存抖动问题。

public class MainActivity extends AppCompatActivity {

private int resIndex;

int[] resIds = {R.drawable.one, R.drawable.two};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

TextView hello = findViewById(R.id.hello);

final ImageView iv = findViewById(R.id.iv);

hello.setOnClickListener(new View.OnClickListener() {

@RequiresApi(api = Build.VERSION_CODES.KITKAT)

@Override

public void onClick(View v) {

// Intent intent = new Intent(MainActivity.this,MyActivity.class);

// startActivity(intent);

iv.setImageBitmap(getBitmap());

}

});

BitmapFactory.Options options = new BitmapFactory.Options();

//设置为true,使这块内存能够复用

options.inMutable =true;

reuseBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.one,options);

}

/**

* 重用bitmap

*/

private Bitmap reuseBitmap;

@RequiresApi(api = Build.VERSION_CODES.KITKAT)

private Bitmap getBitmap() {

BitmapFactory.Options options = new BitmapFactory.Options();

options.inSampleSize = 1;

//为true 只解析bitmap的占用内存大小,不加载bitmap到内存中

options.inJustDecodeBounds = true;

BitmapFactory.decodeResource(getResources(), resIds[resIndex % 2], options);

if (canUseForInBitmap(reuseBitmap, options)) {

options.inMutable = true;

options.inBitmap = reuseBitmap;

}

//恢复设置

options.inJustDecodeBounds = false;

return BitmapFactory.decodeResource(getResources(), resIds[resIndex++ % 2], options);

}

static boolean canUseForInBitmap(

Bitmap candidate, BitmapFactory.Options targetOptions) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

// From Android 4.4 (KitKat) onward we can re-use if the byte size of

// the new bitmap is smaller than the reusable bitmap candidate

// allocation byte count.

int width = targetOptions.outWidth / targetOptions.inSampleSize;

int height = targetOptions.outHeight / targetOptions.inSampleSize;

int byteCount = width * height * getBytesPerPixel(candidate.getConfig());

return byteCount <= candidate.getAllocationByteCount();

}

// On earlier versions, the dimensions must match exactly and the inSampleSize must be 1

return candidate.getWidth() == targetOptions.outWidth

&& candidate.getHeight() == targetOptions.outHeight

&& targetOptions.inSampleSize == 1;

}

/**

* A helper function to return the byte usage per pixel of a bitmap based on its configuration.

*/

static int getBytesPerPixel(Bitmap.Config config) {

if (config == Bitmap.Config.ARGB_8888) {

return 4;

} else if (config == Bitmap.Config.RGB_565) {

return 2;

} else if (config == Bitmap.Config.ARGB_4444) {

return 2;

} else if (config == Bitmap.Config.ALPHA_8) {

return 1;

}

return 1;

}

}

运行后发现内存抖动的问题解决了:

内存图

android加载大量图片内存优化,Android图片加载内存优化相关推荐

  1. Android踩坑日记:使用Fesco图片加载库在GridView上的卡顿优化

    1,fresco是一个强大的图片加载库 2,fresco设计了一个叫做image pipeline(图片管道)的模块,它负责从从网络,从本地文件系统,从本地资源加载图片,为了最大限度节约资源和cpu时 ...

  2. ios 图片加载内存尺寸_iOS内存分析上-图片加载内存分析

    简介 对于大多数App来说,内存占用主要就是图片.本文将从实用的角度分析,iOS图片的内存占用.测量.优化等. iOS内存-有什么影响 在移动操作系统设备中,是不能像PC一样进行内存swap的,而随着 ...

  3. WEEX-EEUI 卡顿优化(图片加载)

    前言 前两天前端的小伙伴告诉我,他写的页面再android手机上特别的卡,崩溃了很多次.这让我紧张了起来,已经用weex-eeui做过一个项目了,之前还没发现这个问题.因为问题不好定位,让我想起了之前 ...

  4. web资源优化之图片加载的时机

    前言 图片资源是WEB项目中很重要的组成部分,也是交互设计中一个很重要的体现,往往一张图能胜过千言万语,所谓"一图胜白言"就是这个道理.然后大量的图片也会给服务器带来很大的压力,据 ...

  5. html加载时页面闪烁白色背景,解决页面加载闪白问题-背景图片加载优化

    页面加载闪白 今天遇到一个问题,写了一个使用深色背景图的网页,发现访问/刷新时,会出现短暂的闪白现象. 之前使用浅色背景时没有发现过这个问题,搜索半天也没有找到特别直白有效的回答. 找到的几个答案,有 ...

  6. ios 加载大量图片崩溃_iOS超高分辨率图片崩溃解决方法

    本文为CocoaChina网友xxg90s投稿 前言: ID作为一款以IM为基础的办公软件,在用户使用过程中,经常会遇到一些超大的或者超高分辨率的图片(以下统一称:大图).基于SDWebImage为基 ...

  7. 如何给图片加水印?这三个图片加水印方法,帮你添加花式水印

    大家有没有这样情况,自己好不容易做好的作品发布到网络平台上结果被他人盗用了,很让人气愤,那我们应该如何避免这种情况呢? 其实我们可以给自己的作品加上一些专属的个性化水印,那小伙伴们知道图片加水印怎么操 ...

  8. java 图片加水印不失真_java实现图片加水印效果

    图片加水印代码,这些代码不常用,但是用到的时候需要注意的地方也挺多的,每次都重写比较麻烦,记下来备忘.代码是图片加水印的一般流程,可根据实际项目需要自行修改. 注:代码在JPG和PNG格式图片下测试通 ...

  9. 如何给图片加水印?分享怎么给图片加水印的方法

    当我们在平台上发布自己精心拍摄的照片,或分享自己总结的知识点时,难免会遇到一些人盗用自己图片的情况.这时候,我们就会给图片添加上水印,从而来防止自己的图片被盗,那要怎么给图片加水印呢?别着急,今天我就 ...

  10. html给图片加个框,PS怎么给图片加边框 几个步骤搞定

    给自己的的照片弄个精美的边框是非常常见的操作,那么在制作电子相册的过程中,如何用PS来给你的照片加一个好看的边框呢,其实不难,下面就来说一下操作方法,有兴趣的朋友来参考学习下吧. 类别:图像处理    ...

最新文章

  1. uva 101 The Blocks Problem
  2. 目标检测--边界框(bounding box)解析
  3. linux-安装jdk
  4. tomcat日志按天切分
  5. Android NDK工程创建与编译运行
  6. 【包邮送书活动】20210924期-开奖通知
  7. JAVA中自己写的util中的chop,Java StringUtils.chop方法代碼示例
  8. 通过WiFi控制智能小车机器人制作过程详解
  9. (37)FPGA原语设计(BUFR)
  10. mysql 设置默认值_为什么 Flink 无法实时写入 MySQL?
  11. QT 设置QDialog显示与隐藏系统按钮(最大小化等)
  12. 基模高斯光束matlab_MATLAB 高斯光束传播轨迹的模拟
  13. Windows实例通过IIS如何搭建多个FTP站点
  14. chd mysql 作用_Cloudera Manager CHD 切换内置数据库PostgreSQL 到 Mysql
  15. php人人商城定时任务,人人商城异步操作菜单示例
  16. 12306火车票助手
  17. 什么轴的机械键盘声音小
  18. el-radio-button 设置默认选中问题
  19. excel函数获取长域名的顶级域名
  20. 世界杯数据可视化分析

热门文章

  1. 秋冬季健康生活小常识
  2. 漏斗分析 - AARRR模型案例分析
  3. 求长方柱的体积和表面积
  4. 一筐梨子一筐水果——协变性(covariant)
  5. mac 笔记本 终端使用管理员权限
  6. csapp 大作业 hello的自白
  7. php guzzle,在PHP中实现使用Guzzle执行POST和GET请求
  8. -atime、-ctime、mtime、-newer
  9. 对抖音App评论进行抓取
  10. js 中出现 invalid date问题