• 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

    基本使用

    1. //加载url
    2. Glide.with(this)
    3. .load(url)
    4. .placeholder(R.drawable.placeholder)
    5. .error(R.drawable.error)
    6. .into(imageView)
    7. //加载本地drawable资源
    8. Glide.with(this)
    9. .load(R.mipmap.ic_launcher)
    10. .into(imageView)
    11. //加载gif,Glide会智能判断
    12. Glide.with(this)
    13. .load(R.drawable.a)
    14. .into(imageView)
    15. //asBitmap只加载静态图片,如果图片为gif则加载第一帧
    16. Glide.with(this)
    17. .asBitmap()
    18. .load(R.drawable.a)
    19. .into(imageView)
    20. //后备回调符
    21. Glide.with(this)
    22. .load(url)
    23. .fallback(R.mipmap.ic_launcher) //当url为null时显示
    24. .into(imageView)

     RequestOptions

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

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

    设置图片大小

    宽高单位是px

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

    设置缩略图

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

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

    1. //先加载缩略图,再加载原图
    2. RequestBuilder requestBuilder1= Glide.with(this).load(URL1);
    3. Glide.with(this).load(URL).diskCacheStrategy(DiskCacheStrategy.NONE)
    4. .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();

    文件下载

    1. new Thread(() -> {
    2. FutureTarget target = Glide.with(MainActivity.this).asFile().load(URL).submit();
    3. try {
    4. File image = target.get();
    5. File file = new File(getCacheDir(),"file.png");
    6. image.compareTo(file);
    7. } catch (ExecutionException | InterruptedException e) {
    8. throw new RuntimeException(e);
    9. }
    10. }).start();

    图片裁剪

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

    过渡动画

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

    可以自定义动画

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


    源码分析

    with
     RequestManager requestManager = Glide.with(this);

    load
    RequestBuilder load = requestManager.load(URL);

    into
    1. CustomViewTarget target = new CustomViewTarget(view) {
    2. @Override
    3. protected void onResourceCleared(@Nullable Drawable placeholder) {
    4. Log.e(TAG, "资源清理");
    5. }
    6. @Override
    7. public void onLoadFailed(@Nullable Drawable errorDrawable) {
    8. Log.e(TAG, "加载失败");
    9. }
    10. @Override
    11. public void onResourceReady(@NonNull Drawable resource, @Nullable Transitionsuper Drawable> transition) {
    12. Log.e(TAG, "加载成功");
    13. }
    14. };
    15. CustomViewTarget 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为什么要加入网络权限?

    android:name="android.permission.INTERNET" />

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

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

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

  • 相关阅读:
    【STM32】基于HAL库建立自己的低功耗模式配置库(STM32L4系列低功耗所有配置汇总)
    机械硬盘,Win10系统,磁盘100%
    形式化验证笔记
    Python快速而美丽[v1.0.0][命令行工具]
    Python 编程竟然如此幽默!揭秘程序员们的搞笑日常,快来看看吧!
    操作系统:中断和异常
    Linux常见指令和基础知识
    【MybatisPlus】简介与使用
    idea实现Docker 远程部署项目
    Java项目:SSM电影售票管理系统
  • 原文地址:https://blog.csdn.net/qq_34123324/article/details/132646384