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

Glide的使用及源码分析

前言

依赖

implementation 'com.github.bumptech.glide:glide:4.16.0'

github: GitHub - bumptech/glide: An image loading and caching library for Android focused on smooth scrolling

基本使用

//加载url
Glide.with(this)
.load(url)
.placeholder(R.drawable.placeholder)
.error(R.drawable.error)
.into(imageView)//加载本地drawable资源
Glide.with(this)
.load(R.mipmap.ic_launcher)
.into(imageView)//加载gif,Glide会智能判断
Glide.with(this)
.load(R.drawable.a)
.into(imageView)//asBitmap只加载静态图片,如果图片为gif则加载第一帧
Glide.with(this)
.asBitmap()
.load(R.drawable.a)
.into(imageView)//后备回调符
Glide.with(this)
.load(url)
.fallback(R.mipmap.ic_launcher) //当url为null时显示
.into(imageView)

 RequestOptions

Glide的配置都可以通过RequestOptions配置,用于提取公共属性,复用。

RequestOptions options = new RequestOptions().placeholder(R.drawable.ic_launcher_background).error(R.drawable.ic_launcher_foreground).fallback(R.mipmap.ic_launcher);Glide.with(this).load(URL).apply(options).into(view);

设置图片大小

宽高单位是px

Glide.with(this).load(URL).override(100,100).into(view);

设置缩略图

RequestBuilder<Drawable> requestBuilder= Glide.with(this).asDrawable().sizeMultiplier(0.5f);//显示原图的50%
Glide.with(this).load(URL).thumbnail(requestBuilder).into(view);

先加载缩略图,再加载原图

//先加载缩略图,再加载原图
RequestBuilder<Drawable> requestBuilder1= Glide.with(this).load(URL1);Glide.with(this).load(URL).diskCacheStrategy(DiskCacheStrategy.NONE).thumbnail(requestBuilder1).into(view);

缓存设置

Glide默认开启内存缓存和硬盘缓存

禁用缓存策略

Glide.with(this).load(URL).skipMemoryCache(true).into(view);

硬盘缓存策略

  • DiskCacheStrategy.NONE //不开启硬盘缓存
  • DiskCacheStrategy.DATA //只缓存原始图片
  • DiskCacheStrategy.RESOURCE //只缓存转换后的图片
  • DiskCacheStrategy.ALL //同时缓存原始图片和转换后图片
  • DiskCacheStrategy.AUTOMATIC //智能模式,Glide根据图片资源选择模式
  Glide.with(this).load(URL).diskCacheStrategy(DiskCacheStrategy.NONE).into(view);

预加载

  Glide.with(this).load(URL).preload();

文件下载

        new Thread(() -> {FutureTarget<File> target =  Glide.with(MainActivity.this).asFile().load(URL).submit();try {File image =  target.get();File file = new File(getCacheDir(),"file.png");image.compareTo(file);} catch (ExecutionException | InterruptedException e) {throw new RuntimeException(e);}}).start();

图片裁剪

Glide.with(this)
.load(url)
//.centerCrop() //居中剪裁
//.fitCenter() // 默认
.circleCrop() //圆形图片
.into(imageView)

过渡动画

 //过渡动画
Glide.with(this).load(URL).diskCacheStrategy(DiskCacheStrategy.NONE).transition(withCrossFade(1000)) //默认为300ms.into(view);

可以自定义动画

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"android:duration="2000"android:fromAlpha="0"android:toAlpha="1" />
Glide.with(this).load(URL).diskCacheStrategy(DiskCacheStrategy.NONE).transition(GenericTransitionOptions.with(R.anim.anim_alpha)).into(view)


源码分析

with

 RequestManager requestManager = Glide.with(this);

load

RequestBuilder<Drawable> load = requestManager.load(URL);

into

CustomViewTarget<ImageView, Drawable> target = new CustomViewTarget<ImageView, Drawable>(view) {@Overrideprotected void onResourceCleared(@Nullable Drawable placeholder) {Log.e(TAG, "资源清理");}@Overridepublic void onLoadFailed(@Nullable Drawable errorDrawable) {Log.e(TAG, "加载失败");}@Overridepublic void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {Log.e(TAG, "加载成功");}};CustomViewTarget<ImageView, Drawable> into = load.into(target);

1:RequestBuilder.java

->into

->return into( glideContext.buildImageViewTarget(view, transcodeClass), /* targetListener= */ null, requestOptions, Executors.mainThreadExecutor()); //构造一个ImageViewTarget

->Request request = buildRequest(target, targetListener, options, callbackExecutor); //构造一个请求,接口实现SingleRequest

2:RequestManager.java

->requestManager.track(target, request);

3:RequestTracker.java

->requestTracker.runRequest(request);//两个set集合添加request请求

->request.begin();

