从源码的角度带你分析Glide整体加载流程以及设计模式

基本调用流程

这一篇文章我们从源码的角度分析Glide实现,首先我们从一句最简单的使用方式来探索他的设计与实现,可以看到下面这句话是最基础的使用

Glide.with(this)
        .load(R.raw.large_giphy_logo)
        .into(giphyLogoView);

接下来我们一步一步的跟踪他的调用过程,首先我们看到他调用了Glide的with方法并传入了自己的引用,我们可以看到这方法的实现如下:

public static RequestManager with(Activity activity) {
  RequestManagerRetriever retriever = RequestManagerRetriever.get();
  return retriever.get(activity);
}

他调用了RequestManagerRetriever的方法获取了一个RequestManagerRetriever然后在调用get方法获取了一个RequestManager,到这里我们大概基本明白了with方法做的是将当前引用(Activity,Fragment)传递进去并获取一个和当前引用绑定的RequestManager,到这里大家应该能明白了为什么说Glide绑定了界面的生命周期了吧

接着调用了RequestManager的load方法,可以看到这一步创建了RequestBuilder

public RequestBuilder<Drawable> load(@Nullable Object model) {
  return asDrawable().load(model);
}

最后调用到了loadGeneric方法

public RequestBuilder<TranscodeType> load(@Nullable Object model) {
  return loadGeneric(model);
}

不过从这个方法我们可以看到他只是将传递进来的资源保存了,现在还没有发送真正的网络请求

private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
  this.model = model;
  isModelSet = true;
  return this;
}

然后调用了RequestBuilder的into方法

public Target<TranscodeType> into(ImageView view) {
    Util.assertMainThread();
    Preconditions.checkNotNull(view);

    if (!requestOptions.isTransformationSet()
            && requestOptions.isTransformationAllowed()
            && view.getScaleType() != null) {
        if (requestOptions.isLocked()) {
            requestOptions = requestOptions.clone();
        }
        switch (view.getScaleType()) {
            case CENTER_CROP:
                requestOptions.optionalCenterCrop(context);
                break;
            case CENTER_INSIDE:
                requestOptions.optionalCenterInside(context);
                break;
            case FIT_CENTER:
            case FIT_START:
            case FIT_END:
                requestOptions.optionalFitCenter(context);
                break;
            //$CASES-OMITTED$
            default:
                // Do nothing.
        }
    }

    return into(context.buildImageViewTarget(view, transcodeClass));
}

在这个方法里面,主要判断了是否设置了Transformation如果设置了,然后根据相应的规则变换bitmap,最后调用了这个into方法

public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) {
    Util.assertMainThread();
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
        throw new IllegalArgumentException("You must call #load() before calling #into()");
    }

    Request previous = target.getRequest();

    if (previous != null) {
        requestManager.clear(target);
    }

    requestOptions.lock();
    Request request = buildRequest(target);
    target.setRequest(request);
    requestManager.track(target, request);

    return target;
}

在这方法中创建了Request,然后调用requestManager的track方法去执行这个request

void track(Target<?> target, Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
  }

我们再来查看下buildRequest方法

  private Request buildRequest(Target<TranscodeType> target) {
    return buildRequestRecursive(target, null, transitionOptions, requestOptions.getPriority(),
            requestOptions.getOverrideWidth(), requestOptions.getOverrideHeight());
}

