前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >源码阅读--Glide

源码阅读--Glide

作者头像
提莫队长
发布2019-02-21 14:48:41
5150
发布2019-02-21 14:48:41
举报
文章被收录于专栏:刘晓杰刘晓杰

1.用法及参考资料

参考资料:http://www.apkbus.com/blog-705730-60158.html 用法:

Glide.with(this).load("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1494417111222&di=0679f94eacd58059affec7cc9a33c731&imgtype=0&src=http%3A%2F%2Fi.zeze.com%2Fattachment%2Fforum%2F201506%2F28%2F104039ydramgzhbzxarof9.jpg").into(mImageView;

2.重要类的说明

(1)Engine

负责任务创建,发起,回调,资源的管理

  public <R> LoadStatus load(/**   */) {
    ......
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);//----------------------------WeakReference
    ......

    EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
    //------------------------------------Map<Key, WeakReference<EngineResource<?>>> activeResources,从这个参数里面获取的
    //--------------------------------------activeResources在构造函数中赋值,在loadFromCache中添加(如果cache中有的话)
    ......

    //---------------------------------------------------------------获取相关联的EngineJob
    EngineJob<?> current = jobs.get(key);//-----------------------------jobs是一个Map<Key, EngineJob<?>>,在构造函数中被赋值
    if (current != null) {//--------------------------------成功获取,添加Callback
      current.addCallback(cb);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Added to existing load", startTime, key);
      }
      return new LoadStatus(cb, current);
    }

    //-------------------------------------------------------相关联的EngineJob获取失败
    EngineJob<R> engineJob = engineJobFactory.build(key, isMemoryCacheable,
        useUnlimitedSourceExecutorPool);
    DecodeJob<R> decodeJob = decodeJobFactory.build(/....../);
    jobs.put(key, engineJob);
    engineJob.addCallback(cb);
    engineJob.start(decodeJob);//---------------------------------发起新的decodeJob
    return new LoadStatus(cb, engineJob);
  }
(2)EngineJob

调度 DecodeJob,添加,移除资源回调,并 notify 回调 如果从cache中获取,那就由diskCacheExecutor来执行decodeJob,否则由ActiveSourceExecutor来执行

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

实现了 Runnable 接口,调度任务的核心类,整个请求的繁重工作都在这里完成:处理来自缓存或者原始的资源,应用转换动画以及 transcode run方法里面调用了runWrapped

private void runWrapped() {
     switch (runReason) {
      case INITIALIZE:
        stage = getNextStage(Stage.INITIALIZE);//-----------------------获取Stage(INITIALIZE,RESOURCE_CACHE,DATA_CACHE,SOURCE,ENCODE,FINISHED)
        currentGenerator = getNextGenerator();//-----------------------根据Stage获取对应的CacheGenerator
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE:
        runGenerators();
        break;
      case DECODE_DATA:
        decodeFromRetrievedData();//---------------------------调用decodeFromData,如果失败也会调用runGenerators
        break;
    }
  }

runGenerators内部会调用reschedule,重新调度

public void reschedule(DecodeJob<?> job) {
    if (isCancelled) {
      MAIN_THREAD_HANDLER.obtainMessage(MSG_CANCELLED, this).sendToTarget();
    } else {
      getActiveSourceExecutor().execute(job);
    }
  }

3.用法解析

(1)with函数
public static RequestManager with(FragmentActivity activity) {
        return getRetriever(activity).get(activity);
    }

getRetriever获取的是一个RequestManagerRetriever

private static RequestManagerRetriever getRetriever(@Nullable Context context) {
        。。。。。。
        return Glide.get(context).getRequestManagerRetriever();//-----------------------get函数中有对Glide的初始化initGlide
    }

    private static void initGlide(Context context) {

        。。。。。。

        RequestManagerRetriever.RequestManagerFactory factory =
                annotationGeneratedModule != null
                        ? annotationGeneratedModule.getRequestManagerFactory() : null;
        GlideBuilder builder = new GlideBuilder().setRequestManagerFactory(factory);

        。。。。。。

        glide = builder.build(applicationContext);//-----------------------------建造者模式生成glide

        。。。。。。
    }

再来看一下getRetriever之后的get函数做了什么

