热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Fresco4种方案教你降低内存使用

目录1、背景2、三级缓存3、内存优化方案3.1、方案一:设置缓存策略3.2、方案二:根据系统内存状态来及时清空缓存内存,防止OO

目录

1、背景

2、三级缓存

3、内存优化方案

3.1、方案一:设置缓存策略

3.2、方案二:根据系统内存状态来及时清空缓存内存,防止OOM

3.2.1、onLowMemory()

3.2.2、onTrimMemory

3.2.3、 OnLowMemory和OnTrimMemory的比较

3.2.4、优化方案代码

3.3、方案三:压缩过大的图片,降低内存消耗

 3.3.1、注意!

3.4、方案四:记录你加载的图片链接,当程序关闭时,主动清除图片缓存




1、背景


Fresco使用,如果列表图片比多,会特别消耗内存,有可能造成OOM,所以必须进行优化。

Fresco适用教程



2、三级缓存


1、 Bitmap缓存---一级缓存

Bitmap缓存存储Bitmap对象,这些Bitmap对象可以立刻用来显示或者用于后处理。在5.0以下系统,Bitmap缓存位于ashmem,这样Bitmap对象的创建和释放将不会引发GC,更少的GC会使你的APP运行得更加流畅。5.0及其以上系统,内存管理有了很大改进,Bitmap缓存直接位于Java的heap上。当应用在后台运行时,该内存会被清空。



2. 未解码图片的内存缓存---二级缓存

这个缓存存储的是原始压缩格式的图片。从该缓存取到的图片在使用之前,需要先进行解码。如果有调整大小,旋转,或者WebP编码转换工作需要完成,这些工作会在解码之前进行。



3. 磁盘缓存(保存到本地)---三级缓存

和未解码的内存缓存相似,磁盘缓存存储的是未解码的原始压缩格式的图片,在使用之前同样需要经过解码等处理。和一二级缓存不一样,磁盘缓存在APP后台运行时,内容是不会被清空的。即使关机也不会。用户可以随时用系统的设置菜单中进行清空缓存操作。



3、内存优化方案


我们在这里将会采用4种优化方案来对大量图片加载时对内存的过度消耗。

方案一:设置缓存策略。

方案二:根据系统内存状态来及时清空缓存内存,防止OOM

方案三:压缩过大的图片,降低内存消耗

方案四:记录你加载的图片链接,当程序关闭时,主动清除图片缓存



3.1、方案一:设置缓存策略


在我们初始化Fresco时,我们可以通过自主设定Fresco的加载参数来控制图片加载占用内存大小。(下边的参数最好根据自己App图片的加载量和内存大小来设置。)

 Fresco.initialize(this,config);


/** 一级缓存参数 config, >=5.0 in java memory, <5.0 in native memeory.*/Supplier memoryCacheConfigL1 = new Supplier() {@Overridepublic MemoryCacheParams get() {return new MemoryCacheParams(/* 已解码图片缓存最大值,以字节为单位 */30 * ByteConstants.MB,/* 已解码缓存图片最大数量 */256,/* 缓存中准备清除但尚未被删除的容器大小(驱逐器) */15 * ByteConstants.MB,/* 驱逐器中的图片数量 */Integer.MAX_VALUE,/* 缓存中单个图片最大值 */Integer.MAX_VALUE);}};/** 二级缓存参数 config, in native memory.*/Supplier memoryCacheConfigL2 = new Supplier() {@Overridepublic MemoryCacheParams get() {return new MemoryCacheParams(/* 未解码图片缓存最大值,以字节为单位 */10 * ByteConstants.MB,/* 未解码缓存图片最大数量 */Integer.MAX_VALUE,/* 缓存中准备清除但尚未被删除的容器大小(驱逐器) */10 * ByteConstants.MB,/* 驱逐器中的图片数量 */Integer.MAX_VALUE,/* 缓存中单个图片最大值 */8 * ByteConstants.MB);}};/***三级缓存--参数*/DiskCacheConfig diskCacheCOnfig= DiskCacheConfig.newBuilder(context).setBaseDirectoryPath(Environment.getExternalStorageDirectory().getAbsoluteFile())// 缓存图片基路径/* 缓存文件夹名 */.setBaseDirectoryName("yo_image")/* 错误缓存的日志记录器 */.setCacheErrorLogger(new GlobalDiskCacheErrorLogger())/* 默认缓存的最大值 */.setMaxCacheSize(100 * ByteConstants.MB)/* 低磁盘空间时,缓存的最大值 */.setMaxCacheSizeOnLowDiskSpace(100 / 2 * ByteConstants.MB)/* 非常低磁盘空间时,缓存的最大值 */.setMaxCacheSizeOnVeryLowDiskSpace(100 / 3 * ByteConstants.MB)/* 磁盘配置的版本 */.setVersion(1).build();ImagePipelineConfig.Builder builder = ImagePipelineConfig.newBuilder(context).setDownsampleEnabled(true)/* 一级缓存配置 */.setBitmapMemoryCacheParamsSupplier(memoryCacheConfigL1)/* 二级缓存配置 */.setEncodedMemoryCacheParamsSupplier(memoryCacheConfigL2)/* 三级缓存配置(磁盘) */.setMainDiskCacheConfig(diskCacheConfig).setBitmapsConfig(bitmapConfig).setMemoryTrimmableRegistry(this);ImagePipelineConfig cOnfig=builder.build();Fresco.initialize(this,config);