private Request buildRequestRecursive(Target<TranscodeType> target,
                                      @Nullable ThumbnailRequestCoordinator parentCoordinator,
                                      TransitionOptions<?, ? super TranscodeType> transitionOptions,
                                      Priority priority, int overrideWidth, int overrideHeight) {
    if (thumbnailBuilder != null) {
        // Recursive case: contains a potentially recursive thumbnail request builder.
        if (isThumbnailBuilt) {
            throw new IllegalStateException("You cannot use a request as both the main request and a "
                    + "thumbnail, consider using clone() on the request(s) passed to thumbnail()");
        }

        TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions =
                thumbnailBuilder.transitionOptions;
        if (DEFAULT_ANIMATION_OPTIONS.equals(thumbTransitionOptions)) {
            thumbTransitionOptions = transitionOptions;
        }

        Priority thumbPriority = thumbnailBuilder.requestOptions.isPrioritySet()
                ? thumbnailBuilder.requestOptions.getPriority() : getThumbnailPriority(priority);

        int thumbOverrideWidth = thumbnailBuilder.requestOptions.getOverrideWidth();
        int thumbOverrideHeight = thumbnailBuilder.requestOptions.getOverrideHeight();
        if (Util.isValidDimensions(overrideWidth, overrideHeight)
                && !thumbnailBuilder.requestOptions.isValidOverride()) {
            thumbOverrideWidth = requestOptions.getOverrideWidth();
            thumbOverrideHeight = requestOptions.getOverrideHeight();
        }

        ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
        Request fullRequest = obtainRequest(target, requestOptions, coordinator,
                transitionOptions, priority, overrideWidth, overrideHeight);
        isThumbnailBuilt = true;
        // Recursively generate thumbnail requests.
        Request thumbRequest = thumbnailBuilder.buildRequestRecursive(target, coordinator,
                thumbTransitionOptions, thumbPriority, thumbOverrideWidth, thumbOverrideHeight);
        isThumbnailBuilt = false;
        coordinator.setRequests(fullRequest, thumbRequest);
        return coordinator;
    } else if (thumbSizeMultiplier != null) {
        // Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
        ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
        Request fullRequest = obtainRequest(target, requestOptions, coordinator, transitionOptions,
                priority, overrideWidth, overrideHeight);
        BaseRequestOptions<?> thumbnailOptions = requestOptions.clone()
                .sizeMultiplier(thumbSizeMultiplier);

        Request thumbnailRequest = obtainRequest(target, thumbnailOptions, coordinator,
                transitionOptions, getThumbnailPriority(priority), overrideWidth, overrideHeight);

        coordinator.setRequests(fullRequest, thumbnailRequest);
        return coordinator;
    } else {
        // Base case: no thumbnail.
        return obtainRequest(target, requestOptions, parentCoordinator, transitionOptions, priority,
                overrideWidth, overrideHeight);
    }
}

可以看到最后调用了buildRequestRecursive来创建一个Request,在这方法里面通过判断是否设置了thumbnail来创建不同类型的Request,如果没有设置就会创建最基本的请求,也就是SingleRequest

private Request obtainRequest(Target<TranscodeType> target,
                              BaseRequestOptions<?> requestOptions, RequestCoordinator requestCoordinator,
                              TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority,
                              int overrideWidth, int overrideHeight) {
    requestOptions.lock();

    return SingleRequest.obtain(
            context,
            model,
            transcodeClass,
            requestOptions,
            overrideWidth,
            overrideHeight,
            priority,
            target,
            requestListener,
            requestCoordinator,
            context.getEngine(),
            transitionOptions.getTransitionFactory());
}

到这里大家可以看到Glide的源码可以说是非常复杂的,总感觉有时候用到项目里是不是有点太重了,就加载个图片,你看看搞了这么多代码~~

一些设计技巧

绑定界面的生命周期

在Glide中可以看到所有的请求都是和当前界面绑定的,比如:activity执行onStop时,其相应的请求应该暂停,那他是怎么绑定的呢,简单来讲就是在当前activity中绑定一个fragment,这样我们就能通过这个fragment获取到相应的生命周期,然后回调到你要处理的地方,然后在作出相应的处理,如果代码:

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void bindLifeCycle(LifeCycleActivity activity) {
    FragmentManager fm = activity.getFragmentManager();
    //将一个fragment绑定到当前界面,这样就能获取到了当前界面的生命周期了
    LifeCycleFragment current = new LifeCycleFragment();
    fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
}

这样我们就能在LifeCycleFragment中获取到相应的生命周期了

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class LifeCycleFragment extends Fragment {
    private static final String TAG = "LifeCycleFragment";

    @Override
    public void onStart() {
        super.onStart();
        //TODO 这里回调你的生命周期状态
        Log.d(TAG,"onStart");
    }

    @Override
    public void onStop() {
        super.onStop();
        Log.d(TAG,"onStop");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG,"onDestroy");
    }
}

参考:https://github.com/android-cn/android-open-project-analysis/tree/master/tool-lib/image-cache/glide

时间: 2024-10-12 04:51:48

从源码的角度带你分析Glide整体加载流程以及设计模式的相关文章

android7.x Launcher3源码解析(3)---workspace和allapps加载流程

Launcher系列目录: 一.android7.x Launcher3源码解析(1)-启动流程 二.android7.x Launcher3源码解析(2)-框架结构 三.android7.x Launcher3源码解析(3)-workspace和allapps加载流程 前两篇博客分别对Lancher的启动和Launcher的框架结构进行了一些分析,这一篇,将着重开始分析界面的加载流程. 1.整体流程 先上一张整体的流程图吧.(图片看不清可以下载下来看或者右击新开个页面查看图片) 先从Launc

