文档章节

安卓图片缓存技术

htq
 htq
发布于 2016/07/26 09:41
字数 1216
阅读 7
收藏 1

概述:随着手机硬件水平的提高及摩尔效应带来的成本的降低,用户手机上的图片的分辨率越来越高,而对于移动终端而言内存存在一定的限制的,如果程序占用过高的内存,也会抛出OOM异常,降低了APP的用户体验感。另外自己做的APP应该尽可能的减少安装包的体积。本博客主要讲述通过压缩图片来减少安装包体积和通过使用图片缓存技术来高效加载大图。

一 压缩图片:

     在加载高分辨率图片的时候,最好先将图片进行压缩,一般情况下将图片压缩到大小与展示该图片的控件的大小差不多就可以。比如说:我们常用的腾讯QQ,在展示用户图像的控件上显示的实际上是压缩过的用户上传后的图片,当你要查看自己上传高清图像时,腾讯专门提供了一个查看大图的功能,此时才会将用户上传的图片显示出来,这样做的目的当然是为了减少程序占用的内存。

压缩图片主要是用到了安卓BitmapFactory.Options类,主要是通过设置options.inJustDecodeBounds = true; 这样就能在不将该bitmap加载到内存的情况下获得该图片的大小方面的属性,如:options.outHeight,options.outWidth。这样就可以根据需求对这些大小属性进行相应的压缩操作,记得在压缩操作完成后要设置options.inJustDecodeBounds = false;代码如下:
/**@author htq
 * 在该方法中对图片进行压缩,可以减少加载图片时占用的java内存。
 * @param path
 * @return
 */
	private Bitmap loadBitmapFromLocal(String path) {
		if (path == null) {
			return null;
		}
		
		BitmapFactory.Options options = new Options();
		options.inJustDecodeBounds = true;
		Bitmap bitmap = BitmapFactory.decodeFile(path, options);
		float height = 800f;
		float width = 480f;
		float scale = 1;
		if (options.outWidth > width && options.outWidth > options.outHeight) {
			scale = options.outWidth / width;
		} else if (options.outHeight > height
				&& options.outHeight > options.outWidth) {
			scale = options.outHeight / height;
		} else {
			scale = 1;
		}
		options.inSampleSize = (int) scale;
		options.inJustDecodeBounds = false;
		bitmap = BitmapFactory.decodeFile(path, options);
		bitmap = decodeBitmap(bitmap);
		if (!imgCaches.containsKey(path)) {
			//imgCaches.put(path, new SoftReference<Bitmap>(bitmap));
			addCache(path, bitmap);
		}
		return bitmap;
	}

除了减少图片占用程序运行的java内存外,还可以对图片进行质量压缩,不会减少图片的像素,所以转化为bitmap后java内存占用与压缩前相同,但可以用来减少图片的大小,即减少图片占用的磁盘空间。代码如下:
/**@author htq
	 * 该方法是对图片进行质量压缩,不会减少图片的像素,所以转化为bitmap后java内存占用与压缩前相同
	 * 仅仅用来减少图片的大小。
	 */
	private Bitmap decodeBitmap(Bitmap bitmap) {
		int scale = 100;
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		bitmap.compress(Bitmap.CompressFormat.JPEG, scale, bos);
		while ((bos.toByteArray().length / 1024) > 30) {
			bos.reset();
			bitmap.compress(Bitmap.CompressFormat.JPEG, scale, bos);
			scale -= 10;
		}
		ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
		bitmap = BitmapFactory.decodeStream(bis);
		return bitmap;
	}


二 使用图片缓存技术来高效加载大图
     2.1使用软引用来缓存图片:主要是通过一个HashMap来将图片路径和图片资源(用软引用表示)关联起来。代码如下:
private static HashMap<String, SoftReference<Bitmap>> imgCaches;
 imgCaches = new HashMap<String, SoftReference<Bitmap>>();
          具体加载图片步骤如下:
         1.通过path路径查看缓存中是否存在该图片,如果存在,则直接加载,如果不存在,则开启一个子线程从网络中获取。
2.图片下载完成后,将该图片放入到缓存中,供下次查询时使用。具体代码如下:

public void loadBitmap(final String path,
			final OnLoadBitmapListener listener) {
		final Handler handler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				super.handleMessage(msg);
				Bitmap bitmap = (Bitmap) msg.obj;
				listener.loadImage(bitmap, path);
			}
		};
		new Thread() {

			@Override
			public void run() {
				executorThreadPool.execute(new Runnable() {
					@Override
					public void run() {
						Bitmap bitmap = loadBitmapFromCache(path);
						if (bitmap != null) {
							Message msg = handler.obtainMessage();
							msg.obj = bitmap;
							handler.sendMessage(msg);
						}

					}
				});
			}

		}.start();
	}


    2.2内存缓存技术:主要是通过LruCache这个类来缓存图片,故名思意可知,当缓存的图片达到了预先设定的值的时候,那么近期使用次数最少的图片就会被回收掉。

