Glide源码解析

99 阅读8分钟

前言:

从事android开发已经四五年了,对第三方库的源码还没有进行多深入的研读,属实有点说不过去。
接下来会对常用的第三方库进行研读,希望有更深入的了解,并希望从源码中能学到东西,同时在读源码的过程中,对知识薄弱的地方进行加强。
文章只是现阶段对源码的解读,自己的一个记录,如果发现有错误的,评论,一起探讨,共同进步。话不多说,现在就开始吧,希望可以一直坚持下去。

首先列下接下来看源码自己的一些流程 1.提出对第三方库不理解的点,感兴趣的点,提出问题,带着问题去看源码 2.在源码中寻找能解决提出问题的答案,然后记录下来 3.根据自己的理解,绘制第三方库的流程图 4.总结,源码中学到的东西进行总结 5.可以再选择一个功能模块进行细看

glide 源码解析 3.7版本

glide作为安卓比较比较受欢迎的图片加载框架,相信你一定对他有一定的了解,今天就从源码开始,对他进行一个解析,加深对他的认识。

问题:

1.如何判断生命周期进行回收 2.如何缓存,使用缓存 3.如何请求网络图片

一、Glide生命周期的监听

先从glide的最简单的使用开始 Glide.with(context).load(url).into(view); 没看源码之前,可能面试上就会问传入的context有什么要求,如果乱用context会导致什么问题 相信一部分人已经知道,content的传入是会影响glide的回收的,如何使用不当,可能会导致内存泄露。那针对第一个问题,glide如何判断生命周期进行回收的,我们就可以从content入手,看glide是如何监控页面生命周期,进行资源回收的

    public static RequestManager with(Context context) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(context);
    }
    public static RequestManager with(Activity activity) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(activity);
    }
    public static RequestManager with(FragmentActivity activity) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(activity);
    }
    public static RequestManager with(Fragment fragment) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(fragment);
    }
    

通过上面源码,我们知道Glide.with()方法,有多个重载方法,可以传入Context,Activity,FragmentActivity,Fragment等,而他们返回的RequestManager 都是通过RequestManagerRetriever来实现

以传入Fragment为例,会先拿到传入的FragmentManger,这里是通过getChildFragmentManager获取的,如果是activity则是getSupportFragmentManager

    public RequestManager get(Fragment fragment) {
        if (fragment.getActivity() == null) {
            throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
        }
        if (Util.isOnBackgroundThread()) {
            return get(fragment.getActivity().getApplicationContext());
        } else {
            FragmentManager fm = fragment.getChildFragmentManager();
            return supportFragmentGet(fragment.getActivity(), fm);
        }
    }

再看下supportFragmentGet的方法

RequestManager supportFragmentGet(Context context, FragmentManager fm) {
        SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
        RequestManager requestManager = current.getRequestManager();
        if (requestManager == null) {
            requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
            current.setRequestManager(requestManager);
        }
        return requestManager;
    }

还需要跳到getSupportRequestManagerFragment

 SupportRequestManagerFragment getSupportRequestManagerFragment(final FragmentManager fm) {
      SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag(


          FRAGMENT_TAG);
      if (current == null) {
          current = pendingSupportRequestManagerFragments.get(fm);
          if (current == null) {
              current = new SupportRequestManagerFragment();
              pendingSupportRequestManagerFragments.put(fm, current);
              fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
              handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
          }
      }
      return current;
  }

这里我们可以知道,他是先通过前面获取的fragmentmanager 通过tag,看是否存在 SupportRequestManagerFragment,如果不存在就会new一个,然后通过fragmentManager开启事务添加一个fragment,并设置tag,下次就可以通过tag寻找。接下来我们看看SupportRequestManagerFragment是个什么东西

public class SupportRequestManagerFragment extends Fragment {
    private RequestManager requestManager;
    private final ActivityFragmentLifecycle lifecycle;
    private final RequestManagerTreeNode requestManagerTreeNode =
            new SupportFragmentRequestManagerTreeNode();
    private final HashSet<SupportRequestManagerFragment> childRequestManagerFragments =
        new HashSet<SupportRequestManagerFragment>();
    private SupportRequestManagerFragment rootRequestManagerFragment;

    public SupportRequestManagerFragment() {
        this(new ActivityFragmentLifecycle());
    }

