glide源码解析

Glide源码解析

在项目中用到了Glide来加载网络图片,于是想写篇文章来分析下Glide的源码,但是Glide里面的源码非常多,下面主要是从面试的角度来把一些重要的点提一下。
在理解glide的源码前,首先看下它怎么用的, 最常见的glide的用法很简单就是下面的这句代码
Glide.with(MainActivity.this).load(url).into(img1)
这篇文章就来分析一下,这句代码的实现原理。

with

首先,查看下 with的源码

    /**
     * Begin a load with Glide that will tied to the give {@link android.support.v4.app.FragmentActivity}'s lifecycle
     * and that uses the given {@link android.support.v4.app.FragmentActivity}'s default options.
     *
     * @param activity The activity to use.
     * @return A RequestManager for the given FragmentActivity that can be used to start a load.
     */
    public static RequestManager with(FragmentActivity activity) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(activity);
    }

就是返回一个 RequestManagerRetriever 对象,这个RequestManagerRetriever 对象是用来图片加载请求的管理类。它继承于LifeCycleListener,这个是用来管理生命周期,而这个生命周期其实是和我们的activity,fragment所绑定的。这样我们才能把我们的reqeust绑定到我们的activity当中。对于请求我们可以甚至可以做暂停和取消操作。RequestManagerRetriever里这个类的主要作用是将我们的activity和我们的request绑定。
Glide的特点就是能够绑定到组件当中,比如我们自定义的fragment,activity等,通过组件的生命周期来进行请求的处理。这个是它的一个非常重要的特性。

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

进入get方法,我们可以看到,调用了Util.isOnBackgroundThread()方法,这个方法里其实就是判断是否在主线程里面的一个方法,里面是通过Android里面的Looper类来进行判断。也就是这里主要判断如果非主线程的话,会通过全局的context来获得requestmanager,如果是在主线程中的话,则会进入assertNotDestroyed方法。

  @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    private static void assertNotDestroyed(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed()) {
            throw new IllegalArgumentException("You cannot start a load for a destroyed activity");
        }
    }

这个assertNotDestroyed其实就是判断如果activity被销毁就抛出一个IllegalArgumentException。在glide里面RequestManagerRetriever 都是通过与activity生命周期做绑定的,如果一个actiivty被销毁的话,那么接下来的代码肯定是没必要去执行的。
没被销毁的activity返回一个FragmentManager ,然后通过这个FragmentManger返回一个RequestManager。我们进入RequestManagerRetriever.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;
    }

SupportRequestManagerFragment 这个类是一个封装的fragment对象,在supportFragmentGet方法的第二步里面创建一个新的requestmanager对象,并且在构造函数里面传入lifecycle,这个跟requestmanager是相互关联的。最后返回一个requestManager对象。
这个requestManager类里面具体是怎么实现的,我们进入源码看一下

public class RequestManager implements LifecycleListener {
    private final Context context;
    private final Lifecycle lifecycle;
    private final RequestManagerTreeNode treeNode;
    private final RequestTracker requestTracker;
    private final Glide glide;
    private final OptionsApplier optionsApplier;
    private DefaultOptions options;

    public RequestManager(Context context, Lifecycle lifecycle, RequestManagerTreeNode treeNode) {
        this(context, lifecycle, treeNode, new RequestTracker(), new ConnectivityMonitorFactory());
    }

    RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode,
            RequestTracker requestTracker, ConnectivityMonitorFactory factory) {
        this.context = context.getApplicationContext();
        this.lifecycle = lifecycle;
        this.treeNode = treeNode;
        this.requestTracker = requestTracker;
        this.glide = Glide.get(context);
        this.optionsApplier = new OptionsApplier();

        ConnectivityMonitor connectivityMonitor = factory.build(context,
                new RequestManagerConnectivityListener(requestTracker));

        // If we're the application level request manager, we may be created on a background thread. In that case we
        // cannot risk synchronously pausing or resuming requests, so we hack around the issue by delaying adding
        // ourselves as a lifecycle listener by posting to the main thread. This should be entirely safe.
        if (Util.isOnBackgroundThread()) {
            new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    lifecycle.addListener(RequestManager.this);
                }
            });
        } else {
            lifecycle.addListener(this);
        }
        lifecycle.addListener(connectivityMonitor);
    }