使用该类时要预先设置缓存图片内存大小,且必须重写该类的sizeof()方法,默认返回图片数量。代码如下:

private LruCache<String, Bitmap> mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
		@Override
		protected int sizeOf(String key, Bitmap bitmap) {
			// 重写此方法来衡量每张图片的大小,默认返回图片数量。
			return bitmap.getByteCount() / 1024;
		}
	};

与上述使用软引用来加载缓存图片类似,首先会在 LruCache 的缓存中进行检查。如果找到了该图片的缓存,则直接加载,否则开启一个后台线程来加载这张图片。代码如下:
<pre name="code" class="html">public synchronized void addBitmapToMemoryCache(String key, Bitmap bitmap) {
        if (mMemoryCache.get(key) == null) {
            if (key != null && bitmap != null)
                mMemoryCache.put(key, bitmap);
        } else
            Log.w(TAG, "the res is aready exits");
    }

    public synchronized Bitmap getBitmapFromMemCache(String key) {
        Bitmap bm = mMemoryCache.get(key);
        if (key != null) {
            return bm;
        }
        return null;
    }

/**
     * 移除缓存
     * 
     * @param key
     */
    public synchronized void removeImageCache(String key) {
        if (key != null) {
            if (mMemoryCache != null) {
                Bitmap bm = mMemoryCache.remove(key);
                if (bm != null)
                    bm.recycle();
            }
        }
    }


        
   


本文转载自:http://blog.csdn.net/htq__/article/details/50935707

共有 人打赏支持
htq

htq

粉丝 19
博文 67
码字总数 1007
作品 3
武汉
为什么Android官方废弃SoftRefrerence软引用和WeakReference弱引用,而拥抱LruCache?

为什么Android官方废弃SoftRefrerence软引用和WeakReference弱引用,而拥抱LruCache? 一些具有Java背景的研发者喜欢使用软引用(SoftRefrerence)和弱引用(WeakReference)来缓存Java对象和数据...

开开心心过
06/09
0
0
腾讯技术分享:Android版手机QQ的缓存监控与优化实践

本文内容整理自公众号腾讯Bugly,感谢原作者的分享。 1、问题背景 对于Android应用来说,内存向来是比较重要的性能指标。内存占用过高,会影响应用的流畅度,甚至引发OOM,非常影响用户体验。...

JackJiang2011
04/08
0
0
Android开发优化之——对Bitmap的内存优化

在Android应用里,最耗费内存的就是图片资源。而且在Android系统中,读取位图Bitmap时,分给虚拟机中的图片的堆栈大小只有8M,如果超出了,就会出现OutOfMemory异常。所以,对于图片的内存优...

KingMing
2015/04/03
0
0
最美应用-从Android研发工程师的角度之[最美时光]

最美应用-从Android研发工程师的角度之最美时光 @author ASCE1885的 Github 简书 微博 CSDN 最近发现最美应用这样一个网站,它会定期推介一些很有意思的app,作为开发者,每次看到很棒的app...

2tman
2015/08/19
0
0
[Android] Android开发优化之——对Bitmap的内存优化

在Android应用里,最耗费内存的就是图片资源。而且在Android系统中,读取位图Bitmap时,分给虚拟机中的图片的堆栈大小只有8M,如果超出了,就会出现OutOfMemory异常。所以,对于图片的内存优...

haman
2014/01/25
0
1

没有更多内容

加载失败,请刷新页面

加载更多

70.shell的函数 数组 告警系统需求分析

20.16/20.17 shell中的函数 20.18 shell中的数组 20.19 告警系统需求分析 20.16/20.17 shell中的函数: ~1. 函数就是把一段代码整理到了一个小单元中,并给这个小单元起一个名字,当用到这段...

王鑫linux
今天
2
0
分布式框架spring-session实现session一致性使用问题

前言:项目中使用到spring-session来缓存用户信息,保证服务之间session一致性,但是获取session信息为什么不能再服务层获取? 一、spring-session实现session一致性方式 用户每一次请求都会...

WALK_MAN
今天
5
0
C++ yield()与sleep_for()

C++11 标准库提供了yield()和sleep_for()两个方法。 (1)std::this_thread::yield(): 线程调用该方法时,主动让出CPU,并且不参与CPU的本次调度,从而让其他线程有机会运行。在后续的调度周...

yepanl
今天
4
0
Java并发编程实战(chapter_3)(线程池ThreadPoolExecutor源码分析)

这个系列一直没再写,很多原因,中间经历了换工作,熟悉项目,熟悉新团队等等一系列的事情。并发课题对于Java来说是一个又重要又难的一大块,除非气定神闲、精力满满,否则我本身是不敢随便写...

心中的理想乡
今天
34
0
shell学习之获取用户的输入命令read

在运行脚本的时候,命令行参数是可以传入参数,还有就是在脚本运行过程中需要用户输入参数,比如你想要在脚本运行时问个问题,并等待运行脚本的人来回答。bash shell为此提 供了read命令。 ...

woshixin
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部