深入理解Glide源码:三条主线分析 Glide 执行流程

Glide流程分析

说到图片加载框架,大家最熟悉的莫过于Glide了,但我却不推荐简历上写熟悉Glide, 除非你熟读它的源码,或者参与Glide的开发和维护。然而很多小伙伴对于Glide的流程及其源码解读总是无从下手,本篇就从三条主线来分析一下Glide流程及源码!

第一条主线

加入队列流程:

RequestManager with = Glide.with(this);
RequestBuilder<Drawable> load = with.load(url);
load.into(iv);   // 前面的暂时先不看,当调用into方法后,说明加载图片的请求才真正开始

继续调用

return into(
    glideContext.buildImageViewTarget(view, transcodeClass),
    /*targetListener=*/ null,
    requestOptions);

继续跟踪,会发现以下代码

requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);//发送请求开始的地方

void track(Target<?> target, Request request) {
  targetTracker.track(target);
  requestTracker.runRequest(request);//从名字看叫运行请求
}

继续跟踪

通过该方法得知Glide也有两个队列;运行队列和等待队列;
public void runRequest(Request request) {
  requests.add(request);//加入运行队列;
  if (!isPaused) {
    request.begin();//开始执行
  } else {
    pendingRequests.add(request);//加入等待队列
  }
}

第二条主线

请求如何运行?

在第一条主线中,request.begin()方法就是真正开始执行请求的时候;先找到request的实现类:SingleRequest,找到其begin方法;

为什么找到的是SingleRequest?

在第一条主线的RequestBuilder.into方法中有一句代码;

Request request = buildRequest(target, targetListener, options);

继续跟踪它

buildRequestRecursive() 找到构建request的方法;

在该方法中,又能跟踪到

Request mainRequest = buildThumbnailRequestRecursive()

继续跟踪

Request fullRequest =
    obtainRequest(
        target,
        targetListener,
        requestOptions,
        coordinator,
        transitionOptions,
        priority,
        overrideWidth,
        overrideHeight);

上述代码块最终调用的是SingleRequest.obtain()方法,从而得到一个SingleRequest对象;所以能得出结论,request.begin()方法被调用时,即调用了SingleRequestbegin方法;继续跟踪begin方法,会发现onSizeReady方法;

onSizeReady(overrideWidth, overrideHeight);

begin方法中跟踪到engine.load方法,如下(只抽取了部分代码):

// 从活动缓存中获取
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    if (active != null) {
      cb.onResourceReady(active, DataSource.MEMORY_CACHE);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Loaded resource from active resources", startTime, key);
      }
      return null;
    }

// 从内存缓存中获取
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
      cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Loaded resource from cache", startTime, key);
      }
      return null;
    }
// 硬盘缓存,硬盘缓存也是io操作,所以也使用了线程池;动画线程池
    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
    if (current != null) {
      current.addCallback(cb);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      return new LoadStatus(cb, current);
    }

    EngineJob<R> engineJob =
        engineJobFactory.build(
            key,
            isMemoryCacheable,
            useUnlimitedSourceExecutorPool,
            useAnimationPool,
            onlyRetrieveFromCache);

    DecodeJob<R> decodeJob =
        decodeJobFactory.build(
            glideContext,
            model,
            key,
            signature,
            width,
            height,
            resourceClass,
            transcodeClass,
            priority,
            diskCacheStrategy,
            transformations,
            isTransformationRequired,
            isScaleOnlyOrNoTransform,
            onlyRetrieveFromCache,
            options,
            engineJob);

    jobs.put(key, engineJob);

    engineJob.addCallback(cb);
    engineJob.start(decodeJob); //具体的加载,engineJob为加载管理类,decodeJob则为将返回的图片数据进行编码管理的类;

调用engineJob.start()方法后,则会执行以下代码:

public void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
    executor.execute(decodeJob);
  }

继续跟踪找到DecodeJobrun方法;

DecodeJob.run() 继续调用 runWrapped(); 再继续调用getNextGenerator()

private DataFetcherGenerator getNextGenerator() {
    switch (stage) {
      case RESOURCE_CACHE:
        return new ResourceCacheGenerator(decodeHelper, this);
      case DATA_CACHE:
        return new DataCacheGenerator(decodeHelper, this);
      case SOURCE:
      // 根据主线我们目前都先不去处理跟Cache相关的类,直接进入SourceGenerator;这里使用了设计模式-状态模式;(请自行根据第二节内容进行查询)
        return new SourceGenerator(decodeHelper, this);
      case FINISHED:
        return null;
      default:
        throw new IllegalStateException("Unrecognized stage: " + stage);
    }
  }

继续跟踪到SourceGenerator类中的startNext方法;

loadData.fetcher.loadData(helper.getPriority(), this);

根据fetcher找到HttpUrlFetcher,并找到对应的loadData方法;最终发现Glide是通过HttpUrlConnection访问的服务器,并返回最终的stream

问题来了?我怎么知道是这个类的?为什么不是其他类?在这里代码就看不懂了,怎么办?猜测;

既然应该不是再继续从缓存拿,而应该要去访问网络了;所以找到具体访问网络的;发现找不到,怎么办?

找它的实现类,有一个HttpUrlFetcher,那它在哪里初始化的?

通过Find Usages找到哪里调用了--->找到了HttpGlideUrlLoader

再看这个方法HttpGlideUrlLoader哪里调用了;

找到了Glide,继续往上寻找,找打了Glide种的build方法 ,找就能找到Glide.get(context);方法

第三条主线

队列怎么维护的?在MainActivity中我们调用了如下代码:

RequestManager with = Glide.with(this);

继续跟踪到

getRetriever(activity).get(activity)//这里得到了一个RequestManagerRetriever对象,再通过RequestManagerRetriever调用get方法得到RequestManager

继续往下

androidx.fragment.app.FragmentManager fm = activity.getSupportFragmentManager();
return this.supportFragmentGet(activity, fm, (Fragment)null);

通过this.supportFragmentGet方法(如下代码),最终我们得到SupportRequestManagerFragment对象;

private RequestManager supportFragmentGet(@NonNull Context context, @NonNull androidx.fragment.app.FragmentManager fm, @Nullable Fragment parentHint) {
    SupportRequestManagerFragment current = this.getSupportRequestManagerFragment(fm, parentHint);//这段代码的内部如果能够得到Fragment就得到,得不到就重新new一个,并且这个fragment中没有进行任何的UI处理;
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
        Glide glide = Glide.get(context);
        requestManager = this.factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
        current.setRequestManager(requestManager);
    }

    return requestManager;
}

得到Fragment对象后,再将RequestManager对象赋值进去,如果RequestManager为空,则帮助创建;

RequestManager对象则是生命周期管理的重要一环,因为它实现了LifecycleListener接口,并且在创建RequestManager的时候,会将这个接口设置给自己;也就意味着,Glide创建了一个无UI的fragment,这个fragment又与RequestManager进行绑定;当用户的activity或者fragment被调用,系统会自动调用fragment的生命周期方法;而生命周期方法中又会回调LifecycleListener的方法,进而调用RequestManagerRequestManager则也拥有了生命周期;

RequestManageronStart方法被调用后,会通过一系列的调用,将运行中的请求全部放开,进行访问;

onStop方法被调用时,则将运行中队列的数据取出来,如果当前请求正在运行则暂停,然后将所有的数据从运行队列中添加到等待队列中去;

onDestory方法被调用时,则将运行队列和等待队列中的数据全部清除;再将监听移除;将requestManager从Glide中的绑定关系解除;

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

推荐阅读更多精彩内容