    // For testing only.
    @SuppressLint("ValidFragment")
    public SupportRequestManagerFragment(ActivityFragmentLifecycle lifecycle) {
        this.lifecycle = lifecycle;
    }
    
    ...
        @Override
    public void onStart() {
        super.onStart();
        lifecycle.onStart();
    }

    @Override
    public void onStop() {
        super.onStop();
        lifecycle.onStop();
    }

    @Override
1.     public void onDestroy() {
        super.onDestroy();
        lifecycle.onDestroy();
    }

其实SupportRequestManagerFragment是一个空界面的fragment,至于为什么glide要加一个空的fragment,实际上就是fragment对生命周期进行监控,而又不需要界面展示。

二、Glide的图片加载流程

加载流程就得看load方法了

    public DrawableTypeRequest<String> load(String string) {
        return (DrawableTypeRequest<String>) fromString().load(string);
    }
    
 private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
        ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
        ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader =
                Glide.buildFileDescriptorModelLoader(modelClass, context);
        if (modelClass != null && streamModelLoader == null && fileDescriptorModelLoader == null) {
            throw new IllegalArgumentException("Unknown type " + modelClass + ". You must provide a Model of a type for"
                    + " which there is a registered ModelLoader, if you are using a custom model, you must first call"
                    + " Glide#register with a ModelLoaderFactory for your custom model class");
        }

        return optionsApplier.apply(
                new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
                        glide, requestTracker, lifecycle, optionsApplier));
    }

根据不同的加载类型,构建DrawableTypeRequest,然后调用load()方法 DrawableTypeRequest继承至DrawableRequestBuilder,DrawableRequestBuilder继承至GenericRequestBuilder,最终调用GenericRequestBuilder中的load方法

    public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) {
        this.model = model;
        isModelSet = true;
        return this;
    }

这里是返回了自身,我们知道在load()方法后,会调用into方法,在控件上显示图片。

    public Target<TranscodeType> into(ImageView view) {
        Util.assertMainThread();
        if (view == null) {
            throw new IllegalArgumentException("You must pass in a non null View");
        }

        if (!isTransformationSet && view.getScaleType() != null) {
            switch (view.getScaleType()) {
                case CENTER_CROP:
                    applyCenterCrop();
                    break;
                case FIT_CENTER:
                case FIT_START:
                case FIT_END:
                    applyFitCenter();
                    break;
                //$CASES-OMITTED$
                default:
                    // Do nothing.
            }
        }

        return into(glide.buildImageViewTarget(view, transcodeClass));
        
 public <Y extends Target<TranscodeType>> Y into(Y target) {
        Util.assertMainThread();
        if (target == null) {
            throw new IllegalArgumentException("You must pass in a non null Target");
        }
        if (!isModelSet) {
            throw new IllegalArgumentException("You must first set a model (try #load())");
        }

        Request previous = target.getRequest();

        if (previous != null) {
            previous.clear();
            requestTracker.removeRequest(previous);
            previous.recycle();
        }

        Request request = buildRequest(target);
        target.setRequest(request);
        lifecycle.addListener(target);
        requestTracker.runRequest(request);

        return target;
    }

这里会构建一个target对象,再通过target构建一个Request请求,最后通过requestTracker 运行这个请求,接下来看请求如何执行

    public void runRequest(Request request) {
        requests.add(request);
        if (!isPaused) {
            request.begin();
        } else {
            pendingRequests.add(request);
        }
    }
    
      @Override
    public void begin() {
        startTime = LogTime.getLogTime();
        if (model == null) {
            onException(null);
            return;
        }

        status = Status.WAITING_FOR_SIZE;
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
            onSizeReady(overrideWidth, overrideHeight);
        } else {
            target.getSize(this);
        }

        if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
            target.onLoadStarted(getPlaceholderDrawable());
        }
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logV("finished run method in " + LogTime.getElapsedMillis(startTime));
        }
    }
    
    

