1. Why,为什么要加载缩略图?

有的时候不需要展示原图,只需展示图片的缩略图,可以节省内存。比如:网易新闻中的图片浏览,左边展示的小狮子图片就是一个缩略图,点击这个图片,才会展示原图。

 

2. How,怎么做呢?

http://developer.android.com/training/displaying-bitmaps/load-bitmap.html给出了一个方法,可以加载一个图片的缩略图。
BitmapFactory#decodeFile (String pathName, BitmapFactory.Options opts),opts可以指定inJustDecodeBounds和inSampleSize两个参数。当指定inJustDecodeBounds时候,只解析图片的长度和宽度,不载入图片。当指定inSampleSize的时候,会根据inSampleSize载入一个缩略图。 比如inSampleSize=4,载入的缩略图是原图大小的1/4。
要设置inSampleSize是多少呢?假设原图是1500x700的,我们给缩略图留出的空间是100x100的。那么inSampleSize=min(1500/100, 700/100)=7。我们可以得到的缩略图是原图的1/7。这里如果你要问15:7的图片怎么显示到1:1的区域内,请去看ImageView的scaleType属性。
但是事实没有那么完美,虽然设置了inSampleSize=7,但是得到的缩略图却是原图的1/4,原因是inSampleSize只能是2的整数次幂,如果不是的话,向下取得最大的2的整数次幂,7向下寻找2的整数次幂,就是4。
怎么才能不浪费内存呢?大熊同学找到一个方法:Bitmap#createScaledBitmap (Bitmap src, int dstWidth, int dstHeight, boolean filter),该方法可以将一个Bitmap生成指定大小的BItmap,该方法可以放大图片也可以缩小图片。

最终缩略图加载过程:

1. 使用inJustDecodeBounds,读bitmap的长和宽。
2. 根据bitmap的长款和目标缩略图的长和宽,计算出inSampleSize的大小。
3. 使用inSampleSize,载入一个大一点的缩略图A
4. 使用createScaseBitmap,将缩略图A,生成我们需要的缩略图B。
5. 回收缩略图A。

3. Notice,需要注意的事情

createScaseBitmap如果原图和目标缩略图大小一致,那么不会生成一个新的bitmap直接返回bitmap,因此,回收的时候,要判断缩略图A是否就是缩略图B,如果说是的话,不要回收。

4. 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/**
 */
public class BitmapUtils {
    private 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 halfHeight = height / 2;
            final int halfWidth = width / 2;
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }
 
    // 如果是放大图片,filter决定是否平滑,如果是缩小图片,filter无影响
    private static Bitmap createScaleBitmap(Bitmap src, int dstWidth,
            int dstHeight) {
        Bitmap dst = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false);
        if (src != dst) { // 如果没有缩放,那么不回收
            src.recycle(); // 释放Bitmap的native像素数组
        }
        return dst;
    }
 
    // 从Resources中加载图片
    public static Bitmap decodeSampledBitmapFromResource(Resources res,
            int resId, int reqWidth, int reqHeight) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(res, resId, options); // 读取图片长款
        options.inSampleSize = calculateInSampleSize(options, reqWidth,
                reqHeight); // 计算inSampleSize
        options.inJustDecodeBounds = false;
        Bitmap src = BitmapFactory.decodeResource(res, resId, options); // 载入一个稍大的缩略图
        return createScaleBitmap(src, reqWidth, reqHeight); // 进一步得到目标大小的缩略图
    }
 
    // 从sd卡上加载图片
    public static Bitmap decodeSampledBitmapFromFd(String pathName,
            int reqWidth, int reqHeight) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(pathName, options);
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
        options.inJustDecodeBounds = false;
        Bitmap src = BitmapFactory.decodeFile(pathName, options);
        return createScaleBitmap(src, reqWidth, reqHeight);
    }
}

5. 测试代码

代码下载链接 http://download.csdn.net/detail/u011267546/7485045

在drawable-xxhdpi目录下,一共有四种大图,每个平均5-6MB,一共22.9MB。如果原图加载很容易就崩溃了。如果使用上面的方法加载的话,只加载了234KB。这里说一下234KB怎么来的,4个imageView,目标尺寸都是75dip*50dip,在我的手机GalaxyNexus上面,转化为px之后是150px*100px=15000个像素,每个像素使用ARGB_8888方式存储,需要4个字节。一张图片需要15000*4=60000字节,一共有4个Bitmap,那么就是60000*4=240000字节=234.375 KB。

