关闭

Android:图片处理小结

标签: android图片
636人阅读 评论(0) 收藏 举报
分类:

图片处理在安卓开发中十分重要,因为:

  1. 系统资源有限,系统为单个应用分配的内存也有限;
  2. 图片占用大量内存,例如一张2592x1936像素的图片,如果以ARGB_8888编码,会占据2592*1936*4 bytes约19M的内存,这无疑会很容易造成OOM!
  3. 一些控件尤其是AdapterView,会需要加载较多图片,处理不当也会OOM。

本文全部内容均来源于官方文档Displaying Bitmaps Efficiently,简单小结一下方便以后自己快速查找。


1、高效加载大图,Displaying Bitmaps Efficiently

通常我们加载图片的分辨率是会大于屏幕的分辨率,所以加载大内存的图片对于显示效果来说是不会有任何好处的;
解决方法:

1)获得图片的一些信息,包括实际高度宽度,而不加载到内存

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);

2)通过实际所需来计算图片的压缩比例,options.inSampleSize,算法也比较简单,实际高度不断除半来和所需高度比较即可。

3)真正加载压缩后的图片到内存,

options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);


2、在子线程处理图片

1)异步任务方式来处理,官方推荐是AsyncTask;
2)注意并发问题


3、缓存图片

内存缓存

使用内存缓存技术之前,需要先考虑一些问题以选择一个合适的缓存内存大小。

  • How memory intensive is the rest of your activity and/or application?
  • How many images will be on-screen at once? How many need to be available ready to come on-screen?
  • What is the screen size and density of the device? An extra high density screen (xhdpi) device like Galaxy Nexus will need a larger cache to hold the same number of images in memory compared to a device like Nexus S (hdpi).
  • What dimensions and configuration are the bitmaps and therefore how much memory will each take up?
  • How frequently will the images be accessed? Will some be accessed more frequently than others? If so, perhaps you may want to keep certain items always in memory or even have multiple LruCache objects for different groups of bitmaps.
  • Can you balance quality against quantity? Sometimes it can be more useful to store a larger number of lower quality bitmaps, potentially loading a higher quality version in another background task.

使用LruCache类来实现内存缓存,看了源码感觉兼容包android.support.v4.util.LruCache才是真正LRU算法,而android.util.LruCache处理掉的是RU的,不知道有没分析错误!还是使用兼容包保险点。

final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

    // Use 1/8th of the available memory for this memory cache.
    final int cacheSize = maxMemory / 8;

    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
        @Override
        protected int sizeOf(String key, Bitmap bitmap) {
            // The cache size will be measured in kilobytes rather than
            // number of items.
            return bitmap.getByteCount() / 1024;
        }
    };
    ...

直接调用LruCache对象的put和get方法就可以了,使用上还是比较简单的。


磁盘缓存

SDK中并没有磁盘缓存的工具类,但是JakeWharthon大神写了个官方认证的硬盘缓存类。
https://android.googlesource.com/platform/libcore/+/jb-mr2-release/luni/src/main/java/libcore/io/DiskLruCache.java
硬盘缓存的使用没有内存那么方便,需要自己封装一下,主要使用:

  1. 通过获得一个输出流来保存缓存文件;
    DiskLruCache.Editor editor = mDiskLruCache.edit(key);
    OutputStream outputStream = editor.newOutputStream(0);
  2. 通过获得一个输入流来读取缓存文件;
    DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key);
    InputStream inputStream = snapShot.getInputStream(0);

4、管理图片内存

不同版本的android内存管理方式有所不同,比如说

  1. 2.2之前GC时会停止所有线程;2.3以后可以并发GC,所以当Bitmap对象不再被引用时就会被回收;
  2. 2.3.3(API 10)之前,像素数据是存放在native memory的,和存储在Dalvik堆Bitmap对象本身分离。

管理图片内存:
1)在2.3.3之前,使用recycle()方法可以让GC尽快回收Bitmap对象,通过一些计数的方式来确定Bitmap对象确实不再使用,从而合理地使用recycle()方法;

2)在3.0之后,使用BitmapFactory.Options.inBitmap字段,如果这个选项被选择,解码方法加载数据时将尝试重复利用已经存在的Bitmap对象。


最后推荐一下郭霖大神的博客,http://blog.csdn.net/guolin_blog里面有一系列相关的文章!

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:80326次
    • 积分:1685
    • 等级:
    • 排名:千里之外
    • 原创:87篇
    • 转载:0篇
    • 译文:0篇
    • 评论:19条
    最新评论