【Spring源码分析】Bean加载流程概览

代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事的都是Java Web的工作,对于程序员来说,一个Web项目用到Spring,只是配置一下配置文件而已,Spring的加载过程相对是不太透明的,不太好去找加载的代码入口. 下面有很简单的一段代码可以作为Spring代码加载的入口: 1 ApplicationContext ac = new Clas

spring源码深度解析— IOC 之 开启 bean 的加载

概述 前面我们已经分析了spring对于xml配置文件的解析,将分析的信息组装成 BeanDefinition,并将其保存注册到相应的 BeanDefinitionRegistry 中.至此,Spring IOC 的初始化工作完成.接下来我们将对bean的加载进行探索. 之前系列文章: spring源码深度解析— IOC 之 容器的基本实现 spring源码深度解析— IOC 之 默认标签解析(上) spring源码深度解析— IOC 之 默认标签解析(下) spring源码深度解析— IOC

android源码解析(二十二)--&gt;Toast加载绘制流程

前面我们分析了Activity.Dialog.PopupWindow的加载绘制流程,相信大家对整个Android系统中的窗口绘制流程已经有了一个比较清晰的认识了,这里最后再给大家介绍一下Toast的加载绘制流程. 其实Toast窗口和Activity.Dialog.PopupWindow有一个不太一样的地方,就是Toast窗口是属于系统级别的窗口,他和输入框等类似的,不属于某一个应用,即不属于某一个进程,所以自然而然的,一旦涉及到Toast的加载绘制流程就会涉及到进程间通讯,看过前面系列文章的同

spring源码解析之IOC容器(二)------加载和注册

上一篇跟踪了IOC容器对配置文件的定位,现在我们继续跟踪代码,看看IOC容器是怎么加载和注册配置文件中的信息的.开始之前,首先我们先来了解一下IOC容器所使用的数据结构-------BeanDefinition,它是一个上层接口,有很多实现类,分别对应不同的数据载体.我们平时开发的时候,也会定义很多pojo类,来作为获取数据的载体.最常见的就是,从数据库中获取数据之后,使用一个定义的pojo来装载,然后我们就可以在程序中使用这个pojo类来编写各种业务逻辑.同样,IOC容器首先会读取配置的XML

spring源码阅读(2)-- 容器启动之加载BeanDefinition

在<spring源码阅读(1)-- 容器启动之资源定位>一文中,阅读了spring是怎么根据用户指定的配置加载资源,当加载完资源,接下来便是把从资源中加载BeanDefinition. BeanDefinition作为spring其中一个组件,spring是这样描述BeanDefinition的:BeanDefinition描述了一个bean实例,它具有属性值,构造函数参数值以及具体实现提供的更多信息.个人的理解是BeanDefinition保存了一个bean实例的所有元数据,下面列举一些常用

MQTT---HiveMQ源码详解(五)Netty-启动与Listeners加载

实现功能 启动netty,按照用户配置的Listener进行端口的监听,接受客户端发来的链接 实现步骤 1.启动netty 2.通过ListenerConfigurationService获得到用户的Listener配置,将对应的配置绑定到netty上. 类图 这个uml熟悉netty的朋友应该看起来很清晰,下来我们帖几段代码,来看hivemq是如何绑定的. public ListenableFuture<List<ListenerStartResult>> startListen

Android中图片加载框架Glide解析2----从源码的角度理解Glide的执行流程

转载地址:http://blog.csdn.net/guolin_blog/article/details/53939176 在本系列的上一篇文章中,我们学习了Glide的基本用法,体验了这个图片加载框架的强大功能,以及它非常简便的API.还没有看过上一篇文章的朋友,建议先去阅读 Android图片加载框架最全解析(一),Glide的基本用法 . 在多数情况下,我们想要在界面上加载并展示一张图片只需要一行代码就能实现,如下所示: Glide.with(this).load(url).into(i

Android图片加载框架最全解析(二),从源码的角度理解Glide的执行流程

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/53939176 本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 郭霖 即可关注,每天都有文章更新. 在本系列的上一篇文章中,我们学习了Glide的基本用法,体验了这个图片加载框架的强大功能,以及它非常简便的API.还没有看过上一篇文章的朋友,建议先去阅读 Android图片加载框架最全解析(一),Glide的基本用法 . 在多数情况下,我们想要在界面上加载并展示一