如果是布满一个屏幕,至少需要多少内存呢?我的手机是768*1280像素,ARGB_8888方式存储,每个像素4个字节,那么就是768*1280*4=3840KB=3.75MB。所以,缓存3屏幕图像的话,也就11MB左右。做内缓存的时候,有必要考虑下这个问题。

Android中的缩略图加载-不浪费一点多余的内存的更多相关文章

  1. arcgis android 中shapefile的加载

    前言 本文为大家分享arcgis android 中shapefile的加载,默认你有java环境,懂一定的android基础知识,默认你已经安装android studio.如缺乏以上环境和知识,请 ...

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

    我们在使用ListView异步加载图片的时候,在快速滑动或者网络不好的情况下,会出现图片错位.重复.闪烁等问题,其实这些问题总结起来就是一个问题,我们需要对这些问题进行ListView的优化. 比如L ...

  3. Android中的动态加载机制

    在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势.本 ...

  4. Android中的Glide加载图片

    注意:在Android Studio的项目的build.gradle中添加: compile 'com.github.bumptech.glide:glide:3.6.1' 然后同步一下 目录: 使用 ...

  5. Android中的分页加载

    //----------------------MainActivity中--------------------------------------------------- package com ...

  6. Android中ListView动态加载数据

    1. 引言: 为了提高ListView的效率和应用程序的性能,在Android应用程序中不应该一次性加载ListView所要显示的全部信息,而是采取分批加载策略,随着用户的滑动,动态的从后台加载所需的 ...

  7. Android中一张图片加载后所占用内存大小的获取与测试

    Android程序中一旦加载的图片比较多,就有可能出现Out of Memory而导致程序崩溃.这个一方面是因为Android系统本身对于每个单独的进程有内存大小的限制(有16M,64M,128M,2 ...

  8. Android中使用POI加载与显示word文档

    最近打算实现一个功能:在Android中加载显示Word文档,当然这里不是使用外部程序打开.查看一些资料后,打算采用poi实现,确定了以下实现思路: 将ftp中的word文档下载到本地. 调用poi将 ...

  9. Android中ListView分页加载数据

    public class MainActivity extends Activity { private ListView listView=null; //listview的数据填充器 privat ...

随机推荐

  1. poj1182(种类并查集好题)

    不得不说,我得感谢@驱动幽灵百鬼夜行小肆,正是因为看明白了他给出的解析,我才完全弄懂种类并查集的,这里,我也不想去改其他的,就直接引用他的解题报告吧 转载:http://blog.csdn.net/c ...

  2. JAVA-JSP内置对象之request获得所有的参数名称

    相关资料:<21天学通Java Web开发> 获得所有的参数名称1.request对象的getParameterNames()方法可以获得所有的参数名称. RequestForm2.jsp ...

  3. ios CGRectGet...位置属性的基本介绍

    UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(10, 10, 110, 150)]; label.backgroundColor ...

  4. 一次简单的ctf SQL注入绕过

    注入地址:http://103.238.227.13:10087/index.php?id=1 //过滤sql $array = array('table','union','and','or','l ...

  5. golang深度获取子节点

    起因 需要在树形结构里获取子树,树形结构一般是存储一维数组,数组元素里存储子节点的指针 代码 package main import ( "errors" "fmt&qu ...

  6. Android Toolbar的使用 顶部标题栏+后退键

    最近设计安卓里面有个标题栏,里面有个后退键,可以完成后退之类的功能. 好,刚好可以用Toolbar去实现 上代码:activity_main.xml <?xml version="1. ...

  7. [Linux实用工具]munin-node插件配置和插件编写

    前面介绍了2篇munin使用的相关文章: [Linux实用工具]Linux监控工具munin的安装和配置 [Linux实用工具]Linux监控工具munin的展示(Nginx)   这次介绍一下mun ...

  8. 记录 am335x 因为 pinmux 配置不对导致 不断的原因

    其实很简单,是因为 中断不仅仅需要 gpio 的 input 属性, 还需要 pull_up 的数据 {"gpmc_ad11.gpio0_27", OMAP_MUX_MODE7 | ...

  9. AR2220 通过cpu-defend policy处理大量大量arp广播的小技巧

    今天发现有局域网里面有几台电脑中毒了,在大量的发送ARP报文,导致设备cpu利用率很高. 一.查看display cpu-defend statistics 发现arp-reply  arp-requ ...

  10. jmap查看内存使用情况与生成heapdump

    jmap查看内存使用情况与生成heapdump 如果想分析自己的JAVA Application时,可以使用jmap程序来生成heapdump文例: jmap -heap 1234  (1234为进程 ...