《性能优化: 图片加载优化》

加载图片

加载图片的来源可能是手机本地磁盘、网络资源或者是资源文件中的图片。图片分辨率不一、或大或小,但最终图片显示在屏幕上都是Bitmap的形式,一张图片被加载到内存当中所占据的内存大小,除了和图片分辨率有关还和格式有关。因为格式不同,每个像素点占据的内存空间就不一样,通常的格式有ARGB_8888和RGB_565。前者每个像素占用4个字节,后则占用两个字节

图片大小计算

A图:分辨率为300*520、格式为ARGB_8888.
300 * 520 * 4 = 0.595M

B图:一张分辨率为2048*1500、格式为ARGB_8888
2048 * 1500 * 4 = 11.72M

假如A图和B图显示的内容一样,现在一个ImageView宽高非常小,那么我们优先加载A图,因为没有必要加载一张大图显示到宽高比较小的控件上,加载B图,不仅浪费内存资源,像ListView,GridView,如果都是加载大图,有可能造成OOM异常。

优化加载

加载一些未知来源的图片,由于我不知道图片的宽高大小和形状,加载的图片很有可能超出我需要显示的大小,所以在加载前对它的大小做一下检测,如果图片的大小(分辨率)远超出了我们需要现实的大小,我们需要对图片进行压缩处理,这是在客户端处理未知来源图片的优化方式,而服务端(自己公司的图片服务器)一般根据请求的url时带上不同的参数直接获取需要不同等级或者不同分辨率的图片。所以优化的手段有两种,一种是服务对图片进行压缩处理再返回,第二种就是客户处理。核心就是对图片进行压缩优化

服务端压缩优化
举两个例子

1、阿里云图片服务器
阿里云图片服务器一般在请求图片url带上你期望的图片分辨率参数,服务器会更具给定的分辨率给压缩图片返回给客户端。

2、豆瓣电影图片
豆瓣电影图片请求url中 更改图片等级l、m、s就会返回相应等级的图片大小。

https://img1.doubanio.com/view/photo/l/public/p2529206747.jpg
https://img1.doubanio.com/view/photo/m/public/p2529206747.jpg
https://img1.doubanio.com/view/photo/s/public/p2529206747.jpg

服务端具体是怎么压缩处理的,不是我们关注的重点,移动端才是我们所需要研究的。

客户端压缩优化

我们用BitmapFactory去加载一张图片生成Bitmap对象,根据不同的图片资源提供了不同的方法decodeFile用于加载SD卡中的图片、decodeStream用于加载网络中的图片、decodeResource用于加载资源中图片,这些方法会尝试为已经构建的bitmap分配内存,如果此时内存资源紧缺会很容易导致OOM异常。为此每一种解析方法都提供了一个可选的BitmapFactory.Options参数,将这个参数的inJustDecodeBounds属性设置为true就可以让解析方法禁止为bitmap分配内存,返回值也不再是一个Bitmap对象,而是null。虽然Bitmap是null了,但是BitmapFactory.Options的outWidth、outHeight和outMimeType属性都会被赋值。这个技巧让我们可以在加载图片之前就获取到图片的长宽值和MIME类型,从而根据情况对图片进行压缩。如下代码所示:

BitmapFactory.Options options = new BitmapFactory.Options();

options.inJustDecodeBounds = true;

BitmapFactory.decodeResource(getResources(), R.id.myimage, options);

int imageHeight = options.outHeight;

int imageWidth = options.outWidth;

String imageType = options.outMimeType;

而压缩图片可以通过BitmapFactory.Options中inSampleSize
来实现。

压缩思路

1、获取原图分辨率
2、获取显示的ImageView的显示分辨率
3、计算压缩size
4、设置inSampleSize = size

关于inSampleSzie:我们有一张20481536像素的图片,将inSampleSize的值设置为4(即缩小为原来的四分之一),就可以把这张图片压缩成512384像素。原本加载这张图片需要占用13M的内存,压缩后就只需要占用0.75M了

直接套用郭霖大神的方法
参考https://blog.csdn.net/guolin_blog/article/details/9316683
计算压缩size

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;
}

获取压缩后的Bitmap


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);
}

下面的代码非常简单地将任意一张图片压缩成100*100的缩略图,并在ImageView上展示。

mImageView.setImageBitmap(
   decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

Glide图片加载框架

Glide是现在非常流行的图片缓存框架,也是Google官方推荐使用的。它加载网络、磁盘和资源中的图片,内置四级缓存优化、并且会根据ImageView的大小进行图片的压缩处理,它与当前的Activity或Fragment保持相同的声明周期。

关于Glide更多使用 Please look 《图片缓存框架-Glide(使用到源码解析博客整理)》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容