文档章节

Android加载大图的优化策略

abcijkxyz
 abcijkxyz
发布于 2016/07/30 17:23
字数 936
阅读 5
收藏 1
当我们使用大的Bitmap图片时很容易出现OOM的现象,今天我们就来看下该怎么解决这个问题。
一般有两种方法:
1、压缩图片;
2、LruCache缓存;
当然这两种方式同时使用效果更好^^
一、压缩图片
先介绍下图片质量(Bitmap.Config),一共有4种:
ALPHA_8 只有透明度,没有颜色,那么一个像素点占8位。
RGB_565 即R=5,G=6,B=5,没有透明度,那么一个像素点占5+6+5=16位。
ARGB_4444 由4个4位组成,即A=4,R=4,G=4,B=4,那么一个像素点占16位。
ARGB_8888 由4个8位组成,即A=8,R=8,G=8,B=8,那么一个像素点占32位。
默认是ARGB_8888。

据此我们可以写出如下函数:

//根据图片质量确定每个像素点所占字节数
public 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;  
}

//根据Bitmap的宽高来计算其大小,知道图片大小后,我们可以决定是否对其压缩
public static long getBitmapSizeInMemory(int imageW, int imageH) {
    return imageH * imageW * getBytesPerPixel(Bitmap.Config.ARGB_8888);  
}
BitmapFactory.Options有个inJustDecodeBounds属性,将inJustDecodeBounds设置为true时,就不解码图片到内存,只读取图片的基本信息,读取并设置之后,再把该值改为false,然后再进行解码获取图片,这就是压缩图片的原理。
代码如下:
//获取的inSampleSize必须是2的倍数 ps:本函数(getScaleInSampleSize)只是一种参考,具体实现还需要根据实际情况有所变动
public static int getScaleInSampleSize(int resW, int resH, int desW, int desH) {  
	int scaleW = resW / desW;  
	int scaleH = resH / desH;  
	int largeScale = scaleH > scaleW ? scaleH : scaleW;  
	int sampleSize = 1;  
	while (sampleSize < largeScale) {  
		sampleSize *= 2;  
	}
	return sampleSize;  
}
//获取压缩图片
public static Bitmap decodeBitmapFromResource(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);  
    int height = options.outHeight;  
    int width = options.outWidth;  
    String mimeType = options.outMimeType; 
    // 调用上面定义的方法计算inSampleSize值  
    options.inSampleSize = getScaleInSampleSize(width, height, reqWidth, reqHeight);  
    //options.inPreferredConfig= Bitmap.Config.RGB_565; //如有必要,还可以修改图片质量,进一步减小图片大小
    // 使用获取到的inSampleSize值再次解析图片  
    options.inJustDecodeBounds = false;  
    return BitmapFactory.decodeResource(res, resId, options);  
}
二、使用LruCache缓存

LruCache缓存主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值即将达到预设定值之前从内存中移除。

用法如下:

private LruCache<String, Bitmap> mMemoryCache;
@Override
protected void onCreate(Bundle savedInstanceState) {
	// 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。
	// LruCache通过构造函数传入缓存值,以KB为单位。
	int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
	// 使用最大可用内存值的1/6作为缓存的大小。
	int cacheSize = maxMemory / 6;
	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);
}
public void loadBitmap(int resId, ImageView imageView) {
	final String imageKey = String.valueOf(resId);
	final Bitmap bitmap = getBitmapFromMemCache(imageKey);
	if (bitmap != null) {
		imageView.setImageBitmap(bitmap);
	} else {
		//如果缓存里面没有就使用默认的图片
		imageView.setImageResource(R.drawable.image_default);
		LoadWorkerTask task = new LoadWorkerTask();
		task.execute(resId);
	}
}
class LoadWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
	// 在后台加载图片。
	@Override
	protected Bitmap doInBackground(Integer... params) {
		final Bitmap bitmap = decodeBitmapFromResource(
				getResources(), params[0], 100, 100);
		addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);
		return bitmap;
	}
}

代码已经很清楚了,就不解释了。

只要我们掌握了这两种方法,那么当我们需要使用大尺寸或是使用多张Bitmap时就不需要再担心OOM问题了。

本文转载自:http://blog.csdn.net/wdong_love_cl/article/details/51584122

共有 人打赏支持
abcijkxyz
粉丝 64
博文 6196
码字总数 1876
作品 0
深圳
项目经理
私信 提问
Android 性能优化:手把手教你优化Bitmap图片资源的使用

前言 在 开发中,性能优化策略十分重要 本文主要讲解性能优化中的Bitmap 使用优化,希望你们会喜欢 目录 1. 优化原因 即 为什么要优化图片资源,具体如下图:

Carson_Ho
04/24
0
0
Android性能优化:手把手教你如何让App更快、更稳、更省(含内存、布局优化等)

前言 在 开发中,性能优化策略十分重要 因为其决定了应用程序的开发质量:可用性、流畅性、稳定性等,是提高用户留存率的关键 本文全面讲解性能优化中的所有知识,献上一份 性能优化的详细攻...

Carson_Ho
05/30
0
0
Android性能优化:手把手带你全面实现内存优化

前言 在 Android开发中,性能优化策略十分重要 本文主要讲解性能优化中的内存优化,希望你们会喜欢 目录 1. 定义 优化处理 应用程序的内存使用、空间占用 2. 作用 避免因不正确使用内存 & 缺...

codeGoogle
05/08
0
0
android:X5WebView首次初始化X5内核耗时,会产生卡顿现象的解决办法

集成腾讯的X5,一般都是在application中进行初始化,不过有一个现象就是第一次启动都睡有一小会产生了UI卡顿,一开始利用IntentService进行后台线程进行初始化,但还是会产生卡顿现象,不过官...

胜_弟
05/22
0
0
Android图片缓存之初识Glide

前言: 前面总结学习了图片的使用以及Lru算法,今天来学习一下比较优秀的图片缓存开源框架。技术本身就要不断的更迭,从最初的自己使用SoftReference实现自己的图片缓存,到后来做电商项目自...

丁佳辉
2017/10/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Mariadb二进制包安装,Apache安装

安装mariadb 下载二进制包并解压 [root@test-a src]# wget https://downloads.mariadb.com/MariaDB/mariadb-10.2.6/bintar-linux-glibc_214-x86_64/mariadb-10.2.6-linux-glibc_214-x86_64.t......

野雪球
今天
3
0
ConcurrentHashMap 高并发性的实现机制

ConcurrentHashMap 的结构分析 为了更好的理解 ConcurrentHashMap 高并发的具体实现,让我们先探索它的结构模型。 ConcurrentHashMap 类中包含两个静态内部类 HashEntry 和 Segment。HashEnt...

TonyStarkSir
今天
3
0
大数据教程(7.4)HDFS的java客户端API(流处理方式)

博主上一篇博客分享了namenode和datanode的工作原理,本章节将继前面的HDFS的java客户端简单API后深度讲述HDFS流处理API。 场景:博主前面的文章介绍过HDFS上存的大文件会成不同的块存储在不...

em_aaron
昨天
3
0
聊聊storm的window trigger

序 本文主要研究一下storm的window trigger WindowTridentProcessor.prepare storm-core-1.2.2-sources.jar!/org/apache/storm/trident/windowing/WindowTridentProcessor.java public v......

go4it
昨天
7
0
CentOS 生产环境配置

初始配置 对于一般配置来说,不需要安装 epel-release 仓库,本文主要在于希望跟随 RHEL 的配置流程,紧跟红帽公司对于服务器的配置说明。 # yum update 安装 centos-release-scl # yum ins...

clin003
昨天
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部