这里在构造参数里面看到传入两个非常重要的东西,一个是Lifecycle对象,另外一个是RequestTracker 。RequestTracker 是用来跟踪我们的请求对象是否取消,是否暂停,是否完成,它会监听其状态。
这里来总结一下,SupportRequestManagerFragment就是一个封装的fagment,它是用来连接fragment和我们的requestmanager,然后另外一个很重要的东西就是RequestManager,它是所有图片的一个管理类。它是用来实现我们生命周期方法的。
好了,with方法里面需要关注的内容就是这些。
##load

   /**
     * Returns a request builder to load the given {@link java.lang.String}.
     * signature.
     *
     * @see #fromString()
     * @see #load(Object)
     *
     * @param string A file path, or a uri or url handled by {@link com.bumptech.glide.load.model.UriLoader}.
     */
    public DrawableTypeRequest<String> load(String string) {
        return (DrawableTypeRequest<String>) fromString().load(string);
    }

DrawableTypeRequest就是一个管理图片的请求类,不仅可以加载GIF图片也可以直接加载Bitmap。它的父类DrawableRequestBuilder里面,我们看一下他的构造函数

    DrawableRequestBuilder(Context context, Class<ModelType> modelClass,
            LoadProvider<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable> loadProvider, Glide glide,
            RequestTracker requestTracker, Lifecycle lifecycle) {
        super(context, modelClass, loadProvider, GlideDrawable.class, glide, requestTracker, lifecycle);
        // Default to animating.
        crossFade();
    }

构造函数里面有Lifecycle RequestTracker,这些跟刚才Requestmanager里面差不多的类。load方法里面做的就一些赋值的操作。
##into
当我们做好with和load方法后,最后一步是into,也是最麻烦的一步。

   @Override
    public Target<GlideDrawable> into(ImageView view) {
        return super.into(view);
    }

调用了父类GenericRequestBuilder的into,我们来看下GenericRequestBuilder的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));
    }

核心是调用了into方法,我们来看下

/**
     * Set the target the resource will be loaded into.
     *
     * @see Glide#clear(com.bumptech.glide.request.target.Target)
     *
     * @param target The target to load the resource into.
     * @return The given target.
     */
    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,target我们理解成view就行了。因为我们更新都要放在主线程中去执行,所有第一句代码是断言我们是否在主线程中。通过target.getRequest方法来获得请求。如果之前的请求不为空的话,则清空之前的请求。然后我们再会去创建一个新的request,通过buildRequest方法。
调用setRequest和addListener把我们的imagview跟lifecycler关联起来,调用runRequest。
最后返回这个request对象。
看一下buildRequest方法

    private Request buildRequest(Target<TranscodeType> target) {
        if (priority == null) {
            priority = Priority.NORMAL;
        }
        return buildRequestRecursive(target, null);
    }
  private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
        if (thumbnailRequestBuilder != null) {
            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()");
            }
            // Recursive case: contains a potentially recursive thumbnail request builder.
            if (thumbnailRequestBuilder.animationFactory.equals(NoAnimation.getFactory())) {
                thumbnailRequestBuilder.animationFactory = animationFactory;
            }

            if (thumbnailRequestBuilder.priority == null) {
                thumbnailRequestBuilder.priority = getThumbnailPriority();
            }

            if (Util.isValidDimensions(overrideWidth, overrideHeight)
                    && !Util.isValidDimensions(thumbnailRequestBuilder.overrideWidth,
                            thumbnailRequestBuilder.overrideHeight)) {
              thumbnailRequestBuilder.override(overrideWidth, overrideHeight);
            }

            ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
            Request fullRequest = obtainRequest(target, sizeMultiplier, priority, coordinator);
            // Guard against infinite recursion.
            isThumbnailBuilt = true;
            // Recursively generate thumbnail requests.
            Request thumbRequest = thumbnailRequestBuilder.buildRequestRecursive(target, coordinator);
            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, sizeMultiplier, priority, coordinator);
            Request thumbnailRequest = obtainRequest(target, thumbSizeMultiplier, getThumbnailPriority(), coordinator);
            coordinator.setRequests(fullRequest, thumbnailRequest);
            return coordinator;
        } else {
            // Base case: no thumbnail.
            return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
        }
    }

