Android—大图or多图加载解决方案(完美解决OOM问题)

在开发应用的时候,很多时候都会涉及大量图片的加载和高精度图片的加载,这两种操作都是会导致应用程序OOM(OutOfMemory)的问题发生,合理的图片加载和图片内存管理就是必须解决的问题,以下将提供一个比较完善的技术方案,解决这两个问题。

首先,我们必须明确为什么会发生OOM(OutOfMemory)的问题,其原因就是因为在APP运行过程中,所使用的系统内存超出了当前APP的最大可用内存,就发生了OOM的问题。下面,我们来估算一下在一台中高档的手机上面,加载多少图片会导致OOM:假设系统分配给APP的最大可用内存为32M,加载一张512*512分辨率的图片,会占用2M的内存空间,这样,在APP中加载16张图片,就会出现OOM,事实上,当加载10张图片以上,都极容易导致OOM,因为APP运行中还是会占用内存的。(PS:图片占用内存计算:Android中Bitmap的默认加载使用ARGB_8888,每个像素会占用4byte,因为每个像素有两个Chanel,因此一个512*512的图片,无论什么格式,加载进入内存都占用512*512*4*2=2MB,所以,Android图片占用内存大小,只与图片的分辨率(像素)以及加载使用的色彩模式有关)

要解决OOM的问题,从两方面进行优化:1.合理加载资源
2.合理回收资源

合理加载资源

合理加载资源,既如果展示图片的ImageView只有128*96的像素大小,这时候把一张1024*768的图片完全加载到内存中,很明显是错误的行为。这个时候,就需要把要加载的图片进行压缩加载,就是合理地加载资源。

下面,来进行图片的压缩讲解,设置BitmapFactory.Options中inSampleSize的值就可以实现等比例压缩。比如我们有一张2048*1536像素的图片,将inSampleSize的值设置为4,就可以把这张图片压缩成512*384像素。原本加载这张图片需要占用26M的内存,压缩后就只需要占用1.5M了。下面的方法可以根据传入的宽和高,计算出合适的inSampleSize值:

public static int calculateInSampleSize(BitmapFactory.Options options,
		int reqWidth, int reqHeight) {
	// 源图片的高度和宽度
	final int height = options.outHeight;
	final int width = options.outWidth;
	int inSampleSize = 1;
	if (height > reqHeight || width > reqWidth) {
		// 计算出实际宽高和目标宽高的比率
		final int heightRatio = Math.round((float) height / (float) reqHeight);
		final int widthRatio = Math.round((float) width / (float) reqWidth);
		// 选择宽和高中最小的比率作为inSampleSize的值,这样可以保证最终图片的宽和高
		// 一定都会大于等于目标的宽和高。
		inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
	}
	return inSampleSize;
}

计算出合适的缩放比例后,接着进行图片的实际压缩操作:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
        int reqWidth, int reqHeight) {
	// 第一次解析将inJustDecodeBounds设置为true,来获取图片大小
    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(res, resId, options);
    // 调用上面定义的方法计算inSampleSize值
    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    // 使用获取到的inSampleSize值再次解析图片
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);
}

经过以上的两步操作,即可实现合理的加载图片资源。

合理回收资源

合理回收资源,既对加载在内存中的图片资源进行合理的回收,避免因为不再使用的图片资源还留存在内存中的情况出现。而要实现合理回收资源,最核心的一个类就是:LruCache,这个类非常适用于保存图片内存,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除。

下面给出具体的使用方法:

private LruCache<String, Bitmap> mMemoryCache;

@Override
protected void onCreate(Bundle savedInstanceState) {
	// 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。
	// LruCache通过构造函数传入缓存值,以KB为单位。
	int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
	// 使用最大可用内存值的1/8作为缓存的大小。
	int cacheSize = maxMemory / 8;
	mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
		@Override
		protected int sizeOf(String key, Bitmap bitmap) {
			// 重写此方法来衡量每张图片的大小,默认返回图片数量。
			return bitmap.getByteCount() / 1024;
		}
	};
}

public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
	if (getBitmapFromMemCache(key) == null) {
		mMemoryCache.put(key, bitmap);
	}
}

public Bitmap getBitmapFromMemCache(String key) {
	return mMemoryCache.get(key);
}

只要确保整个APP的图片资源的使用,都是通过addBitmapToMemoryCache和getBitmapFromMemCache来进行,即可避免OOM的出现。

Android—大图or多图加载解决方案(完美解决OOM问题),布布扣,bubuko.com

时间: 2024-12-18 17:28:04

Android—大图or多图加载解决方案(完美解决OOM问题)的相关文章

Android高清巨图加载方案

1.今天看了鸿洋的<Android高清巨图加载方案>一文,对加载高清巨图时的解决方案有了一定的认识. 思路为: 提供一个设置图片的入口. 重写onTouchEvent,在里面根据用户移动的手势,去更新显示区域的参数. 每次更新区域参数后,调用invalidate,onDraw里面去regionDecoder.decodeRegion拿到bitmap,去draw. 2.除此之外,对安卓的手势事件分发以及手势监听做了进一步学习. 2.1.手势事件分发 详见<Android手势事件分发过程分析

