Android经典面试题之图片Bitmap怎么做优化

简介: 本文介绍了图片相关的内存优化方法,包括分辨率适配、图片压缩与缓存。文中详细讲解了如何根据不同分辨率放置图片资源,避免图片拉伸变形;并通过示例代码展示了使用`BitmapFactory.Options`进行图片压缩的具体步骤。此外,还介绍了Glide等第三方库如何利用LRU算法实现高效图片缓存。

本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点

图片相关的内存优化

图片相关的优化主要涉及几个方面:分辨率的适配、图片的压缩、图片的缓存

分辨率的适配

分辨率的适配主是针对我们放在drawable目录下的图片资源,目录和对应的手机分辨率可以看下图

DPI、分辨率和drawable目录

所以我们需要不同分辨率的图片来放在对应的目录下来做适配,否则Android系统可能会将我们的图片拉伸导致变形。

或者直接使用svg图也是一个很好的选项。

图片的压缩

图片的压缩是指我们需要根据View所实际需要的图片尺寸来加载对应大小的图片。一般我们用的图片加载第三方库,比如Glide,都已经帮我们做了处理。所以这里的图片压缩我们只需要在我们自己处理图片的时候需要考虑。

图片压缩说起来也不复杂,主要是用到了BitmapFactory的Options,一般都分为如下几个步骤:

(1)先把inJustDecodeBounds设置为true,以便后面回去图片的实际大小

//先把inJustDecodeBounds设置为true,以便后面回去图片的实际大小
BitmapFactory.Options options = new BitmapFactory.Options();
//先解析图片的宽高信息,inJustDecodeBounds为true就只会加载图片的尺寸信息
options.inJustDecodeBounds = true;

(2)然后压缩图片

//Resources res, int resId
BitmapFactory.decodeResource(res, resId, options);

(3)计算压缩的比例,inSampleSize参数表示采样,会对图片的宽高进行缩放

//这里reqWidth和reqHeight表示实际需要的宽高
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
   
    final int height = options.outHeight;
    final int width = options.outWidth;
    int sampleSize = 1;

    if (height > reqHeight || width > reqWidth) {
   
        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        while ((halfHeight / sampleSize) >= reqHeight && (halfWidth / sampleSize) >= reqWidth) {
   
            sampleSize *= 2;
        }
    }

    return sampleSize;
}

//设置inSampleSize参数
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

(4)将inJustDecodeBounds设置为false,加载图片数据

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

完整代码:

public static Bitmap decodeBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) {
   

    BitmapFactory.Options options = new BitmapFactory.Options();
    //先解析图片的宽高信息
    options.inJustDecodeBounds = true;

    BitmapFactory.decodeResource(res, resId, options);

    options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
    //加载压缩后的图片
    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(res, resId, options);

}

图片的缓存

同样的,一般我们加载图片都用的是第三方库,比如著名的Glide,图片缓存的事儿它已经帮我们做得很好了,所以我们不需要考虑缓存的事儿。但是我们还是要大致了解怎么样实现一个图片的缓存功能,以便不时之需。

实现缓存的话常用的就是LRU算法,具体的可以查看LinkedHashMap的源码分析和Glide的内存缓存思路。

这里简单介绍下Glide的内存缓存思路。内存缓存的作用就是对于内存中已经加载的图片避免重复加载。

(1)首先Glide内存缓存采用了2种策略,弱引用缓存和LRU算法内存缓存

(2)弱引用缓存就是把图片的弱引用缓存在一个HashMap中,被下载使用的图片首先会缓存在这个弱引用HashMap中。Glide会通过引用计数的方式来记录图片被引用的次数,当引用次数为0时,也就意味着图片资源不再被使用嘛,这时就会将图片资源从这个弱引用缓存中移除,并把这个图片资源加入到LRU算法内存缓存中

(3)LRU算法内存缓存的原理就是将图片资源用强引用的方式存储在LinkedHashMap中,当达到容量限制时移除最近最少使用的资源。Glide会在LRU缓存中的图片被重新使用时将图片资源从LRU缓存中删除,并添加到弱引用的缓存中去。这样做的原因就是防止图片被LRU算法缓存回收。

核心就是思考使用图片的每一个环节,用最低的开销来满足功能需求