代码虽然很多,但绝大部分只是逻辑上的判断,最终调用obtainRequest方法

private Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority,
            RequestCoordinator requestCoordinator) {
        return GenericRequest.obtain(
                loadProvider,
                model,
                signature,
                context,
                priority,
                target,
                sizeMultiplier,
                placeholderDrawable,
                placeholderId,
                errorPlaceholder,
                errorId,
                fallbackDrawable,
                fallbackResource,
                requestListener,
                requestCoordinator,
                glide.getEngine(),
                transformation,
                transcodeClass,
                isCacheable,
                animationFactory,
                overrideWidth,
                overrideHeight,
                diskCacheStrategy);
    }

最终调用父类的obtain方法,我们只用大概知道 在obtain方法里面完成request的各种参数的初始化工作,有深入研究的同学可以再进入到这个方法里面。这里创建request的过程就这样子结束。
回到into方法的代码里面,我们看到有个runRequest方法。找到runRequest方法的源码,在RequestTracker里面。

 /**
     * Starts tracking the given request.
     */
    public void runRequest(Request request) {
        requests.add(request);
        if (!isPaused) {
            request.begin();
        } else {
            pendingRequests.add(request);
        }
    }

ok,在这里面请求被放在一个set集合里面进行管理,最后调用请求的begin开始加载。而request .begin的真正实现是在GenericRequest的begin方法里面

    @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));
        }
    }

首先赋值了状态,图片的状态设置成Status.WAITING_FOR_SIZE,然后对图片的长宽高进行计算,如果长宽高小于0的话,那么就要重新对其进行计算。如果长宽高都正常,onSizeReady对图片加载做一些准备工作。然后在我们图片调用成功以后,它会调用一个onLoadStart方法。接下来我们来看下onSizeReady的代码:

 @Override
    public void onSizeReady(int width, int height) {
      ... ....
      
        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));
        }
    }

这里有个非常重要的方法,engine.load方法,engine对象是一个Engine类,主要用来管理图片开始加载后,一些活动图片资源,缓存图片资源,里面分装了线程池,给我们图片加载请求。来看下Engine类和它里面的load方法:


public class Engine implements EngineJobListener,
        MemoryCache.ResourceRemovedListener,
        EngineResource.ResourceListener {
    private static final String TAG = "Engine";
    private final Map<Key, EngineJob> jobs;
    private final EngineKeyFactory keyFactory;
    private final MemoryCache cache;
    private final EngineJobFactory engineJobFactory;
    private final Map<Key, WeakReference<EngineResource<?>>> activeResources;
    private final ResourceRecycler resourceRecycler;
    private final LazyDiskCacheProvider diskCacheProvider;
 
    private ReferenceQueue<EngineResource<?>> resourceReferenceQueue;

   ... ...
 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);
    }

在load方法里面,看到enginekey是一个key值,它的作用就是从池中取出。
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
从上面这句代码看到,首先它会从缓存中去加载图片,如果图片获取成功的话,会调用onResouceReady方法。
如果从缓存中没有获取到相应的图片的话,这时候会从活动的图片资源中去获得,执行loadFromActiveResources方法。如果图片从活动资源的缓存中获取到的话,也会进入onResouceReady方法。
EngineJob是一个添加和删除回调接口的管理类。通过创建EngineJob后我们看到最终是创建了一个EngineRunnable对象,EngineRunnable顾名思义就是开启了一个子线程,接着调用它的start方法。看一下EngineJob的start方法。

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

执行了GlideExecutor的execute方法,而这个GlideExecutor进去一看。

final class GlideExecutor extends ThreadPoolExecutor

ThreadPoolExecutor是线程池,这样我们就大概地知道了,
到了最终Glide还是将我们的图片请求交给了线程池去处理。这样就大概明白了glide图片加载的原理。

好了,Glide的源码分析到这里结束,由于本人精力和能力有限,无法很深入地进行理解,也没有对细节进行深究,这里只是浅显的分析了基本用法的实现原理,以及glide内部加载图片是调用了ThreadPoolExecutor,交由线程池去处理的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值