当前位置: 首页 > news >正文

glide性能优化实战

glide性能优化实战

前言

项目使用glide加载图片之前也只是会基本api,这次项目有非常多的图片需要展示,而且设备是一个android12的版本,但是性能不太理想,分给APP的资源不太多,所以需要优化现有图片加载逻辑,读者可以根据自己的项目自行选择优化项。

关于Glide的简单介绍

Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的API,高性能、可扩展的图片解码管道(decode pipeline),以及自动的资源池技术。

Glide 支持拉取,解码和展示视频快照,图片,和GIF动画。Glide的Api是如此的灵活,开发者甚至可以插入和替换成自己喜爱的任何网络栈。默认情况下,Glide使用的是一个定制化的基于HttpUrlConnection的栈,但同时也提供了与Google Volley和Square OkHttp快速集成的工具库。

虽然Glide 的主要目标是让任何形式的图片列表的滚动尽可能地变得更快、更平滑,但实际上,Glide几乎能满足你对远程图片的拉取/缩放/显示的一切需求。

API

Glide 使用简明的流式语法API,这是一个非常棒的设计,因为它允许你在大部分情况下一行代码搞定需求:

Glide.with(context).load(url).into(imageView);

性能

Glide 充分考虑了Android图片加载性能的两个关键方面:

  • 图片解码速度
  • 解码图片带来的资源压力
    为了让用户拥有良好的App使用体验,图片不仅要快速加载,而且还不能因为过多的主线程I/O或频繁的垃圾回收导致页面的闪烁和抖动现象。

Glide使用了多个步骤来确保在Android上加载图片尽可能的快速和平滑:

  • 自动、智能地下采样(downsampling)和缓存(caching),以最小化存储开销和解码次数;
  • 积极的资源重用,例如字节数组和Bitmap,以最小化昂贵的垃圾回收和堆碎片影响;
  • 深度的生命周期集成,以确保仅优先处理活跃的Fragment和Activity的请求,并有利于应用在必要时释放资源以避免在后台时被杀掉。

关于Glide的初步优化

上面都是官网的介绍,下面我们进行初步的一个优化。

缓存策略

首先是图片的缓存策略。几个可配置的缓存策略属性在DiskCacheStrategy类中都有介绍

  • NONE 不使用缓存,每次都重新加载

  • DATA 在解码之前,将检索到的数据直接写入磁盘缓存。

  • RESOURCE 在解码后,再将检索到的数据写入磁盘缓存。

  • AUTOMATIC 尝试根据DataFetcher和EncodeStrategy中的ResourceEncoder(如果ResourceEncoder可用的话)的数据源智能地选择策略。

  • ALL 如果是远程数据使用DATA和RESOURCE缓存,如果是本地数据使用RESOURCE缓冲。

项目加载的都是本地图片,所以在加载速度和缓存大小的权衡下,使用了RESOURCE

...
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
...

图片裁剪

因为缓存大小跟图片大小是有直接关系的,所以加载前最好将其裁剪为和控件大小一致,避免过大的图片造成ANR和Out Of Memory

...
.override(your size)
...

移除加载动画

Glide为了保证图片加载的过度流畅性,不显得突兀,是有默认的动画和变换的,但这也会消耗一定的性能,所以我们将它关闭

...
.dontAnimate()
.dontTransform()
...

其他

(可选)如果需要在加载过程中对图片进行处理,可以使用RequestListener

初步结果

都加上过后大概是这个样子

Glide.with(context).load(url).override(your size).dontAnimate().dontTransform().diskCacheStrategy(DiskCacheStrategy.RESOURCE).into(imageView);

可以从Profiler中看到加载一个list的图片时,内存和CPU都有下降。

关于Glide的AppGlideModule定制

在新版Glide中,可以通过自定义AppGlideModule来全局定义glide的设置