onSizeReady这里就是请求执行的地方,并设置好图片的占位图,再继续看下去

    @Override
    public void onSizeReady(int width, int height) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
        }
        if (status != Status.WAITING_FOR_SIZE) {
            return;
        }
        status = Status.RUNNING;

        width = Math.round(sizeMultiplier * width);
        height = Math.round(sizeMultiplier * height);

        ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
        final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);

        if (dataFetcher == null) {
            onException(new Exception("Failed to load model: \'" + model + "\'"));
            return;
        }
        ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
        }
        loadedFromMemoryCache = true;
        loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
                priority, isMemoryCacheable, diskCacheStrategy, this);
        loadedFromMemoryCache = resource != null;
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
        }
    }

这里是做请求的最后一步,生成编码,解码的transcoder,和请求图片相关的DataFetcher类,然后传给Engie做最后的资源获取逻辑

    public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
            DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
            Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
        Util.assertMainThread();
        long startTime = LogTime.getLogTime();

        final String id = fetcher.getId();
        EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
                loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
                transcoder, loadProvider.getSourceEncoder());

        EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
        if (cached != null) {
            cb.onResourceReady(cached);
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logWithTimeAndKey("Loaded resource from cache", startTime, key);
            }
            return null;
        }

        EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
        if (active != null) {
            cb.onResourceReady(active);
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logWithTimeAndKey("Loaded resource from active resources", startTime, key);
            }
            return null;
        }

        EngineJob current = jobs.get(key);
        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 engineJob = engineJobFactory.build(key, isMemoryCacheable);
        DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
                transcoder, diskCacheProvider, diskCacheStrategy, priority);
        EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
        jobs.put(key, engineJob);
        engineJob.addCallback(cb);
        engineJob.start(runnable);

        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Started new load", startTime, key);
        }
        return new LoadStatus(cb, engineJob);
    }
    
   static class EngineJobFactory {
        private final ExecutorService diskCacheService;
        private final ExecutorService sourceService;
        private final EngineJobListener listener;

        public EngineJobFactory(ExecutorService diskCacheService, ExecutorService sourceService,
                EngineJobListener listener) {
            this.diskCacheService = diskCacheService;
            this.sourceService = sourceService;
            this.listener = listener;
        }

        public EngineJob build(Key key, boolean isMemoryCacheable) {
            return new EngineJob(key, diskCacheService, sourceService, isMemoryCacheable, listener);
        }
    }

这个方法是Glide加载图片核心逻辑。Glide 加载首先会从内存中加载,通过 loadFromCache(),loadFromActiveResources(),如果存在就直接返回 cb.onResourceReady(cached); 否则会构建一个EngineJob对象,通过 EngineJobFactory进行构建。包含了两个线程池diskCacheService,sourceService。然后调用了EngineJob方法,执行runnable对象


    public void start(EngineRunnable engineRunnable) {
        this.engineRunnable = engineRunnable;
        future = diskCacheService.submit(engineRunnable);
    }

这里会调用磁盘缓存的任务,看下他runnable 执行

    @Override
    public void run() {
        if (isCancelled) {
            return;
        }

        Exception exception = null;
        Resource<?> resource = null;
        try {
            resource = decode();
        } catch (Exception e) {
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                Log.v(TAG, "Exception decoding", e);
            }
            exception = e;
        }

        if (isCancelled) {
            if (resource != null) {
                resource.recycle();
            }
            return;
        }

        if (resource == null) {
            onLoadFailed(exception);
        } else {
            onLoadComplete(resource);
        }
    }
   

会执行到decode方法

        private Resource<?> decode() throws Exception {
        if (isDecodingFromCache()) {
            return decodeFromCache();
        } else {
            return decodeFromSource();
        }
    }

会isDecodingFromCache 一开始传入的为true,先加载缓存,在run方法中,执行完decode 会有一段代码

        if (resource == null) {
           onLoadFailed(exception);
       } else {
           onLoadComplete(resource);
       }

当从磁盘缓存中没有获取到资源,就会执行onLoadFailed 方法

    private void onLoadFailed(Exception e) {
       if (isDecodingFromCache()) {
           stage = Stage.SOURCE;
           manager.submitForSource(this);
       } else {
           manager.onException(e);
       }
   }

这里会进行Stage的状态设置,再次执行run任务,此时isDecodingFromCache就为false,执行decodeFromSource,请求网络图片,代码如下

    private Resource<T> decodeSource() throws Exception {
       Resource<T> decoded = null;
       try {
           long startTime = LogTime.getLogTime();
           final A data = fetcher.loadData(priority);
           if (Log.isLoggable(TAG, Log.VERBOSE)) {
               logWithTimeAndKey("Fetched data", startTime);
           }
           if (isCancelled) {
               return null;
           }
           decoded = decodeFromSourceData(data);
       } finally {
           fetcher.cleanup();
       }
       return decoded;
   }