3.2、方案二:根据系统内存状态来及时清空缓存内存,防止OOM


在Android的API中有两个方法,可以监听到系统的内存状态。我们可以根据系统的内存状态来主动地释放自身的内存来防止OOM和卡顿的现象。这两个方法分别是onLowMemory& onTrimMemory。



3.2.1、onLowMemory()


OnLowMemory是Android提供的API,在系统内存不足,所有后台程序(优先级为background的进程,不是指后台运行的进程)都被杀死时,系统会调用OnLowMemory。

系统提供的回调有:

  • Application.onLowMemory()
  • Activity.OnLowMemory()
  • Fragement.OnLowMemory()
  • Service.OnLowMemory()
  • ContentProvider.OnLowMemory()

除了上述系统提供的API,还可以自己实现ComponentCallbacks接口,通过API注册,这样也能得到OnLowMemory回调。然后,通过Context.registerComponentCallbacks ()在合适的时候注册回调就可以了。

通过这种自定义的方法,可以在很多地方注册回调,而不需要局限于系统提供的组件。onLowMemory 当后台程序已经终止资源还匮乏时会调用这个方法。好的应用程序一般会在这个方法里面释放一些不必要的资源来应付当后台程序已经终止,前台应用程序内存还不够时的情况。



3.2.2、onTrimMemory


OnTrimMemory是Android 4.0之后提供的API,系统会根据不同的内存状态来回调。系统提供的回调有:

  • Application.onTrimMemory()
  • Activity.onTrimMemory()
  • Fragement.OnTrimMemory()
  • Service.onTrimMemory()
  • ContentProvider.OnTrimMemory()

OnTrimMemory的参数是一个int数值,代表不同的内存状态:

  • TRIM_MEMORY_RUNNING_MODERATE(5):内存不足(后台进程超过5个),并且该进程优先级比较高,需要清理内存
  • TRIM_MEMORY_RUNNING_LOW(10):内存不足(后台进程不足5个),并且该进程优先级比较高,需要清理内存
  • TRIM_MEMORY_RUNNING_CRITICAL(15):内存不足(后台进程不足3个),并且该进程优先级比较高,但如果不是放资源,系统开始杀后台进程,此时app应该清理一些资源
  • TRIM_MEMORY_UI_HIDDEN(20): 你的用户界面不再可见,此时应该释放仅仅使用在UI上的大资源
  • RIM_MEMORY_BACKGROUND(40):系统正处于低内存状态,app进程位于LRU List开始附近,尽管app进程被杀死的概率低,系统可能已经开始杀在LRU List中的后台进程,此时应该释放一些资源,防止被杀的几率。
  • TRIM_MEMORY_MODERATE(60) 系统正处于低内存状态,app进程位于LRU List中部附近,如果系统进一步内存紧张,app进程可能会被杀掉
  • TRIM_MEMORY_COMPLETE(80) 系统正处于低内存状态,app进程是首先被杀进程之一,如果系统现在没有恢复内存,应该立即释放对app不重要的所有内容

Note:当系统开始杀LRU List中进程时,虽然它主要是自下而上,但它同时会考虑哪些进程占用了更多的内存。因此,在LRU List中消耗的内存越少,更可能保留在List中并且快速恢复的机会就越大

系统也提供了一个ComponentCallbacks2,我们可以实现这个接口然后通过Context.registerComponentCallbacks()注册后,就会被系统回调到。



     3.2.3、 OnLowMemory和OnTrimMemory的比较


  1. OnLowMemory被回调时,已经没有后台进程;而onTrimMemory被回调时,还有后台进程。
  2. OnLowMemory是在最后一个后台进程被杀时调用,一般情况是low memory killer 杀进程后触发;而OnTrimMemory的触发更频繁,每次计算进程优先级时,只要满足条件,都会触发。
  3. 通过一键清理后,OnLowMemory不会被触发,而OnTrimMemory会被触发一次。


     3.2.4、优化方案代码