欢迎关注我的公众号AntDream查看更多精彩文章!

目录
相关文章
|
6天前
|
Java Android开发 UED
安卓应用开发中的内存管理优化技巧
在安卓开发的广阔天地里,内存管理是一块让开发者既爱又恨的领域。它如同一位严苛的考官,时刻考验着开发者的智慧与耐心。然而,只要我们掌握了正确的优化技巧,就能够驯服这位考官,让我们的应用在性能和用户体验上更上一层楼。本文将带你走进内存管理的迷宫,用通俗易懂的语言解读那些看似复杂的优化策略,让你的开发之路更加顺畅。
14 2
|
7天前
|
Java Android开发 开发者
安卓应用开发中的线程管理优化技巧
【9月更文挑战第10天】在安卓开发的海洋里,线程管理犹如航行的风帆,掌握好它,能让应用乘风破浪,反之则可能遭遇性能的暗礁。本文将通过浅显易懂的语言和生动的比喻,带你探索如何优雅地处理安卓中的线程问题,从基础的线程创建到高级的线程池运用,让你的应用运行更加流畅。
|
21小时前
|
Android开发 Kotlin
Android经典面试题之Kotlin的==和===有什么区别?
本文介绍了 Kotlin 中 `==` 和 `===` 操作符的区别:`==` 用于比较值是否相等,而 `===` 用于检查对象身份。对于基本类型,两者行为相似;对于对象引用,`==` 比较值相等性,`===` 检查引用是否指向同一实例。此外,还列举了其他常用比较操作符及其应用场景。
147 92
|
4天前
|
监控 算法 数据可视化
深入解析Android应用开发中的高效内存管理策略在移动应用开发领域,Android平台因其开放性和灵活性备受开发者青睐。然而,随之而来的是内存管理的复杂性,这对开发者提出了更高的要求。高效的内存管理不仅能够提升应用的性能,还能有效避免因内存泄漏导致的应用崩溃。本文将探讨Android应用开发中的内存管理问题,并提供一系列实用的优化策略,帮助开发者打造更稳定、更高效的应用。
在Android开发中,内存管理是一个绕不开的话题。良好的内存管理机制不仅可以提高应用的运行效率,还能有效预防内存泄漏和过度消耗,从而延长电池寿命并提升用户体验。本文从Android内存管理的基本原理出发,详细讨论了几种常见的内存管理技巧,包括内存泄漏的检测与修复、内存分配与回收的优化方法,以及如何通过合理的编程习惯减少内存开销。通过对这些内容的阐述,旨在为Android开发者提供一套系统化的内存优化指南,助力开发出更加流畅稳定的应用。
15 0
|
28天前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
29天前
|
Java
【Java基础面试四】、介绍一下Java的数据类型
这篇文章介绍了Java的数据类型,包括8种基本数据类型(整数、浮点、字符、布尔)和3类引用数据类型(数组、类、接口),并提供了基本数据类型所占内存空间和数据范围的详细信息。
|
29天前
|
Java C++
【Java基础面试十七】、Java为什么是单继承,为什么不能多继承?
这篇文章讨论了Java单继承的设计原因,指出Java不支持多继承主要是为了避免方法名冲突等混淆问题,尽管Java类不能直接继承多个父类,但可以通过接口和继承链实现类似多继承的效果。
【Java基础面试十七】、Java为什么是单继承,为什么不能多继承?
|
28天前
|
XML 存储 JSON
【IO面试题 六】、 除了Java自带的序列化之外,你还了解哪些序列化工具?
除了Java自带的序列化,常见的序列化工具还包括JSON(如jackson、gson、fastjson)、Protobuf、Thrift和Avro,各具特点,适用于不同的应用场景和性能需求。
|
28天前
|
Java
【Java基础面试三十七】、说一说Java的异常机制
这篇文章介绍了Java异常机制的三个主要方面:异常处理(使用try、catch、finally语句)、抛出异常(使用throw和throws关键字)、以及异常跟踪栈(异常传播和程序终止时的栈信息输出)。
|
28天前
|
Java
【Java基础面试三十八】、请介绍Java的异常接口
这篇文章介绍了Java的异常体系结构,主要讲述了Throwable作为异常的顶层父类,以及其子类Error和Exception的区别和处理方式。