说明这个问题,首先来看一下实际的内存占用情况。

我们创建一个最简单的android应用,一个Activity,内容是一张图片,图片放在drawable-hdpi目录下。布局文件:

<?xmlversion="1.0" encoding="utf-8"?>

<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:background="@drawable/welcome"

android:id="@+id/splash_layout">

</RelativeLayout>

图片文件大小145k。

打开DDMS,查看内存占用的情况:

在米1(小屏手机)上的内存占用情况:

而在大屏手机上显示的内存占用情况:

内存占用了12M,1-byte array(byte,boolean)栏中,内存占了8.5M,而最大一个对象占了4.16M,应该就是图片。而实际上图片大小也就145K。之所以大屏手机会出现这种情况,主要是因为我们把图片放在hdpi目录下,而大屏手机实际上是xhdpi甚至是xxhdpi。根据Android官方文档提供的资料:

By default, Android scales your bitmapdrawables (.png,.jpg, and.giffiles) and Nine-Patch drawables (.9.pngfiles) sothat they render at the appropriate physical size on each device. For example,if your application provides bitmap drawables only for the baseline, mediumscreen density (mdpi), then the systemscales them up when on ahigh-density screen, and scales them down when on a low-densityscreen.

Android会自动拉伸图片以适应当前手机的分辨率。因此导致了OOM内存溢出。

那么如果我们把hdpi的图片复制一份到xhdpi和xxhdpi中会怎样?

查看运行的结果:

在米1(小屏手机)上的内存占用情况:

而在大屏手机上显示的内存占用情况:

内存已经有所减少,特别是1-bytearray(byte[], boolean[])这一行。米1由于对应的是hdpi的图片,所以不受影响。

但是这样做也有问题,首先我们得把图片都拷贝到不同分辨率对应的目录下(最正确的做法是分别做一套对应分辨率的图片);其次图片占用内存的大小虽然已经减小,但还是太大。

再想一想,我们在布局文件里面写android:background和android:src这些属性,实际上解析之后执行的是view.setBackgroundResource和view.setImageResource方法,这两个方法实际上是拿到资源ID再去获取资源的drawable。他们会decode图片后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。

实际上我们可以用decodeStream来替代,因为decodeStream直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间.另外我们可以设置图片的参数,例如设置为Bitmap.Config.RGB_565来减少内存开销。因为在android文档中描述Bitmap.Config.RGB_565每一个像素存在2个字节中,而默认的Bitmap.Config.ARGB_8888每一个像素则需要4个字节,理论上足足节省了一半空间。

了解这些之后,我把布局文件中的android:background去掉,在java文件中来设置背景。

如下:

BitmapFactory.Options opt = newBitmapFactory.Options();

opt.inPreferredConfig = Bitmap.Config.RGB_565;

opt.inPurgeable = true;

opt.inInputShareable = true;

//获取资源图片

InputStream is = context.getResources().openRawResource(resId);

Bitmap bitmap = BitmapFactory.decodeStream(is,null, opt);

is.close();

returnnew BitmapDrawable(context.getResources(),bitmap);

运行之后在来看效果:

在米1(小屏手机)上的内存占用情况:

而在大屏手机上显示的内存占用情况:

内存瞬间降下来,1-bytearray(byte[], boolean[])这一行最大值为151K。

=================另外一篇解释=============

android中用setBackgroundResource加载图片时出现oom

用setBackgroundResource显示多张图片时,会出现oom,

在看了setBackgroundResource的源码以后,恍然大悟,android对于直接通过资源id载入的资源其实是做了cache的了,这样下次再需要此资源的时候直接从cache中得到,这也是为效率考虑。但这样做也造成了用过的资源都会在内存中,这样的设计不是很适合使用了很多大图片资源的应用,这样累积下来应用的内存峰值是很高的。

代码如下:

detailView=(ImageView)findViewById(R.id.detailView);

detailView.setBackgroundResource(R.drawable.more_info);//this line will lead to OOM

换成这种:

detailView.setImageResource(R.drawable.more_info); //也同样会OOM

后来找到了solution:

/**
          * 以最省内存的方式读取本地资源的图片
          * @param context
          *@param resId
          * @return
          */

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

opt.inPreferredConfig = Bitmap.Config.RGB_565;

opt.inPurgeable = true;

opt.inInputShareable = true;

InputStream is = getResources().openRawResource(

R.drawable.splash );

Bitmap bm = BitmapFactory.decodeStream(is, null, opt);

BitmapDrawable bd = new BitmapDrawable(getResources(), bm);

holder.iv.setBackgroundDrawable(bd);

取得bitmap之后,再 detailView.setImageBitmap(pdfImage); 就ok了!

那是为什么,会导致oom呢:

原来当使用像 imageView.setBackgroundResource,imageView.setImageResource, 或者 BitmapFactory.decodeResource  这样的方法来设置一张大图片的时候,

这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。

因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source,decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。如果在读取时加上图片的Config参数,可以跟有效减少加载的内存,从而跟有效阻止抛out of Memory异常。