import android.content.Context
import com.bumptech.glide.Glide
import com.bumptech.glide.GlideBuilder
import com.bumptech.glide.Registry
import com.bumptech.glide.annotation.GlideModule
import com.bumptech.glide.load.DecodeFormat
import com.bumptech.glide.load.engine.bitmap_recycle.LruArrayPool
import com.bumptech.glide.load.engine.bitmap_recycle.LruBitmapPool
import com.bumptech.glide.load.engine.cache.DiskLruCacheWrapper
import com.bumptech.glide.load.engine.cache.LruResourceCache
import com.bumptech.glide.load.engine.cache.MemorySizeCalculator
import com.bumptech.glide.load.engine.executor.GlideExecutor
import com.bumptech.glide.module.AppGlideModule
import com.bumptech.glide.request.RequestOptions
import com.fawvw.hmi.media.common.utils.LogUtil
import java.io.File@GlideModule
class MyAppGlideModule : AppGlideModule() {private val TAG = "MyAppGlideModule"//图片文件缓存 10Mprivate var IMAGE_CACHE_COUNT = 10 * 1024 * 1024private val SOURCE_EXECUTOR_NAME = "source"private val ANIMATION_EXECUTOR_NAME = "animation"override fun applyOptions(context: Context, builder: GlideBuilder) {super.applyOptions(context, builder)val calculator = MemorySizeCalculator.Builder(context).build()val defaultMemoryCacheSize = calculator.memoryCacheSizeval defaultBitmapPoolSize = calculator.bitmapPoolSizeval defaultArrayPoolSize = calculator.arrayPoolSizeInBytesLogUtil.d(TAG,"defaultMemoryCacheSize: $defaultMemoryCacheSize, defaultBitmapPoolSize: $defaultBitmapPoolSize, defaultArrayPoolSize: $defaultArrayPoolSize")builder.setDefaultRequestOptions(RequestOptions().format(DecodeFormat.PREFER_RGB_565))val cacheLocation = File(context.externalCacheDir, "GlideCache")if (!cacheLocation.exists()) {cacheLocation.mkdirs()}//设置glide文件缓存为10Mbuilder.setDiskCache {DiskLruCacheWrapper.create(cacheLocation, IMAGE_CACHE_COUNT.toLong())}//设置glide内存,bitmap池,数组池砍builder.setMemoryCache(LruResourceCache((defaultMemoryCacheSize / 4).toLong()))builder.setBitmapPool(LruBitmapPool((defaultBitmapPoolSize / 4).toLong()))builder.setArrayPool(LruArrayPool(defaultArrayPoolSize / 4))//设置Source线程最大数量为1builder.setSourceExecutor(GlideExecutor.newSourceBuilder().setThreadCount(1).setName(SOURCE_EXECUTOR_NAME).build())//设置Animation线程最大数量为1builder.setAnimationExecutor(GlideExecutor.newAnimationBuilder().setThreadCount(1).setName(ANIMATION_EXECUTOR_NAME).build())}override fun registerComponents(context: Context, glide: Glide, registry: Registry) {super.registerComponents(context, glide, registry)}
}

编译过后,就可以调用GlideApp了,用于将Glide替换掉,注意别忘了添加@GlideModule注解。

总结

在进行了上面的两个定制过后,CPU和内存都有明显的下降,但是有些配置确实会导致加载速度变慢和用户体验变差,需要自己权衡。

相关文章:

glide性能优化实战

glide性能优化实战 前言 项目使用glide加载图片之前也只是会基本api,这次项目有非常多的图片需要展示,而且设备是一个android12的版本,但是性能不太理想,分给APP的资源不太多,所以需要优化现有图片加载逻辑,读者可以…...

Python 环境搭建和安装(保姆级教程)

