从源码的角度带你分析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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 声明 本文章是基于 glide 3.6.1的 个各类的功能介绍 1.Glide:向外暴露单例静态接口,构建Requ...
    河里的枇杷树阅读 1,143评论 0 3
  • 本文是Glide源码解析系列的第一篇,通过这篇文档,将可以了解到: 1.Glide如何绑定Activity、Fra...
    他的大姨父阅读 8,527评论 6 42
  • 六月十二那天,阳光很好,风轻轻吹着。西瓜结束了作为初中生的最重要的一次考试。西瓜以为自己会像文里写的那样哭泣,那样...
    桃夭公子阅读 326评论 2 4
  • 2017年10月22日星期日 距离18考研61天 早晨6点40起床,7点40到教室。 复习政治选择题。 数学做的线...
    sy_yunyi阅读 246评论 0 0