public RequestManager get(FragmentActivity activity) {
        if (Util.isOnBackgroundThread()) {
            return get(activity.getApplicationContext());
        } else {
            assertNotDestroyed(activity);
            FragmentManager fm = activity.getSupportFragmentManager();
            return supportFragmentGet(activity, fm, null /*parentHint*/);
        }
    }

    public RequestManager get(Context context) {
        。。。。。。
        return getApplicationManager(context);
    }

    private RequestManager getApplicationManager(Context context) {

        if (applicationManager == null) {
            synchronized (this) {
                if (applicationManager == null) {

                    。。。。。。

                    Glide glide = Glide.get(context);
                    applicationManager = factory.build(glide, new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
                }
            }
        }

        return applicationManager;
    }

applicationManager就是RequestManager 上面是isOnBackgroundThread,那么就是在主线程的流程————-说白了也就是为了获得RequestManager

private RequestManager supportFragmentGet(Context context, FragmentManager fm,
                                              Fragment parentHint) {
        SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
        RequestManager requestManager = current.getRequestManager();
        if (requestManager == null) {
            // TODO(b/27524013): Factor out this Glide.get() call.
            Glide glide = Glide.get(context);
            requestManager =
                    factory.build(glide, current.getLifecycle(), current.getRequestManagerTreeNode());
            current.setRequestManager(requestManager);
        }
        return requestManager;
    }

综上,整个with函数就为了获得RequestManager。 它里面有个RequestTracker是用来保存request的,用的是WeakHashMap

//----------------------------------------------删除不再正常使用的entry
    private void expungeStaleEntries() {
        for (Object x; (x = queue.poll()) != null; ) {//-------------------------------这里的queue是ReferenceQueue(Reference queue for cleared WeakEntries)
            synchronized (queue) {
                Entry<K,V> e = (Entry<K,V>) x;
                int i = indexFor(e.hash, table.length);

                Entry<K,V> prev = table[i];
                Entry<K,V> p = prev;
                while (p != null) {
                    Entry<K,V> next = p.next;
                    if (p == e) {
                        if (prev == e)
                            table[i] = next;
                        else
                            prev.next = next;
                        // Must not null out e.next;
                        // stale entries may be in use by a HashIterator
                        e.value = null; // Help GC
                        size--;
                        break;
                    }
                    prev = p;
                    p = next;
                }
            }
        }
    }

这个“弱键”的原理呢?大致上就是,通过WeakReference和ReferenceQueue实现的。 WeakHashMap的key是“弱键”,即是WeakReference类型的;ReferenceQueue是一个队列,它会保存被GC回收的“弱键”。实现步骤是: (01) 新建WeakHashMap,将“键值对”添加到WeakHashMap中。实际上,WeakHashMap是通过数组table保存Entry(键值对);每一个Entry实际上是一个单向链表,即Entry是键值对链表。 (02) 当某“弱键”不再被其它对象引用,并被GC回收时。在GC回收该“弱键”时,这个“弱键”也同时会被添加到ReferenceQueue(queue)队列中。 (03) 当下一次我们需要操作WeakHashMap时,会先同步table和queue。table中保存了全部的键值对,而queue中保存被GC回收的键值对;同步它们,就是删除table中被GC回收的键值对。 这就是“弱键”如何被自动从WeakHashMap中删除的步骤了。

(2)load函数

跟踪进去就是配置了点参数

(3)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);//-----------------------获取了Request以后就开始runRequest------request.begin();

    return target;
  }

  @Override
  public void begin() {
    ......

    status = Status.WAITING_FOR_SIZE;
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      onSizeReady(overrideWidth, overrideHeight);//----------------------------------------获取数据并解析
    } else {
      target.getSize(this);
    }

    if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
        && canNotifyStatusChanged()) {
      target.onLoadStarted(getPlaceholderDrawable());//------------------------------------把图片加载进控件中
    }
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
      logV("finished run method in " + LogTime.getElapsedMillis(startTime));
    }
  }

  public void onSizeReady(int width, int height) {
    。。。。。。
    status = Status.RUNNING;

    float sizeMultiplier = requestOptions.getSizeMultiplier();
    this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
    this.height = maybeApplySizeMultiplier(height, sizeMultiplier);

    loadStatus = engine.load(/*****/);//------------------------------------------之前讨论过的engine.load方法
    。。。。。。
  }
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年05月18日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.用法及参考资料
  • 2.重要类的说明
    • (1)Engine
      • (2)EngineJob
        • (3)DecodeJob
        • 3.用法解析
          • (1)with函数
            • (2)load函数
              • (3)into函数
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档