美文网首页Android技术知识Android开发经验谈Android开发
深入理解Glide源码:三条主线分析-Glide-执行流程

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

作者: 愿天堂没Android | 来源:发表于2022-01-25 21:27 被阅读0次

    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中的绑定关系解除;

    相关文章

      网友评论

        本文标题:深入理解Glide源码:三条主线分析-Glide-执行流程

        本文链接:https://www.haomeiwen.com/subject/tckghrtx.html