android系统源码阅读笔记|Glide内存占用优化

Glide内存占用优化
近期项目中选用glide作为图片加载工具,布局采用NestedScrollView嵌套RecyclerView实现,recycleview中的条目有张图片,通过glide添加,RecyclerView不断下滑不断加载更多item,随着recycleview中的item数量的不断增加,应用内存不断增长直至最后OOM退出
查找发现内存暴涨是因为recyvleview中的item条目数量太多,每个条目都持有一个bitmap占用了大量内存,要想内存保持不暴涨,必须做到及时回收item中的bitmap,在adapter中重写item回收方法:

@Override public void onViewRecycled(@NonNull BaseViewHolder holder) { MyLog.e(TAG,"onViewRecycled"); ImageView imageView = holder.itemView.findViewById(R.id.goods_img); if(imageView!=null) { imageView.setImageDrawable(null); Glide.with(imageView.getContext()).clear(imageView); } super.onViewRecycled(holder); }

发现onViewRecycled有调用,但是调用的次数非常少,相对于大量的添加item来说,这点回收无济于事,通过网络查找发现NestedScrollView+RecyclerView的使用方式会导致RecyclerView不复用item,所以修改代码结构,将NestedScrollView+Recycleview的形式改为单独recycleview,之前在NestedScrollView中的其他子view添加到recycleview中,添加方法类似添加header、footer,这样RecyclerView的复用功能就能正常使用,修改后发现onViewRecycled方法调用非常频繁,内存很好的控住住了,没有出现暴涨。
随后继续针对glide添加优化,使用glide提供的全局设置进步一降低缓存池大小和图片质量,glide全局配置使用如下:
添加module类:
public class CouponModule implements GlideModule {private static final String TAG = "CouponModule"; @Override public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) { MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(CouponApplication.getContext()).build(); int defaultMemoryCacheSize = calculator.getMemoryCacheSize(); int defaultBitmapPoolSize = calculator.getBitmapPoolSize(); int defaultArrayPoolSize = calculator.getArrayPoolSizeInBytes(); builder.setDefaultRequestOptions( new RequestOptions() .format(DecodeFormat.PREFER_RGB_565)); builder.setMemoryCache(new LruResourceCache(defaultMemoryCacheSize/2)); builder.setBitmapPool(new LruBitmapPool(defaultBitmapPoolSize/2)); builder.setArrayPool(new LruArrayPool(defaultArrayPoolSize/2)); }@Override public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {} }

【android系统源码阅读笔记|Glide内存占用优化】manifest文件添加meta-data信息:

混淆脚本修改:
#glide module混淆 #-keep public class * implements com.bumptech.glide.module.GlideModule -keep public class com.android.hshq.coupon.CouponModule # for DexGuard only #-keepresourcexmlelements manifest/application/meta-data@value=https://www.it610.com/article/GlideModule

更多内容查看wiki:https://github.com/bumptech/glide/wiki/Configuration
在全局设置中将图片质量设置为565,如果遇到显示gif文件的时候,会出现gif图片周边出现黑框的问题,需要在加载图片时候,单独针对gif结尾的url将图片质量改回8888
public static void display(Context context, String url, ImageView imageView) { RequestOptions options = new RequestOptions() .centerCrop() .placeholder(R.drawable.ic_refresh_loading) .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC) .error(R.drawable.ic_refresh_bad_net); if(!TextUtils.isEmpty(url) && url.endsWith(".gif")) { options.format(DecodeFormat.PREFER_ARGB_8888); } Glide.with(context) .load(url) .apply(options) .into(imageView); }

glide总体来说使用非常方便,不需要从布局层面开始修改,gif图片自动播放,但是在内存回收方面不及fresco,fresco会在图片不可见的情况下主动回收内存,中途本也考虑过将glide替换为fresco,但最终测试结果发现添加主动回收操作以及限制图片质量后占用内存与使用fresco的情况下差不多,就没有替换为fresco。
在以后遇到巨量图片加载任务的项目中,我想我会首选使用fresco作为图片加载工具使用。

    推荐阅读