另外,需要特别注意: 

         decodeStream是直接读取图片资料的字节码了, 不会根据机器的各种分辨率来自动适应,使用了decodeStream之后,需要在hdpi和mdpi,ldpi中配置相应的图片资源,否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。

解决大屏手机上setImageResource()内存溢出相关推荐

  1. 解决Android 模拟机开机黑屏问题、npm内存溢出问题

    Android模拟机开机黑屏,试试Android Studio中顶部菜单栏中File中的Settings,Settings里搜Android SDK,找到其中的SDK Tools,勾选最高版本,点击下 ...

  2. POI读写超大数据量Excel,解决超过几万行而导致内存溢出的问题(附源码)

    来源:cnblogs.com/swordfall/p/8298386.html 1. Excel2003与Excel2007 两个版本的最大行数和列数不同,2003版最大行数是65536行,最大列数是 ...

  3. 解决Mask RCNN训练时GPU内存溢出问题

    首先自己是个小白对于如何使用GPU跑程序这个学习了一下: (1)使用的是putty,安装了Anaconda这个IDE环境,用的conda install tensorflow-gpu安装的GPU版本t ...

  4. 大数据导出Excel导致内存溢出的解决方案

    一.问题描述: 公司之前的项目中客户有一个需求是将业务数据导出到Excel表中,方便他们对账,单个导出任务数据量近100W,每当月初任务量多时,导出的项目就会内存溢出,挂掉. 二.原因分析: 1.每个 ...

  5. java写入excel文件内存不足,java 导出 excel 最佳实践,java 大文件 excel 避免OOM(内存溢出) excel 工具框架...

    产品需求 产品经理需要导出一个页面的所有的信息到 EXCEL 文件. 需求分析 对于 excel 导出,是一个很常见的需求. 最常见的解决方案就是使用 poi 直接同步导出一个 excel 文件. 客 ...

  6. 解决POI读取Excel百万级内存溢出问题

    使用传统poi来操作大数据量的excel会出现内存溢出的问题,根据各种资源,亲试了一个可用工具类,附代码如下: 一.基于eventusermodel的excel解析工具类 package com.ta ...

  7. 鸿蒙荣耀x10max,荣耀X10 Max有秘密武器:5G大屏手机能比4G还省电

    [TechWeb]根据官方此前公布的消息,荣耀旗下全新的大屏5G手机荣耀X10 Max将于7月2日也就是今天正式亮相,并且该机有望成为今年唯一一款大屏手机,受到众多大屏爱好者的关注.随着发布会进入最后 ...

  8. 大数据excel导出,内存溢出解决方案(SXSSF流用户模型)

    SXSSF(流用户模型 API) SXSSF(包:org.apache.poi.xssf.streaming)是 XSSF 的一个 API 兼容的流扩展,当必须生成非常大的电子表格并且堆空间有限时使用 ...

  9. 解决yarn build时报错:内存溢出FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed

    NODE_OPTIONS=--max_old_space_size=8192 yarn build 参考链接: https://www.freesion.com/article/24241202316 ...

最新文章

  1. SpringBoot随笔
  2. Android中怎样使用createTempFile实现将字节数据创建到临时文件并转换成FileOutputStream和FileInputStream
  3. android沿曲线移动,Android动画学习Demo(3) 沿着贝塞尔曲线移动的Property Animation
  4. thymeleaf教程
  5. 开发人员,请不要抱怨项目没有文档
  6. 物资申请php,危废企业申请经营许可证需满足的条件及申请程序
  7. OFFICE技术讲座:中文标点符号有哪些
  8. 【2019百度之星初赛二1003=HDU6676】度度熊与运算式 1(思维)
  9. [转载] 使用hexo+github搭建免费个人博客详细教程
  10. csgo手机上看demo_《CSGO》观看游戏DEMO方法 怎么观看游戏DEMO
  11. centos6.5安装ansible和tower
  12. 安装yasm(汇编编译器)和 nasm
  13. 用爬虫抓取新浪微博粉丝
  14. 教程 |「川言川语」:用神经网络RNN模仿特朗普的语言风格
  15. STM32F4开发板硬件简介
  16. win10无法识别光驱的解决方法
  17. ubuntu下安装navicat
  18. css学习笔记之图像
  19. 读书:SQL必知必会
  20. Android MIFARE读写器详解2

热门文章

  1. 质量小议2:质量从哪里来?
  2. 操作系统——银行家算法(银行家和房地产开发商的爱恨情仇)
  3. Unity 对GPU的基础性能优化
  4. 计算机视觉——Bag of features
  5. 2020-02-14
  6. 从❤️庄周梦蝶❤️的寓言故事中感悟出一个科学真理:真假之间只相差一个 e^(iπ)
  7. 计算机技能鉴定培训内容,计算机网络管理员职业技能鉴定培训班教学计划大纲.doc...
  8. 面试官:说说React Router有几种模式?实现原理?
  9. 【RPG Maker MZ】独立游戏制作日志①
  10. Unity-业余2D游戏制作笔记01-Dialogue System for Unity使用