请求成功后会执行decodeFromSourceData

    private Resource<T> decodeFromSourceData(A data) throws IOException {
        final Resource<T> decoded;
        if (diskCacheStrategy.cacheSource()) {
            decoded = cacheAndDecodeSourceData(data);
        } else {
            long startTime = LogTime.getLogTime();
            decoded = loadProvider.getSourceDecoder().decode(data, width, height);
            if (Log.isLoggable(TAG, Log.VERBOSE)) {
                logWithTimeAndKey("Decoded from source", startTime);
            }
        }
        return decoded;
    }

    private Resource<T> cacheAndDecodeSourceData(A data) throws IOException {
        long startTime = LogTime.getLogTime();
        SourceWriter<A> writer = new SourceWriter<A>(loadProvider.getSourceEncoder(), data);
        diskCacheProvider.getDiskCache().put(resultKey.getOriginalKey(), writer);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Wrote source to cache", startTime);
        }

        startTime = LogTime.getLogTime();
        Resource<T> result = loadFromCache(resultKey.getOriginalKey());
        if (Log.isLoggable(TAG, Log.VERBOSE) && result != null) {
            logWithTimeAndKey("Decoded source from cache", startTime);
        }
        return result;
    }

将请求到的数据保存到磁盘,返回资源. 拿到资源后,会调用onLoadComplete()方法

    private void onLoadComplete(Resource resource) {
        manager.onResourceReady(resource);
    }
        @Override
  public void onResourceReady(final Resource<?> resource) {
        this.resource = resource;
        MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
    }

通过hanlder发送消息,回到主线程

    private void handleResultOnMainThread() {
        if (isCancelled) {
            resource.recycle();
            return;
        } else if (cbs.isEmpty()) {
            throw new IllegalStateException("Received a resource without any callbacks to notify");
        }
        engineResource = engineResourceFactory.build(resource, isCacheable);
        hasResource = true;

        // Hold on to resource for duration of request so we don't recycle it in the middle of notifying if it
        // synchronously released by one of the callbacks.
        engineResource.acquire();
        listener.onEngineJobComplete(key, engineResource);

        for (ResourceCallback cb : cbs) {
            if (!isInIgnoredCallbacks(cb)) {
                engineResource.acquire();
                cb.onResourceReady(engineResource);
            }
        }
        // Our request is complete, so we can release the resource.
        engineResource.release();
    }

资源的内存缓存,并回调展示,这里会进行请求期间的数据进行保存,然后同步回调完成后进行释放,保存到内存缓存中

    @SuppressWarnings("unchecked")
    @Override
    public void onEngineJobComplete(Key key, EngineResource<?> resource) {
        Util.assertMainThread();
        // A null resource indicates that the load failed, usually due to an exception.
        if (resource != null) {
            resource.setResourceListener(key, this);

            if (resource.isCacheable()) {
                activeResources.put(key, new ResourceWeakReference(key, resource, getReferenceQueue()));
            }
        }
        // TODO: should this check that the engine job is still current?
        jobs.remove(key);
    }

    @Override
    public void onResourceReleased(Key cacheKey, EngineResource resource) {
        Util.assertMainThread();
        activeResources.remove(cacheKey);
        if (resource.isCacheable()) {
            cache.put(cacheKey, resource);
        } else {
            resourceRecycler.recycle(resource);
        }
    }

三、总结

通过上面两部分的源码分析,可以知道Glide通过添加一个空白的fragment来做生命周期的监听,然后执行资源的回收。 Glide的缓存分为两层,内存缓存,磁盘缓存。有的博主说是有三次,那是算上了网络的一层。 在设置网络图片时,先从内存缓存读取,不存在就会到磁盘读取,还是没有就会就会进行网络获取图片数据。获取到数据之后会将图片保存到磁盘,然后加载图片到界面,再将图片保存到内存中。而图片的请求则是通过DataFetcher,可以是HttpUrlConnection,可以是okhttp,可以是volley来进行请求