本章节我们将向大家介绍如何在本地搭建Python开发环境。 Python可应用于多平台包括 Linux 和 Mac OS X。 你可以通过终端窗口输入 "python" 命令来查看本地是否已经安装Python以及Python的安装版本。 Unix (Solaris, Linux, FreeBSD, AIX, HP/UX, SunOS, IRIX, 等…...

Java并发编程(二):同步机制与多线程是否矛盾

同步机制与多线程是否矛盾 0 纠正对异步和多选误解1 概述2 为什么要引入同步机制3 为什么多线程依然有意义3 总结 大家好,我是欧阳方超,可以关注我的公众号“欧阳方超”,后续内容将在公众号首发。 0 纠正对异步和多选误解 行文之前先纠正一下…...

golang分布式缓存项目 Day2 单机并发缓存

注:该项目原作者:https://geektutu.com/post/geecache-day1.html。本文旨在记录本人做该项目时的一些疑惑解答以及部分的测试样例以便于本人复习。 支持并发读写 接下来我们使用 sync.Mutex 封装 LRU 的几个方法,使之支持并发的读写。在这之…...

一个百度、必应搜索引擎图片获取下载的工具包

前言:前段时间需要一大批图片,跑去百度搜图下载,发现特别麻烦,于是用了一天时间写了一个工具库,方便后续使用,这里分享给大家 imagecapture 是一个用 Go 语言编写的库,旨在从百度和必应等搜索引…...

安全见闻(网络安全篇)

笔记仅供学习,切勿触碰法律红线! 以下笔记学习来自B站泷羽Sec:https://space.bilibili.com/350329294?spm_id_from333.337.search-card.all.click 如涉及侵权马上删除文章 1.编程语言 C语言:一种通用的、面向过程的编程语言&am…...

手写一些方法

模拟new方法 function Otaku(name,age) {this.name name;this.age age; this.habit Games}Otaku.prototype.strength 60;Otaku.prototype.sayName function () {console.log("I am " this.name);};function myNew(fn, ...args) {const obj Object.create(f…...

仅需三步!用AI工具免费打造10w+抖音爆款烟火秀视频教程

抖音上的烟火秀视频总能唤起人们对节日的温馨回忆,它们不仅视觉效果震撼,还自带流量属性。我自己在刷到这类视频时,也不禁回想起童年放烟花的快乐时光,那种浓厚的年味让人怀念。这些视频通常伴随着合适的音乐,能够迅速…...

基于redis实现API接口访问次数限制

一,概述 日常开发中会有一个常见的需求,需要限制接口在单位时间内的访问次数,比如说某个免费的接口限制单个IP一分钟内只能访问5次。该怎么实现呢,通常大家都会想到用redis,确实通过redis可以实现这个功能&#xff0c…...

[ Linux 命令基础 3 ] Linux 命令详解-文件和目录管理命令

🍬 博主介绍 👨‍🎓 博主介绍:大家好,我是 _PowerShell ,很高兴认识大家~ ✨主攻领域:【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 🎉点赞➕评论➕收藏 养成习…...

npm i 的时候报错: npm ERR! Error: EPERM: operation not permitted, rename

文章目录 噩梦解决办法总结 噩梦 最近改漏洞,这个项目删掉了 node_modules文件夹 重新安装依赖,结果安装一半的时候就一直报这个错。 然后查了很多方法,基本都是下面这些: 权限不够,以管理员运行cmd重新安装。清除 n…...

如何迁移剪映源文件

1、打开剪映,打开全局设置 2、查看草稿位置。把要迁移的文件拷贝到这个路径下面。 3、关闭文件,返回上一层界面,可以看到拷贝到目录下的文件。...

Go语言中的`io.Copy`函数:高效的数据复制解决方案

在Go语言中,io.Copy函数是一个强大而高效的工具,用于将数据从一个io.Reader复制到一个io.Writer。这篇文章将深入探讨io.Copy函数的工作原理、使用方法及其在实际应用中的优势。无论您是后端开发人员还是对Go语言感兴趣的程序员,这篇文章都将…...

datastage在升级版本到11.7之后,部分在11.3上正常执行的SP报错SQLSTATE = 22007: 本机错误代码 = -180

在升级版本到11.7之后,部分在11.3上正常执行的SP开始报错,报的SQL错误是时间参数问题,但是一样的SP可以直接call sp执行,也可以手动调用作业执行,只有设置定时调度时作业会报错, CALLXXX.XXX(1,CURRENT TIM…...

docker——项目部署

什么是Docker? Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可抑制的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。容器完全使用沙盒机制,相互之间不会存在任何接口。几…...

设计模式(Unity)——更新中

设计模式 文章目录 设计模式工厂模式创建方法(Create Methods)简单工厂(Simple Factory)工厂方法(Method Factory)抽象工厂(Abstract Factroy) 策略模式 工厂模式 创建方法&#xf…...

小程序中引入下载到本地的iconfont字体图标加载不出来问题解决

我这个是uniapp项目,字体图标都是一样的,在vue项目中web端、uniapp运行到h5都没问题,但是运行到小程序加载不出来,报错如下: 不让用本地路径,所以我们要转为base64编码,这里给大家提供一个工具,它可以把本地字体文件转为base64:transfonter 进入官网后,第一步: …...

百度富文本禁止编辑

<script type"text/javascript">$(function () {editorcontent new baidu.editor.ui.Editor();editorcontent.render(authentication);//禁用代码editorcontent.ready(function () {editorcontent.setDisabled();});try {editorcontent.sync();} catch (err) …...

C++开发基础之使用librabbitmq库实现RabbitMQ消息队列通信

1. 前言 RabbitMQ是一个流行的开源消息队列系统&#xff0c;支持多种消息协议&#xff0c;广泛用于构建分布式系统和微服务架构。可以在不同应用程序之间实现异步消息传递。在本文中&#xff0c;我们将熟悉如何使用C与RabbitMQ进行消息通信。 2. 准备工作 在 Windows 平台上…...

头歌网络安全(11.12)

头歌禁止复制解决 必须先下篡改猴&#xff01;&#xff01;&#xff01;&#xff01; 头歌复制助手 Educoder Copy Helperhttps://scriptcat.org/zh-CN/script-show-page/1860 Java生成验证码 第1关&#xff1a;使用Servlet生成验证码 任务描述 本关任务&#xff1a;使用se…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...

4. TypeScript 类型推断与类型组合

一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式&#xff0c;自动确定它们的类型。 这一特性减少了显式类型注解的需要&#xff0c;在保持类型安全的同时简化了代码。通过分析上下文和初始值&#xff0c;TypeSc…...

windows系统MySQL安装文档

概览&#xff1a;本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容&#xff0c;为学习者提供全面的操作指导。关键要点包括&#xff1a; 解压 &#xff1a;下载完成后解压压缩包&#xff0c;得到MySQL 8.…...