Android 在加载图片时经常会出现OOM的情况,也就是内存溢出,特别是同时加载多张图片或者比较大的图片时非常容易出现,给开发者造成了很大的麻烦,这篇文章也是我在开发的过程中遇到的所作出的解决方案,还有在网上找到的解决方法,列出来提供大家参考。


方案一:读取图片时,尽量要进行压缩后再进行显示,还要选择合适的读取方式。

尽量不要使用setImageBitmapsetImageResourceBitmapFactory.decodeResource来设置一张大图,因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source,decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。

InputStream is =this.getResources().openRawResource(R.drawable.pic1);

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

options.inJustDecodeBounds= false;

options.inSampleSize= 10;//widthhight设为原来的十分一

Bitmap btp = BitmapFactory.decodeStream(is,null, options);


如果在读取时加上图片的Config参数,可以更有效减少加载的内存,从而跟有效阻止抛out of Memory异常。

/**

* 以最省内存的方式读取本地资源的图片

* @paramcontext

* @paramresId

* @return

*/

public static Bitmap readBitMap(Context context,intresId){

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

opt.inPreferredConfig= Bitmap.Config.RGB_565;

opt.inPurgeable=true;

opt.inInputShareable=true;

// 获取资源图片

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

returnBitmapFactory.decodeStream(is,null, opt);

}

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


方案二:在适当的时候及时回收图片占用的内存

通常Activity或者Fragment在onStop/onDestroy时候就可以释放图片资源:

if(imageView != null&& imageView.getDrawable()!=null){

Bitmap oldBitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();

imageView.setImageDrawable(null);

if(oldBitmap != null){

oldBitmap.recycle();

oldBitmap = null;

}

}

// Other code.

System.gc();


在释放资源时,需要注意释放的Bitmap或者相关的Drawable是否有被其它类引用。如果正常的调用,可以通过Bitmap.isRecycled()方法来判断是否有被标记回收;而如果是被UI线程的界面相关代码使用,就需要特别小心避免回收有可能被使用的资源,不然有可能抛出系统异常: E/AndroidRuntime: java.lang.IllegalArgumentException: Cannot draw recycled bitmaps 并且该异常无法有效捕捉并处理。
方案三:不必要的时候避免图片的完整加载

只需要知道图片大小的情形下,可以不完整加载图片到内存。在使用BitmapFactory压缩图片的时候,BitmapFactory.Options设置inJustDecodeBounds为true后,再使用decodeFile()等方法,可以在不分配空间状态下计算出图片的大小。示例:

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

// 设置inJustDecodeBounds为false

opts.inJustDecodeBounds= false;

// 使用decodeFile方法得到图片的宽和高

BitmapFactory.decodeFile(path, opts);

// 打印出图片的宽和高

Log.d("example", opts.outWidth+","+ opts.outHeight);

(ps:原理其实就是通过图片的头部信息读取图片的基本信息)


方案四:优化Dalvik虚拟机的堆内存分配

堆(HEAP)是VM中占用内存最多的部分,通常是动态分配的。堆的大小不是一成不变的,通常有一个分配机制来控制它的大小。比如初始的HEAP是4M大,当4M的空间被占用超过75%的时候,重新分配堆为8M大;当8M被占用超过75%,分配堆为16M大。倒过来,当16M的堆利用不足30%的时候,缩减它的大小为8M大。重新设置堆的大小,尤其是压缩,一般会涉及到内存的拷贝,所以变更堆的大小对效率有不良影响。Heap Utilization是堆的利用率。当实际的利用率偏离这个百分比的时候,虚拟机会在GC的时候调整堆内存大小,让实际占用率向个百分比靠拢。使用 dalvik.system.VMRuntime类提供的setTargetHeapUtilization方法可以增强程序堆内存的处理效率。

privatefinalstaticfloat TARGET_HEAP_UTILIZATION= 0.75f;

// 在程序onCreate时就可以调用

VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);


方案五、自定义堆(Heap)内存大小

对于一些Android项目,影响性能瓶颈的主要是Android自己内存管理机制问题,目前手机厂商对RAM都比较吝啬,对于软件的流畅性来说RAM对性能的影响十分敏感,除了优化Dalvik虚拟机的堆内存分配外,我们还可以强制定义自己软件的对内存大小,我们使用Dalvik提供的 dalvik.system.VMRuntime类来设置最小堆内存为例:

privatefinalstaticint CWJ_HEAP_SIZE= 6 * 1024 * 1024 ;

VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); // 设置最小heap内存为6MB大小。

但是上面方法还是存在问题,函数setMinimumHeapSize其实只是改变了堆的下限值,它可以防止过于频繁的堆内存分配,当设置最小堆内存大小超过上限值(Max Heap Size)时仍然采用堆的上限值,对于内存不足没什么作用。
最后介绍一下图片占用进程的内存算法。android中处理图片的基础类是Bitmap,顾名思义,就是位图。占用内存的算法如:图片的width*height*Config。如果Config设置为ARGB_8888,那么上面的Config就是4。一张480*320的图片占用的内存就是480*320*4 byte。在默认情况下android进程的内存占用量为16M,因为Bitmap他除了java中持有数据外,底层C++的 skia图形库还会持有一个SKBitmap对象,因此一般图片占用内存推荐大小应该不超过8M。这个可以调整,编译源代码时可以设置参数。

参考了开源中国社区中的

Android加载图片导致内存溢出(Out of Memory异常)


更多相关文章

  1. android批量文件上传(android批量图片上传)
  2. App启动时三种效果(黑屏白屏、背景图片、延迟加载)
  3. Android(安卓)仿照微信发说说,既能实现拍照,选图库,多图案上传 使用
  4. Android(安卓)根据角度旋转图片
  5. 制作一款简单的网络图片查看器
  6. Android(安卓)XML shape 标签使用详解(apk瘦身,减少内存)
  7. Android车轮之图片加载框架Android-Universal-Image-Loader
  8. Android原生分享功能的思考与实现
  9. Android实现遮罩层(蒙板)效果

随机推荐

  1. android应用去掉标题栏的方法
  2. Android(安卓)Studio 迁移 AndroidX 遇到
  3. android学习—— 简单的实现 android 退
  4. ViewGroup measure layout
  5. Button监听方式
  6. Android(安卓)2.2 r1 API 中文文档系列(11
  7. MediaProvider流程分析
  8. 怎么让我们自己开发的Android程序设为默
  9. android 纯代码 详细编写布局文件
  10. 遇到问题描述:Android(安卓)Please ensure