public class BaseApplication extends Application {@Overridepublic void onCreate() {super.onCreate();}/*** OnTrimMemory是Android 4.0之后提供的API,系统会根据不同的内存状态来回调。*/@Overridepublic void onTrimMemory(int level) {super.onTrimMemory(level);if (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE) { // 60ImagePipelineFactory.getInstance().getImagePipeline().clearMemoryCaches();}}/*** OnLowMemory是Android提供的API,在系统内存不足,所有后台程序* (优先级为background的进程,不是指后台运行的进程)都被杀死时,系统会调用OnLowMemory。*/@Overridepublic void onLowMemory() {super.onLowMemory();ImagePipelineFactory.getInstance().getImagePipeline().clearMemoryCaches();}
}

3.3、方案三:压缩过大的图片,降低内存消耗


public static void setImageURI(String url,SimpleDraweeView simpleDraweeView, int width, int height) {Uri uri = (url != null) ? Uri.parse(url) : null;ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri).setResizeOptions(new ResizeOptions(width, height)).build();DraweeController cOntroller= Fresco.newDraweeControllerBuilder().setUri(uri).setAutoPlayAnimations(true).setOldController(simpleDraweeView.getController()).setImageRequest(request).build();simpleDraweeView.setController(controller); }

       3.3.1、注意!


 当你适用new ResizeOptions(width, height) 来压缩图片尺寸的时候,这个方法是有限制的:只支持JPG格式的图片。



那么我们怎么来支持更多的格式呢?我们需要在初始化ImagePipelineConfig的时候,setDownsampleEnabled(true)就可以了。上面我们的方案一里边有代码。


 


3.4、方案四:记录你加载的图片链接,当程序关闭时,主动清除图片缓存

我们在加载图片的Adapter中创建一个存储图片url的数组。

protected Set picCacheUris = null;//图片加载链接

在adapter加载图片的时候保存这些url:

 protected void tryAddToCacheUrls(String url) {if (!picCacheUris.contains(url + "")) picCacheUris.add(url + "");}

然后在页面关闭或者退出等必要时候手动清除内存:

@Overridepublic void onDestroy() {super.onDestroy();tryClearMemoryCache();}protected void tryClearMemoryCache() {if (picCacheUris != null && picCacheUris.size() > 0) {evictFromMemoryCache(picCacheUris);picCacheUris.clear();picCacheUris = null;} protected void evictFromDiskCache( Set picCacheUris){if(picCacheUris!=null) {for (String url : picCacheUris) {try {Uri uri = Uri.parse(url + "");Fresco.getImagePipeline().evictFromMemoryCache(uri);} catch (Exception e) {}}}}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


推荐阅读
  • 计算机视觉领域介绍 | 自然语言驱动的跨模态行人重识别前沿技术综述(上篇)
    本文介绍了计算机视觉领域的最新进展,特别是自然语言驱动的跨模态行人重识别技术。上篇内容详细探讨了该领域的基础理论、关键技术及当前的研究热点,为读者提供了全面的概述。 ... [详细]
  • 在处理大图片时,PHP 常常会遇到内存溢出的问题。为了避免这种情况,建议避免使用 `setImageBitmap`、`setImageResource` 或 `BitmapFactory.decodeResource` 等方法直接加载大图。这些函数在处理大图片时会消耗大量内存,导致应用崩溃。推荐采用分块处理、图像压缩和缓存机制等策略,以优化内存使用并提高处理效率。此外,可以考虑使用第三方库如 ImageMagick 或 GD 库来处理大图片,这些库提供了更高效的内存管理和图像处理功能。 ... [详细]
  • 如何使用 net.sf.extjwnl.data.Word 类及其代码示例详解 ... [详细]
  • 在《Cocos2d-x学习笔记:基础概念解析与内存管理机制深入探讨》中,详细介绍了Cocos2d-x的基础概念,并深入分析了其内存管理机制。特别是针对Boost库引入的智能指针管理方法进行了详细的讲解,例如在处理鱼的运动过程中,可以通过编写自定义函数来动态计算角度变化,利用CallFunc回调机制实现高效的游戏逻辑控制。此外,文章还探讨了如何通过智能指针优化资源管理和避免内存泄漏,为开发者提供了实用的编程技巧和最佳实践。 ... [详细]
  • 您的数据库配置是否安全?DBSAT工具助您一臂之力!
    本文探讨了Oracle提供的免费工具DBSAT,该工具能够有效协助用户检测和优化数据库配置的安全性。通过全面的分析和报告,DBSAT帮助用户识别潜在的安全漏洞,并提供针对性的改进建议,确保数据库系统的稳定性和安全性。 ... [详细]
  • 如何将TS文件转换为M3U8直播流:HLS与M3U8格式详解
    在视频传输领域,MP4虽然常见,但在直播场景中直接使用MP4格式存在诸多问题。例如,MP4文件的头部信息(如ftyp、moov)较大,导致初始加载时间较长,影响用户体验。相比之下,HLS(HTTP Live Streaming)协议及其M3U8格式更具优势。HLS通过将视频切分成多个小片段,并生成一个M3U8播放列表文件,实现低延迟和高稳定性。本文详细介绍了如何将TS文件转换为M3U8直播流,包括技术原理和具体操作步骤,帮助读者更好地理解和应用这一技术。 ... [详细]
  • V8不仅是一款著名的八缸发动机,广泛应用于道奇Charger、宾利Continental GT和BossHoss摩托车中。自2008年以来,作为Chromium项目的一部分,V8 JavaScript引擎在性能优化和技术创新方面取得了显著进展。该引擎通过先进的编译技术和高效的垃圾回收机制,显著提升了JavaScript的执行效率,为现代Web应用提供了强大的支持。持续的优化和创新使得V8在处理复杂计算和大规模数据时表现更加出色,成为众多开发者和企业的首选。 ... [详细]
  • 在 Linux 环境下,多线程编程是实现高效并发处理的重要技术。本文通过具体的实战案例,详细分析了多线程编程的关键技术和常见问题。文章首先介绍了多线程的基本概念和创建方法,然后通过实例代码展示了如何使用 pthreads 库进行线程同步和通信。此外,还探讨了多线程程序中的性能优化技巧和调试方法,为开发者提供了宝贵的实践经验。 ... [详细]
  • REST与RPC:选择哪种API架构风格?
    在探讨REST与RPC这两种API架构风格的选择时,本文首先介绍了RPC(远程过程调用)的概念。RPC允许客户端通过网络调用远程服务器上的函数或方法,从而实现分布式系统的功能调用。相比之下,REST(Representational State Transfer)则基于资源的交互模型,通过HTTP协议进行数据传输和操作。本文将详细分析两种架构风格的特点、适用场景及其优缺点,帮助开发者根据具体需求做出合适的选择。 ... [详细]
  • 手指触控|Android电容屏幕驱动调试指南
    手指触控|Android电容屏幕驱动调试指南 ... [详细]
  • 并发编程入门:初探多任务处理技术
    并发编程入门:探索多任务处理技术并发编程是指在单个处理器上高效地管理多个任务的执行过程。其核心在于通过合理分配和协调任务,提高系统的整体性能。主要应用场景包括:1) 将复杂任务分解为多个子任务,并分配给不同的线程,实现并行处理;2) 通过同步机制确保线程间协调一致,避免资源竞争和数据不一致问题。此外,理解并发编程还涉及锁机制、线程池和异步编程等关键技术。 ... [详细]
  • 在前文探讨了Spring如何为特定的bean选择合适的通知器后,本文将进一步深入分析Spring AOP框架中代理对象的生成机制。具体而言,我们将详细解析如何通过代理技术将通知器(Advisor)中包含的通知(Advice)应用到目标bean上,以实现切面编程的核心功能。 ... [详细]
  • 投融资周报 | Circle 达成 4 亿美元融资协议,唯一艺术平台 A 轮融资超千万美元 ... [详细]
  • Java中高级工程师面试必备:JVM核心知识点全面解析
    对于软件开发人员而言,随着技术框架的不断演进和成熟,许多高级功能已经被高度封装,使得初级开发者只需掌握基本用法即可迅速完成项目。然而,对于中高级工程师而言,深入了解Java虚拟机(JVM)的核心知识点是必不可少的。这不仅有助于优化性能和解决复杂问题,还能在面试中脱颖而出。本文将全面解析JVM的关键概念和技术细节,帮助读者全面提升技术水平。 ... [详细]
  • C++ 进阶:类的内存布局与虚函数类的实现细节
    C++ 进阶:类的内存布局与虚函数类的实现细节 ... [详细]
author-avatar
圣友家具简章da
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有