[转]Nginx 502 PHP LNMP 502 终极解决方案 完美解决502 用 upstream 和 fastcgi_next_upstream 可以极大缓解

转: http://xn--ghqyhzj.com/post-21537.html 本文针对LNMP的PHP 版本ver 5.3.6 or Higher,其它未测试过. 1. 使用不同端口或php-fpm.sock启动多个php-fpm主进程 假设使用不同的配置文件启动3个创建sock监听的PHP-FPM主进程 #/usr/local/php/sbin/php-fpm --fpm-config /usr/local/php/etc/php-fpm.1.conf#/usr/local/php/sb

Android项目实战(十二):解决OOM的一种偷懒又有效的办法

原文:Android项目实战(十二):解决OOM的一种偷懒又有效的办法 在程序的manifest文件的application节点加入android:largeHeap=“true” 即可. 对,只需要一句话! 那么这行代码的意思是什么呢? 简单的说就是使该APP获取最大可分配的内存,以便解决OOM问题. 但是.OOM问题出现的原因总得来说有两点: 1.某个手机的内存真的很少 2.代码问题,比如没有处理好Bitmap图片的大小 可以说,出现OOM的情况基本都是第二种情况,那么就需要修改代码,看看哪

emlog通过pjax实现无刷新加载网页--完美解决cnzz统计和javascript失效问题

想要更详细了解pjax,需要查看官网 或者看本站文章:jQuery.pjax.js:使用AJAX和pushState无刷新加载网页(官网教程中文翻译) 效果看本站,音乐无刷新播放,代码高亮和复制js加载成功- 准备文件 编辑模板 header.php 的 head 添加必要文件: jquery-1.11.1.min.js:百度网盘下载 jquery.pjax-1.8.2.min.js:百度网盘下载 下载到模板的 scripts 目录下后将下面两句添加到</head>所有script标签的最前面

Android性能调优:记一次解决OOM的经历

OOM OOM(Out Of Memory)是Android应用开发中相信每个人都遇到过的问题,而OOM在crash log中的stack trace一般没有实际意义,因为是在分配内存的时候才会抛出OOM异常,而这个时候的stack trace和OOM的原因没有任何关系.所以OOM问题的定位和分析就需要多花费一些功夫. 下面,我就结合一个例子,来讲讲怎么定位OOM问题. 问题 在程序员们把代码写完,基本流程测试无误,准备要发布的时候,云测的结果却是:一大波OOM异常.没办法,只好重新打开电脑定位

outlook 关闭时最小化到任务栏的完美解决方法

最近使用Outlook,但是发现很容易被关闭退出,不能实现关闭最小化. 在网上了找了很久也使用了outlook on the desktop的插件,但是安装该插件后运行报错而弃用.最后找到了一个叫keepoutlookrunning的com 的加载项完美解决,下载地址:keepoutlookrunning. 安装方法:见百度文库 注意:改插件需要 "Microsoft Visual C++ 2010 可再发行组件包"的支持,如遇到安装时无法安装加载项时请先安装组件包,组件包下载地址 插

Android大图加载内存优化(如何防止OutOfMemory)

一.简介 移动设备不断发展的今天,有的人认为内存已经足够大了,不用再管什么内存优化,Java是虚拟机可以帮我维护内存.其实内存空间资源还是很宝贵的,不管手机内存有多大,系统分配给单个应用的内存空间还是很有限的大致有16M,64M,128M等.在Android中加载大图会非常消耗系统资源,16M的图片大致可以存储3张1024X1536质量为ARGB_8888的图片,这里边还不包含其它Object所占的资源.软件在系统上运行,环境是很复杂的,可能测试的时候有限的测试次数上没有发现内存泄漏问题,但是在

Android中ListView异步加载图片错位、重复、闪烁问题分析及解决方案

Android中ListView异步加载图片错位.重复.闪烁问题分析及解决方案 我们在使用ListView异步加载图片的时候,在快速滑动或者网络不好的情况下,会出现图片错位.重复.闪烁等问题,其实这些问题总结起来就是一个问题,我们需要对这些问题进行ListView的优化. 比如ListView上有100个Item,一屏只显示10个Item,我们知道getView()中convertView是用来复用View对象的,因为一个Item的对应一个View对象,而ImageView控件就是View对象通

Android中使用WebView加载大图

在Android系统中,加载图片是一个充满挑战的工作,特别是超出屏幕很大的图片,要考虑适应屏幕,滚动等问题. 而采用网页的方式可以很好的屏蔽这些问题,Webview+JS可以很好的控制屏幕的适配,也不会出现内存溢出的情况,来看看怎么实现的吧 package com.msn.support.gallery; import android.annotation.TargetApi; import android.os.Bundle; import android.support.annotation