4:SingleRequest.java

 ->onSizeReady(overrideWidth, overrideHeight);

5:Engine.java

->memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);//三级缓存

->EngineResource<?> active = loadFromActiveResources(key); //一级缓存活动--运行时缓存

->EngineResource<?> cached = loadFromCache(key); //二级缓存Cache--运行时缓存

->waitForExistingOrStartNewJob

->jobs.get(key, onlyRetrieveFromCache)////三级缓存磁盘-非运行时缓存

6:EngineJob.java

如果缓存里都没有,去请求

->engineJob.start(decodeJob);

7:DecodeJob.java

->run()

->runWrapped()

->case INITIALIZE:

stage = getNextStage(Stage.INITIALIZE);

currentGenerator = getNextGenerator();

runGenerators();

->currentGenerator.startNext()

8:SourceGenerator.java

->startNext()

9:DecodeHelper.java

->loadData = helper.getLoadData().get(loadDataListIndex++);

-> glideContext.getRegistry().getModelLoaders(model)  //这里会取注册的Loaders

10:ModelLoader.java

->LoadData<?> current = modelLoader.buildLoadData(model, width, height, options);

11:HttpGlideUrlLoader.java

->buildLoadData

->return new LoadData<>(url, new HttpUrlFetcher(url, timeout));

12:HttpUrlFetcher.java

->loadData

->loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders()); //发起HttpUrlConnect请求

->getStreamForSuccessfulRequest;//获得InputStream

->stream = ContentLengthInputStream.obtain(urlConnection.getInputStream(), contentLength);//会对InputSteam做一系列的优化,压缩,防止过大导致崩溃

……

->InputStream会转成Bitmap

……

最终回调到CustomViewTarget.onResourceReady

也就是

贴上完整的时序图

Glide生命周期

Glide之所以如此灵活,无须对用户的Activity或Fragment进行管理,避免内存泄漏,在于空白的父类SupportRequestManagerFragment,通过jetpack的lifecycle进行管理。

面试总结

1:在子线程使用Glide.with函数,会发生什么?

答:Glide.with在子线程里不会添加生命周期,在主线程才会添加一个FragmentActivity,绑定使用的Activity生命周期

2:项目中大量使用Glide,会造成内存泄漏问题,请问如何避免?

答:通过Glide.with()传入的对象,尽量是包含能自动回收的Activity等包含生命周期的作用域,避免使用Application这种,造成无法回收现象。

3:使用Glide为什么要加入网络权限?

<uses-permission android:name="android.permission.INTERNET" />

答:因为内部会有HttpURLConnection请求,在执行Request事务后,会先从活动缓存取,如果没有,再去内存缓存,再去磁盘缓存,然后通过HttpUrlFetcher发起HttpURLConnection请求,所有需要网络权限

4:Glide源码里面的缓存,为什么要有 活动缓存 还需要 有内存缓存?或者为什么设计三层缓存?

答:简单来说,一级缓存采用LRU算法,最新最少使用的图片,当请求队列有新的图片时候,会淘汰掉最新最少使用的图片,如果这张图片后面还需要页面展示,那么就会有产生效率问题,因此再增加了一层不采用LRU的内存缓存。

http://www.lryc.cn/news/152026.html

相关文章:

  • 外贸爬虫系统
  • CentOS 8 安装 Code Igniter 4
  • .net framework 提示安装了 但是删除面板看不到
  • flask-smorest 库
  • android WindowManager的简单使用
  • Spark_Spark比mapreduce快的原因
  • el-upload调用内部方法删除文件
  • 无涯教程-JavaScript - CUBEKPIMEMBER函数
  • 代码随想录Day_52打卡
  • 692. 前K个高频单词
  • 介绍 Docker 的基本概念和优势,以及在应用程序开发中的实际应用
  • C++:构建一个二叉树的代码
  • iOS 设置下载部分文件,如何获取完整文件的大小
  • 如何助力金融贷款企业实现精准营销获客
  • html中的换行(\n)或回车(\r)符号不起作用的解决办法、br、white、space、pre、line
  • SpringBoot+MyBatisPlus+MySql+vue2+elementUi的案例、java访问数据库服务、java提供接口服务
  • 设计模式入门(二)观察者模式
  • 列化复杂的xml对应的类
  • 什么是软件开发生命周期(SDLC)?
  • 计算机视觉中常用的角点检测算法及其作用
  • css3英文文字换行,超过两行...展示
  • 查各种金属非金属材料的物性参数方法
  • 【数据库】查询PostgreSQL中所有表逻辑外键
  • 【Kubernetes理论篇】2023年最新CKA考题+解析
  • 【Linux】目录结构、路径
  • Java-集合框架-List,Set,Map,队列
  • 第一章_线程基础知识
  • linux(centos7)定时关机解决方案
  • reactnative笔记
  • 软件架构模式+系统架构