Glide 是 Google的开源项目, Glide具有获取、解码和展示视频剧照、图片、动画等功能,它还有灵活的API,这些API使开发者能够将Glide应用在几乎任何网络协议栈里。创建Glide的主要目的有两个,一个是实现平滑的图片列表滚动效果,另一个是支持远程图片的获取、大小调整和展示。本篇博客,我们一起深入分析Glide的源码。

总体设计

with方法

首先我们来看一下glide的一般使用方法

Glide.with(this)
        .load("http://image.baidu.com/search/detail?ct=503316480&z=0&ipn=d&word=%E5%9B%BE%E7%89%87&hs=0&pn=0&spn=0&di=157484237350&pi=0&rn=1&tn=baiduimagedetail&is=0%2C0&ie=utf-8&oe=utf-8&cl=2&lm=-1&cs=4271053251%2C2424464488&os=2375022793%2C1835605452&simid=4247939438%2C550168575&adpicid=0&lpn=0&ln=30&fr=ala&fm=&sme=&cg=&bdtype=0&oriquery=&objurl=http%3A%2F%2Fpic55.nipic.com%2Ffile%2F20141208%2F19462408_171130083000_2.jpg&fromurl=ippr_z2C%24qAzdH3FAzdH3Fooo_z%26e3Bgtrtv_z%26e3Bv54AzdH3Fzi7wgptAzdH3F8c8n9d9_d_z%26e3Bip4s&gsm=0")
        .into(mImageView);

with方法主要就是用于创建RequestManager,这里是Glide通过Activity/Fragment生命周期管理Request原理所在,流程图如下:

那我们就从with方法入手,with方法传入的参数可以是Context,Activity,Fragment或FragmentActiviy,以FragmentActiviy为例子

public static RequestManager with(FragmentActivity activity) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(activity);
}

获取了RequestManagerRetriever,并调用了其get方法

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

判断是否在主线程中调用,如果是子线程中,则调用get(activity.getApplicationContext())

public RequestManager get(Context context) {
    if (context == null) {
        throw new IllegalArgumentException("You cannot start a load on a null Context");
    } else if (Util.isOnMainThread() && !(context instanceof Application)) {
        if (context instanceof FragmentActivity) {
            return get((FragmentActivity) context);
        } else if (context instanceof Activity) {
            return get((Activity) context);
        } else if (context instanceof ContextWrapper) {
            return get(((ContextWrapper) context).getBaseContext());
        }
    }

    return getApplicationManager(context);
}

很明显传入的context是ApplicationContext,所以会调用getApplicationManager(context)

private RequestManager getApplicationManager(Context context) {
    // Either an application context or we're on a background thread.
    if (applicationManager == null) {
        synchronized (this) {
            if (applicationManager == null) {
                // Normally pause/resume is taken care of by the fragment we add to the fragment or activity.
                // However, in this case since the manager attached to the application will not receive lifecycle
                // events, we must force the manager to start resumed using ApplicationLifecycle.
                applicationManager = new RequestManager(context.getApplicationContext(),
                        new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
            }
        }
    }

    return applicationManager;
}

创建了一个RequestManager,并将其返回,这里的ApplicationLifecycle很重要,下面会提到,再回到之前的get方法

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

如果在主线程中调用get方法,则会通过获取传入activity的FragmentManager,并将其传入到supportFragmentGet(activity, fm);方法中

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,SupportRequestManagerFragment 是一个无界面的Fragment类,起到把请求和Activity生命周期同步的作用。

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

可以看到 getSupportRequestManagerFragment中,会先去判断传入的FragmentManager 中是否已经绑定了这个SupportRequestManagerFragment ,没有就将其创建,并添加到FragmentManager 中

我们可以看到SupportRequestManagerFragment 中,生命周期的方法,都会同步调用lifecycle的相应方法

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

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

而这个lifecycle就是ActivityFragmentLifecycle,它将用了观察者模式,可以发现addListener就是添加观察者,然后每一个生命周期方法,同步通知给每一个listener

@Override
public void addListener(LifecycleListener listener) {
    lifecycleListeners.add(listener);

    if (isDestroyed) {
        listener.onDestroy();
    } else if (isStarted) {
        listener.onStart();
    } else {
        listener.onStop();
    }
}

void onStart() {
    isStarted = true;
    for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
        lifecycleListener.onStart();
    }
}

回到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 中的RequestManager,判断其是否存在,不在则进行创建,然后和SupportRequestManagerFragment 进行绑定,这里需要强调的是,构建RequestManager时,将SupportRequestManagerFragment 的lifecycle传入,我们看看RequestManager的构造函数里面

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.addListener方法,将RequestManager自身添加到lifecycle中,这里的巧妙之处,在于,SupportRequestManagerFragment 的生命周期的方法,都会同步通知lifecycle的所有Listener,所以SupportRequestManagerFragment 的生命周期都可同步通知RequestManager,这就是glide的巧妙之处。

上面还做了判断,如果这个RequestManager是application级别的,将其post到主线程中,再调用 lifecycle.addListener(RequestManager.this);方法,保证生命周期的同步效果

到这里,with方法的逻辑就执行完毕了,那么总结一下这个方法的作用,通过with方法中的参数不同,调用RequestManagerRetriever的get方法,最终创建一个空的Fragment 名为SupportRequestManagerFragment 并绑定一个RequestManager

load方法

with方法返回的是一个RequestManager,那么load方法的逻辑显然就是在RequestManager中

load调用处理流程图:

public DrawableTypeRequest<String> load(String string) {
    return (DrawableTypeRequest<String>) fromString().load(string);
}

会先调用fromString再调用load方法

public DrawableTypeRequest<String> fromString() {
    return loadGeneric(String.class);
}
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));
}

loadGeneric方法中创建了两个ModelLoader,分别是streamModelLoader 和fileDescriptorModelLoader,然后通过他们构造了一个DrawableTypeRequest

其实就是通过工厂模式创建相应的类型的ModelLoader,我们以Glide.buildStreamModelLoader为例

public static <T> ModelLoader<T, InputStream> buildStreamModelLoader(Class<T> modelClass, Context context) {
    return buildModelLoader(modelClass, InputStream.class, context);
}

这里传递了InputStream.class

public static <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass,
        Context context) {
     if (modelClass == null) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "Unable to load null model, setting placeholder only");
        }
        return null;
    }
    return Glide.get(context).getLoaderFactory().buildModelLoader(modelClass, resourceClass);
}

通过Glide.get(context).getLoaderFactory()获取GenericLoaderFactory并调用其buildModelLoader创建InputStream.class对应的ModelLoader

public synchronized <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass) {
    ModelLoader<T, Y> result = getCachedLoader(modelClass, resourceClass);
    if (result != null) {
        // We've already tried to create a model loader and can't with the currently registered set of factories,
        // but we can't use null to demonstrate that failure because model loaders that haven't been requested
        // yet will be null in the cache. To avoid this, we use a special signal model loader.
        if (NULL_MODEL_LOADER.equals(result)) {
            return null;
        } else {
            return result;
        }
    }

    final ModelLoaderFactory<T, Y> factory = getFactory(modelClass, resourceClass);
    if (factory != null) {
        result = factory.build(context, this);
        cacheModelLoader(modelClass, resourceClass, result);
    } else {
        // We can't generate a model loader for the given arguments with the currently registered set of factories.
        cacheNullLoader(modelClass, resourceClass);
    }
    return result;
}

getCachedLoader方法判断InputStream.class对应的ModelLoader是否已经创建过,也就是是否存在内存缓存中,有则返回

然后调用了getFactory方法,根据InputStream.class,创建其对应的ModelLoaderFactory

private <T, Y> ModelLoaderFactory<T, Y> getFactory(Class<T> modelClass, Class<Y> resourceClass) {
    Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> resourceToFactories = modelClassToResourceFactories.get(modelClass);
    ModelLoaderFactory/*T, Y*/ result = null;
    if (resourceToFactories != null) {
        result = resourceToFactories.get(resourceClass);
    }

    if (result == null) {
        for (Class<? super T> registeredModelClass : modelClassToResourceFactories.keySet()) {
            // This accounts for model subclasses, our map only works for exact matches. We should however still
            // match a subclass of a model with a factory for a super class of that model if if there isn't a
            // factory for that particular subclass. Uris are a great example of when this happens, most uris
            // are actually subclasses for Uri, but we'd generally rather load them all with the same factory rather
            // than trying to register for each subclass individually.
            if (registeredModelClass.isAssignableFrom(modelClass)) {
                Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> currentResourceToFactories =
                        modelClassToResourceFactories.get(registeredModelClass);
                if (currentResourceToFactories != null) {
                    result = currentResourceToFactories.get(resourceClass);
                    if (result != null) {
                        break;
                    }
                }
            }
        }
    }

    return result;
}

可以发现ModelLoaderFactory是保存在一个叫resourceToFactories的Map 中,而这个Map又是存储在名叫modelClassToResourceFactories的Map 中

然后是调用ModelLoaderFactory的build方法创建ModelLoader,然后通过cacheModelLoader方法将ModelLoader进行缓存起来

private <T, Y> void cacheModelLoader(Class<T> modelClass, Class<Y> resourceClass, ModelLoader<T, Y> modelLoader) {
    Map<Class/*Y*/, ModelLoader/*T, Y*/> resourceToLoaders = cachedModelLoaders.get(modelClass);
    if (resourceToLoaders == null) {
        resourceToLoaders = new HashMap<Class/*Y*/, ModelLoader/*T, Y*/>();
        cachedModelLoaders.put(modelClass, resourceToLoaders);
    }
    resourceToLoaders.put(resourceClass, modelLoader);
}

fromString的流程就分析完毕,然后回到RequestManager的load方法

public DrawableTypeRequest<String> load(String string) {
    return (DrawableTypeRequest<String>) fromString().load(string);
}

fromString返回DrawableTypeRequest,所以load方法在DrawableTypeRequest中

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

只是对我们传进来的图片的uri进行赋值

Into方法

into方法是加载图片的发起点,其逻辑在DrawableRequestBuilder类中

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

调用了GenericRequestBuilder的into方法

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

根据不同的ImageView 的ScaleType有不同的处理逻辑,applyCenterCrop()方法和 applyFitCenter()的实现都是在子类DrawableRequestBuilder中

public DrawableRequestBuilder<ModelType> fitCenter() {
    return transform(glide.getDrawableFitCenter());
}

然后调用了transform方法

public DrawableRequestBuilder<ModelType> transform(Transformation<GifBitmapWrapper>... transformation) {
    super.transform(transformation);
    return this;
}
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> transform(
        Transformation<ResourceType>... transformations) {
    isTransformationSet = true;
    if (transformations.length == 1) {
        transformation = transformations[0];
    } else {
        transformation = new MultiTransformation<ResourceType>(transformations);
    }

    return this;
}

其实就是对GenericRequestBuilder中的transformation 进行赋值,而这个transformation 是通过glide.getDrawableFitCenter()方法进行赋值

GifBitmapWrapperTransformation getDrawableFitCenter() {
    return drawableFitCenter;
}

而这个drawableFitCenter是在Glide的构造函数中进行赋值的

bitmapFitCenter = new FitCenter(bitmapPool);
drawableFitCenter = new GifBitmapWrapperTransformation(bitmapPool, bitmapFitCenter);

FitCenter是BitmapTransformation的子类,BitmapTransformation 实现了Transformation

接下来看一下GifBitmapWrapperTransformation的创建过程

public GifBitmapWrapperTransformation(BitmapPool bitmapPool, Transformation<Bitmap> bitmapTransformation) {
    this(bitmapTransformation, new GifDrawableTransformation(bitmapTransformation, bitmapPool));
}

传入了FitCenter和BitmapPool (此类很重要,后面会讲解),里面又创建了GifDrawableTransformation来包裹这两个参数

GifBitmapWrapperTransformation(Transformation<Bitmap> bitmapTransformation,
        Transformation<GifDrawable> gifDataTransformation) {
    this.bitmapTransformation = bitmapTransformation;
    this.gifDataTransformation = gifDataTransformation;
}

然后调用了glide.buildImageViewTarget(view, transcodeClass)

<R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) {
    return imageViewTargetFactory.buildTarget(imageView, transcodedClass);
}

这里的transcodedClass传入的是 GlideDrawable

public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) {
    if (GlideDrawable.class.isAssignableFrom(clazz)) {
        return (Target<Z>) new GlideDrawableImageViewTarget(view);
    } else if (Bitmap.class.equals(clazz)) {
        return (Target<Z>) new BitmapImageViewTarget(view);
    } else if (Drawable.class.isAssignableFrom(clazz)) {
        return (Target<Z>) new DrawableImageViewTarget(view);
    } else {
        throw new IllegalArgumentException("Unhandled class: " + clazz
                + ", try .as*(Class).transcode(ResourceTranscoder)");
    }
}

根据clazz的类型不同,构建不同的ImageViewTarget

public GlideDrawableImageViewTarget(ImageView view) {
    this(view, GlideDrawable.LOOP_FOREVER);
}

public GlideDrawableImageViewTarget(ImageView view, int maxLoopCount) {
    super(view);
    this.maxLoopCount = maxLoopCount;
}

无论哪种类型的ImageViewTarget都调用了父类ImageViewTarget的构造方法

public ImageViewTarget(ImageView view) {
    super(view);
}

public ViewTarget(T view) {
    if (view == null) {
        throw new NullPointerException("View must not be null!");
    }
    this.view = view;
    sizeDeterminer = new SizeDeterminer(view);
}
public SizeDeterminer(View view) {
    this.view = view;
}

然后这个GlideDrawableImageViewTarget会被传入到into方法中

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

判断之前针对这个imageView创建的GlideDrawableImageViewTarget是否已经创建了Request ,如果已经存在则进行清空,并从requestTracker中移除,如果之前从创建过,就首先调用buildRequest方法创建Request

private Request buildRequest(Target<TranscodeType> target) {
    if (priority == null) {
        priority = Priority.NORMAL;
    }
    return buildRequestRecursive(target, null);
}

这里有Request 优先级的设置

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方法中

GenericRequest<A, T, Z, R> request = (GenericRequest<A, T, Z, R>) REQUEST_POOL.poll();
if (request == null) {
    request = new GenericRequest<A, T, Z, R>();
}
request.init(loadProvider,
        model,
        signature,
        context,
        priority,
        target,
        sizeMultiplier,
        placeholderDrawable,
        placeholderResourceId,
        errorDrawable,
        errorResourceId,
        fallbackDrawable,
        fallbackResourceId,
        requestListener,
        requestCoordinator,
        engine,
        transformation,
        transcodeClass,
        isMemoryCacheable,
        animationFactory,
        overrideWidth,
        overrideHeight,
        diskCacheStrategy);
return request;

首先从REQUEST_POOL这个队列中拿出一个request,如果不存在,则新建一个,request的构造函数是空实现,其相关参数是在其init方法进行初始化的

{
    this.loadProvider = loadProvider;
    this.model = model;
    this.signature = signature;
    this.fallbackDrawable = fallbackDrawable;
    this.fallbackResourceId = fallbackResourceId;
    this.context = context.getApplicationContext();
    this.priority = priority;
    this.target = target;
    this.sizeMultiplier = sizeMultiplier;
    this.placeholderDrawable = placeholderDrawable;
    this.placeholderResourceId = placeholderResourceId;
    this.errorDrawable = errorDrawable;
    this.errorResourceId = errorResourceId;
    this.requestListener = requestListener;
    this.requestCoordinator = requestCoordinator;
    this.engine = engine;
    this.transformation = transformation;
    this.transcodeClass = transcodeClass;
    this.isMemoryCacheable = isMemoryCacheable;
    this.animationFactory = animationFactory;
    this.overrideWidth = overrideWidth;
    this.overrideHeight = overrideHeight;
    this.diskCacheStrategy = diskCacheStrategy;
    status = Status.PENDING;

    // We allow null models by just setting an error drawable. Null models will always have empty providers, we
    // simply skip our sanity checks in that unusual case.
    if (model != null) {
        check("ModelLoader", loadProvider.getModelLoader(), "try .using(ModelLoader)");
        check("Transcoder", loadProvider.getTranscoder(), "try .as*(Class).transcode(ResourceTranscoder)");
        check("Transformation", transformation, "try .transform(UnitTransformation.get())");
        if (diskCacheStrategy.cacheSource()) {
            check("SourceEncoder", loadProvider.getSourceEncoder(),
                    "try .sourceEncoder(Encoder) or .diskCacheStrategy(NONE/RESULT)");
        } else {
            check("SourceDecoder", loadProvider.getSourceDecoder(),
                    "try .decoder/.imageDecoder/.videoDecoder(ResourceDecoder) or .diskCacheStrategy(ALL/SOURCE)");
        }
        if (diskCacheStrategy.cacheSource() || diskCacheStrategy.cacheResult()) {
            // TODO if(resourceClass.isAssignableFrom(InputStream.class) it is possible to wrap sourceDecoder
            // and use it instead of cacheDecoder: new FileToStreamDecoder<Z>(sourceDecoder)
            // in that case this shouldn't throw
            check("CacheDecoder", loadProvider.getCacheDecoder(),
                    "try .cacheDecoder(ResouceDecoder) or .diskCacheStrategy(NONE)");
        }
        if (diskCacheStrategy.cacheResult()) {
            check("Encoder", loadProvider.getEncoder(),
                    "try .encode(ResourceEncoder) or .diskCacheStrategy(NONE/SOURCE)");
        }
    }
}

对request进行赋值,然后各种check校验,根据DiskCacheStrategy中策略的不同,一共4种策略,默认DiskCacheStrategy的策略是RESULT

public enum DiskCacheStrategy {
    /** Caches with both {@link #SOURCE} and {@link #RESULT}. */
    ALL(true, true),
    /** Saves no data to cache. */
    NONE(false, false),
    /** Saves just the original data to cache. */
    SOURCE(true, false),
    /** Saves the media item after all transformations to cache. */
    RESULT(false, true);

    private final boolean cacheSource;
    private final boolean cacheResult;

    DiskCacheStrategy(boolean cacheSource, boolean cacheResult) {
        this.cacheSource = cacheSource;
        this.cacheResult = cacheResult;
    }

    /**
     * Returns true if this request should cache the original unmodified data.
     */
    public boolean cacheSource() {
        return cacheSource;
    }

    /**
     * Returns true if this request should cache the final transformed result.
     */
    public boolean cacheResult() {
        return cacheResult;
    }
}

回到GenericRequestBuilder 的into方法中

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

将这个request 设置进GlideDrawableImageViewTarget中

public void setRequest(Request request) {
    setTag(request);
}

private void setTag(Object tag) {
    if (tagId == null) {
        isTagUsedAtLeastOnce = true;
        view.setTag(tag);
    } else {
        view.setTag(tagId, tag);
    }
}

其实就是将imageView和request 通过setTag方法进行绑定

然后将GlideDrawableImageViewTarget添加到lifecycle中,接着调用requestTracker.runRequest(request),执行这个request

public void runRequest(Request request) {
    requests.add(request);
    if (!isPaused) {
        request.begin();
    } else {
        pendingRequests.add(request);
    }
}

首先将request添加到requests中

private final Set<Request> requests = Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());

然后执行request的begin方法

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方法中调用了Engine的load方法,首先创建了一个EngineKey

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

通过这个key去查找缓存是否存在

EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);

private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {
        return null;
    }

    EngineResource<?> cached = getEngineResourceFromCache(key);
    if (cached != null) {
        cached.acquire();
        activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
    }
    return cached;
}

通过getEngineResourceFromCache方法获取EngineResource

private EngineResource<?> getEngineResourceFromCache(Key key) {
    Resource<?> cached = cache.remove(key);

    final EngineResource result;
    if (cached == null) {
        result = null;
    } else if (cached instanceof EngineResource) {
        // Save an object allocation if we've cached an EngineResource (the typical case).
        result = (EngineResource) cached;
    } else {
        result = new EngineResource(cached, true /*isCacheable*/);
    }
    return result;
}

先从cache中寻找资源,如果找到则将其从cache中移除并放入activeResources中,,activeResources是一个Map

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

然后如果资源在缓存中找到后会放入cb.onResourceReady(cached)进行回调,cb是ResourceCallback

如果loadFromCache找不到则调用loadFromActiveResources

private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
    if (!isMemoryCacheable) {
        return null;
    }

    EngineResource<?> active = null;
    WeakReference<EngineResource<?>> activeRef = activeResources.get(key);
    if (activeRef != null) {
        active = activeRef.get();
        if (active != null) {
            active.acquire();
        } else {
            activeResources.remove(key);
        }
    }

    return active;
}

其实就是从activeResources中获取EngineResource,如果能获取到EngineResource,则放入cb.onResourceReady进行回调

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

cache是LruResourceCache对象,作为资源的LRU缓存;activeResources是以弱引用为值的Map,用于缓存使用中的资源。比一般内存缓存额外多一级缓存的意义在于,当内存不足时清理cache中的资源时,不会对使用中的Bitmap造成影响。

以上两个缓存中都找不到的话,就会从jobs通过key获取EngineJob,如果EngineJob存在的话,则用其构造LoadStatus进行返回

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对象并调用其start方法,同时也创建了DecodeJob,将EngineJob和DecodeJob构造一个EngineRunnable

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

EngineJob的start方法执行EngineRunnable

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

diskCacheService的类型是ThreadPoolExecutor的子类FifoPriorityThreadPoolExecutor,也就是说将engineRunnable放入线程池中执行。

然后自然会执行到EngineRunnable的run方法

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

在EngineRunnable的run方法中进行编码,执行decode方法

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

根据缓存策略调用decodeFromCache或者decodeFromSource

private Resource<?> decodeFromSource() throws Exception {
    return decodeJob.decodeFromSource();
}

先看decodeFromSource,调用DecodeJob的decodeFromSource方法。

public Resource<Z> decodeFromSource() throws Exception {
    Resource<T> decoded = decodeSource();
    return transformEncodeAndTranscode(decoded);
}

先看decodeSource里面的逻辑

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

先通过DataFetcher访问网络获得文件流,接口DataFetcher的实现类根据配置而不同,我们看看HttpUrlFetcher的loadData方法的实现

@Override
public InputStream loadData(Priority priority) throws Exception {
    return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders());
}

其实内部就是建立网络链接,获取InputStream

private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers)
        throws IOException {
    if (redirects >= MAXIMUM_REDIRECTS) {
        throw new IOException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
    } else {
        // Comparing the URLs using .equals performs additional network I/O and is generally broken.
        // See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
        try {
            if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
                throw new IOException("In re-direct loop");
            }
        } catch (URISyntaxException e) {
            // Do nothing, this is best effort.
        }
    }
    urlConnection = connectionFactory.build(url);
    for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
      urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
    }
    urlConnection.setConnectTimeout(2500);
    urlConnection.setReadTimeout(2500);
    urlConnection.setUseCaches(false);
    urlConnection.setDoInput(true);

    // Connect explicitly to avoid errors in decoders if connection fails.
    urlConnection.connect();
    if (isCancelled) {
        return null;
    }
    final int statusCode = urlConnection.getResponseCode();
    if (statusCode / 100 == 2) {
        return getStreamForSuccessfulRequest(urlConnection);
    } else if (statusCode / 100 == 3) {
        String redirectUrlString = urlConnection.getHeaderField("Location");
        if (TextUtils.isEmpty(redirectUrlString)) {
            throw new IOException("Received empty or null redirect url");
        }
        URL redirectUrl = new URL(url, redirectUrlString);
        return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
    } else {
        if (statusCode == -1) {
            throw new IOException("Unable to retrieve response code from HttpUrlConnection.");
        }
        throw new IOException("Request failed " + statusCode + ": " + urlConnection.getResponseMessage());
    }
}

之后会将InputStream 传入decodeFromSourceData方法中

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

先将SourceWriter放入diskCacheProvider的DiskCache中,然后调用loadFromCache

private Resource<T> loadFromCache(Key key) throws IOException {
    File cacheFile = diskCacheProvider.getDiskCache().get(key);
    if (cacheFile == null) {
        return null;
    }

    Resource<T> result = null;
    try {
        result = loadProvider.getCacheDecoder().decode(cacheFile, width, height);
    } finally {
        if (result == null) {
            diskCacheProvider.getDiskCache().delete(key);
        }
    }
    return result;
}

根据需要将文件流写入磁盘缓存,再对文件流进行编码

public Resource<Bitmap> decode(InputStream source, int width, int height) {
    Bitmap bitmap = downsampler.decode(source, bitmapPool, width, height, decodeFormat);
    return BitmapResource.obtain(bitmap, bitmapPool);
}
ublic Bitmap decode(InputStream is, BitmapPool pool, int outWidth, int outHeight, DecodeFormat decodeFormat) {
    final ByteArrayPool byteArrayPool = ByteArrayPool.get();
    final byte[] bytesForOptions = byteArrayPool.getBytes();
    final byte[] bytesForStream = byteArrayPool.getBytes();
    final BitmapFactory.Options options = getDefaultOptions();

    // Use to fix the mark limit to avoid allocating buffers that fit entire images.
    RecyclableBufferedInputStream bufferedStream = new RecyclableBufferedInputStream(
            is, bytesForStream);
    // Use to retrieve exceptions thrown while reading.
    // TODO(#126): when the framework no longer returns partially decoded Bitmaps or provides a way to determine
    // if a Bitmap is partially decoded, consider removing.
    ExceptionCatchingInputStream exceptionStream =
            ExceptionCatchingInputStream.obtain(bufferedStream);
    // Use to read data.
    // Ensures that we can always reset after reading an image header so that we can still attempt to decode the
    // full image even when the header decode fails and/or overflows our read buffer. See #283.
    MarkEnforcingInputStream invalidatingStream = new MarkEnforcingInputStream(exceptionStream);
    try {
        exceptionStream.mark(MARK_POSITION);
        int orientation = 0;
        try {
            orientation = new ImageHeaderParser(exceptionStream).getOrientation();
        } catch (IOException e) {
            if (Log.isLoggable(TAG, Log.WARN)) {
                Log.w(TAG, "Cannot determine the image orientation from header", e);
            }
        } finally {
            try {
                exceptionStream.reset();
            } catch (IOException e) {
                if (Log.isLoggable(TAG, Log.WARN)) {
                    Log.w(TAG, "Cannot reset the input stream", e);
                }
            }
        }

        options.inTempStorage = bytesForOptions;

        final int[] inDimens = getDimensions(invalidatingStream, bufferedStream, options);
        final int inWidth = inDimens[0];
        final int inHeight = inDimens[1];

        final int degreesToRotate = TransformationUtils.getExifOrientationDegrees(orientation);
        final int sampleSize = getRoundedSampleSize(degreesToRotate, inWidth, inHeight, outWidth, outHeight);

        final Bitmap downsampled =
                downsampleWithSize(invalidatingStream, bufferedStream, options, pool, inWidth, inHeight, sampleSize,
                        decodeFormat);

        // BitmapFactory swallows exceptions during decodes and in some cases when inBitmap is non null, may catch
        // and log a stack trace but still return a non null bitmap. To avoid displaying partially decoded bitmaps,
        // we catch exceptions reading from the stream in our ExceptionCatchingInputStream and throw them here.
        final Exception streamException = exceptionStream.getException();
        if (streamException != null) {
            throw new RuntimeException(streamException);
        }

        Bitmap rotated = null;
        if (downsampled != null) {
            rotated = TransformationUtils.rotateImageExif(downsampled, pool, orientation);

            if (!downsampled.equals(rotated) && !pool.put(downsampled)) {
                downsampled.recycle();
            }
        }

        return rotated;
    } finally {
        byteArrayPool.releaseBytes(bytesForOptions);
        byteArrayPool.releaseBytes(bytesForStream);
        exceptionStream.release();
        releaseOptions(options);
    }
}

编码过程中通过设置采样率缩放图片,降低内存占用,提高加载性能。

private Bitmap downsampleWithSize(MarkEnforcingInputStream is, RecyclableBufferedInputStream  bufferedStream,
        BitmapFactory.Options options, BitmapPool pool, int inWidth, int inHeight, int sampleSize,
        DecodeFormat decodeFormat) {
    // Prior to KitKat, the inBitmap size must exactly match the size of the bitmap we're decoding.
    Bitmap.Config config = getConfig(is, decodeFormat);
    options.inSampleSize = sampleSize;
    options.inPreferredConfig = config;
    if ((options.inSampleSize == 1 || Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT) && shouldUsePool(is)) {
        int targetWidth = (int) Math.ceil(inWidth / (double) sampleSize);
        int targetHeight = (int) Math.ceil(inHeight / (double) sampleSize);
        // BitmapFactory will clear out the Bitmap before writing to it, so getDirty is safe.
        setInBitmap(options, pool.getDirty(targetWidth, targetHeight, config));
    }
    return decodeStream(is, bufferedStream, options);
}
private static Bitmap decodeStream(MarkEnforcingInputStream is, RecyclableBufferedInputStream bufferedStream,
        BitmapFactory.Options options) {
     if (options.inJustDecodeBounds) {
         // This is large, but jpeg headers are not size bounded so we need something large enough to minimize
         // the possibility of not being able to fit enough of the header in the buffer to get the image size so
         // that we don't fail to load images. The BufferedInputStream will create a new buffer of 2x the
         // original size each time we use up the buffer space without passing the mark so this is a maximum
         // bound on the buffer size, not a default. Most of the time we won't go past our pre-allocated 16kb.
         is.mark(MARK_POSITION);
     } else {
         // Once we've read the image header, we no longer need to allow the buffer to expand in size. To avoid
         // unnecessary allocations reading image data, we fix the mark limit so that it is no larger than our
         // current buffer size here. See issue #225.
         bufferedStream.fixMarkLimit();
     }

    final Bitmap result = BitmapFactory.decodeStream(is, null, options);

    try {
        if (options.inJustDecodeBounds) {
            is.reset();
        }
    } catch (IOException e) {
        if (Log.isLoggable(TAG, Log.ERROR)) {
            Log.e(TAG, "Exception loading inDecodeBounds=" + options.inJustDecodeBounds
                    + " sample=" + options.inSampleSize, e);
        }
    }

    return result;
}

这样返回的InpuStream就通过downsampleWithSize方法变为了Bitmap,如果设置了degreesToRotate(旋转的角度),就调用rotateImageExif设置

Bitmap rotated = null;
if (downsampled != null) {
    rotated = TransformationUtils.rotateImageExif(downsampled, pool, orientation);

    if (!downsampled.equals(rotated) && !pool.put(downsampled)) {
        downsampled.recycle();
    }
}
public static Bitmap rotateImageExif(Bitmap toOrient, BitmapPool pool, int exifOrientation) {
    final Matrix matrix = new Matrix();
    initializeMatrixForRotation(exifOrientation, matrix);
    if (matrix.isIdentity()) {
        return toOrient;
    }

    // From Bitmap.createBitmap.
    final RectF newRect = new RectF(0, 0, toOrient.getWidth(), toOrient.getHeight());
    matrix.mapRect(newRect);

    final int newWidth = Math.round(newRect.width());
    final int newHeight = Math.round(newRect.height());

    Bitmap.Config config = getSafeConfig(toOrient);
    Bitmap result = pool.get(newWidth, newHeight, config);
    if (result == null) {
        result = Bitmap.createBitmap(newWidth, newHeight, config);
    }

    matrix.postTranslate(-newRect.left, -newRect.top);

    final Canvas canvas = new Canvas(result);
    final Paint paint = new Paint(PAINT_FLAGS);
    canvas.drawBitmap(toOrient, matrix, paint);

    return result;
}

回到decodeFromSource方法

public Resource<Z> decodeFromSource() throws Exception {
    Resource<T> decoded = decodeSource();
    return transformEncodeAndTranscode(decoded);
}
private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded) {
    long startTime = LogTime.getLogTime();
    Resource<T> transformed = transform(decoded);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Transformed resource from source", startTime);
    }

    writeTransformedToCache(transformed);

    startTime = LogTime.getLogTime();
    Resource<Z> result = transcode(transformed);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Transcoded transformed from source", startTime);
    }
    return result;
}

transform方法调用了Transformation的transform方法

private Resource<T> transform(Resource<T> decoded) {
    if (decoded == null) {
        return null;
    }

    Resource<T> transformed = transformation.transform(decoded, width, height);
    if (!decoded.equals(transformed)) {
        decoded.recycle();
    }
    return transformed;
}

Transformation是接口;BitmapTransformation实现了该接口但留下了另一个抽象方法transform;CenterCrop和FitCenter两个类继承了BitmapTransformation并实现了抽象方法transform。

public final Resource<Bitmap> transform(Resource<Bitmap> resource, int outWidth, int outHeight) {
    if (!Util.isValidDimensions(outWidth, outHeight)) {
        throw new IllegalArgumentException("Cannot apply transformation on width: " + outWidth + " or height: "
                + outHeight + " less than or equal to zero and not Target.SIZE_ORIGINAL");
    }
    Bitmap toTransform = resource.get();
    int targetWidth = outWidth == Target.SIZE_ORIGINAL ? toTransform.getWidth() : outWidth;
    int targetHeight = outHeight == Target.SIZE_ORIGINAL ? toTransform.getHeight() : outHeight;
    Bitmap transformed = transform(bitmapPool, toTransform, targetWidth, targetHeight);

    final Resource<Bitmap> result;
    if (toTransform.equals(transformed)) {
        result = resource;
    } else {
        result = BitmapResource.obtain(transformed, bitmapPool);
    }

    return result;
}

接下来看一下CenterCrop的transform方法

protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
    final Bitmap toReuse = pool.get(outWidth, outHeight, toTransform.getConfig() != null
            ? toTransform.getConfig() : Bitmap.Config.ARGB_8888);
    Bitmap transformed = TransformationUtils.centerCrop(toReuse, toTransform, outWidth, outHeight);
    if (toReuse != null && toReuse != transformed && !pool.put(toReuse)) {
        toReuse.recycle();
    }
    return transformed;
}

由BitmapPool提供一个Bitmap作为下一步的Canvas载体。BitmapPool的实现类是LruBitmapPool,顾名思义是一个基于LRU方式的Bitmap缓存池,用于Bitmap的复用。

接下来是TransformationUtils的centerCrop方法

public static Bitmap centerCrop(Bitmap recycled, Bitmap toCrop, int width, int height) {
    if (toCrop == null) {
        return null;
    } else if (toCrop.getWidth() == width && toCrop.getHeight() == height) {
        return toCrop;
    }
    // From ImageView/Bitmap.createScaledBitmap.
    final float scale;
    float dx = 0, dy = 0;
    Matrix m = new Matrix();
    if (toCrop.getWidth() * height > width * toCrop.getHeight()) {
        scale = (float) height / (float) toCrop.getHeight();
        dx = (width - toCrop.getWidth() * scale) * 0.5f;
    } else {
        scale = (float) width / (float) toCrop.getWidth();
        dy = (height - toCrop.getHeight() * scale) * 0.5f;
    }

    m.setScale(scale, scale);
    m.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
    final Bitmap result;
    if (recycled != null) {
        result = recycled;
    } else {
        result = Bitmap.createBitmap(width, height, getSafeConfig(toCrop));
    }

    // We don't add or remove alpha, so keep the alpha setting of the Bitmap we were given.
    TransformationUtils.setAlpha(toCrop, result);

    Canvas canvas = new Canvas(result);
    Paint paint = new Paint(PAINT_FLAGS);
    canvas.drawBitmap(toCrop, m, paint);
    return result;
}

在TransformationUtils的centerCrop方法中,根据目标尺寸调整矩阵并绘制结果。

FitCenter类的逻辑与centerCrop类相似,回到DecodeJob的transformEncodeAndTranscode方法

接下来调用writeTransformedToCache将转换结果写入磁盘缓存,

private void writeTransformedToCache(Resource<T> transformed) {
    if (transformed == null || !diskCacheStrategy.cacheResult()) {
        return;
    }
    long startTime = LogTime.getLogTime();
    SourceWriter<Resource<T>> writer = new SourceWriter<Resource<T>>(loadProvider.getEncoder(), transformed);
    diskCacheProvider.getDiskCache().put(resultKey, writer);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Wrote transformed from source to cache", startTime);
    }
}

再调用transcode方法进行转码

private Resource<Z> transcode(Resource<T> transformed) {
    if (transformed == null) {
        return null;
    }
    return transcoder.transcode(transformed);
}

transcode方法中的transcoder的实际类型是GlideBitmapDrawableTranscoder

public Resource<GlideBitmapDrawable> transcode(Resource<Bitmap> toTranscode) {
    GlideBitmapDrawable drawable = new GlideBitmapDrawable(resources, toTranscode.get());
    return new GlideBitmapDrawableResource(drawable, bitmapPool);
}

GlideBitmapDrawableTranscoder的transcode方法将Bitmap资源进行封装

public GlideBitmapDrawableResource(GlideBitmapDrawable drawable, BitmapPool bitmapPool) {
    super(drawable);
    this.bitmapPool = bitmapPool;
}

到这里就结束了decodeFromSource的流程。

接下来看decodeFromCache

private Resource<?> decodeFromCache() throws Exception {
    Resource<?> result = null;
    try {
        result = decodeJob.decodeResultFromCache();
    } catch (Exception e) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "Exception decoding result from cache: " + e);
        }
    }

    if (result == null) {
        result = decodeJob.decodeSourceFromCache();
    }
    return result;
}

先调用DecodeJob的decodeResultFromCache方法获取,获取失败则调用DecodeJob的decodeSourceFromCache方法

public Resource<Z> decodeResultFromCache() throws Exception {
    if (!diskCacheStrategy.cacheResult()) {
        return null;
    }

    long startTime = LogTime.getLogTime();
    Resource<T> transformed = loadFromCache(resultKey);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Decoded transformed from cache", startTime);
    }
    startTime = LogTime.getLogTime();
    Resource<Z> result = transcode(transformed);
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logWithTimeAndKey("Transcoded transformed from cache", startTime);
    }
    return result;
}

decodeResultFromCache方法从磁盘缓存中获取对应Bitmap并将其转码

public Resource<Z> decodeSourceFromCache() throws Exception {
    if (!diskCacheStrategy.cacheSource()) {
        return null;
    }

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

decodeSourceFromCache方法从磁盘缓存中获取对应Bitmap并将其转换(因为是原尺寸,需要调整大小)

EngineRunnable的decode是decodeFromCache和decodeFromSource二选一,decodeFromCache也获取失败的话会怎么样呢?

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

缓存中没有结果的情况下会调用onLoadFailed方法

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

public void submitForSource(EngineRunnable runnable) {
    future = sourceService.submit(runnable);
}

变更缓存策略重新放入线程池中执行,也就是从网络获取。这里的线程池是sourceService而不是上面的diskCacheService,

得到了处理结果,接下来调用EngineRunnable的onLoadComplete方法将结果传入

private void onLoadComplete(Resource resource) {
    manager.onResourceReady(resource);
}

onLoadComplete方法调用了EngineJob的onResourceReady方法

public void onResourceReady(final Resource<?> resource) {
    this.resource = resource;
    MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
private static class MainThreadCallback implements Handler.Callback {

    @Override
    public boolean handleMessage(Message message) {
        if (MSG_COMPLETE == message.what || MSG_EXCEPTION == message.what) {
            EngineJob job = (EngineJob) message.obj;
            if (MSG_COMPLETE == message.what) {
                job.handleResultOnMainThread();
            } else {
                job.handleExceptionOnMainThread();
            }
            return true;
        }

        return false;
    }
}

关键在handleResultOnMainThread中

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

onResourceReady方法中向Handler传递消息并由MainThreadCallback处理消息 ,也就切换到了主线程。handleResultOnMainThread方法会调用GenericRequest的onResourceReady方法

public void onResourceReady(Resource<?> resource) {
    if (resource == null) {
        onException(new Exception("Expected to receive a Resource<R> with an object of " + transcodeClass
                + " inside, but instead got null."));
        return;
    }

    Object received = resource.get();
    if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
        releaseResource(resource);
        onException(new Exception("Expected to receive an object of " + transcodeClass
                + " but instead got " + (received != null ? received.getClass() : "") + "{" + received + "}"
                + " inside Resource{" + resource + "}."
                + (received != null ? "" : " "
                    + "To indicate failure return a null Resource object, "
                    + "rather than a Resource object containing null data.")
        ));
        return;
    }

    if (!canSetResource()) {
        releaseResource(resource);
        // We can't set the status to complete before asking canSetResource().
        status = Status.COMPLETE;
        return;
    }

    onResourceReady(resource, (R) received);
}
private void onResourceReady(Resource<?> resource, R result) {
    // We must call isFirstReadyResource before setting status.
    boolean isFirstResource = isFirstReadyResource();
    status = Status.COMPLETE;
    this.resource = resource;

    if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache,
            isFirstResource)) {
        GlideAnimation<R> animation = animationFactory.build(loadedFromMemoryCache, isFirstResource);
        target.onResourceReady(result, animation);
    }

    notifyLoadSuccess();

    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logV("Resource ready in " + LogTime.getElapsedMillis(startTime) + " size: "
                + (resource.getSize() * TO_MEGABYTE) + " fromCache: " + loadedFromMemoryCache);
    }
}

onResourceReady方法调用GlideDrawableImageViewTarget的onResourceReady方法

public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> animation) {
    if (!resource.isAnimated()) {
        //TODO: Try to generalize this to other sizes/shapes.
        // This is a dirty hack that tries to make loading square thumbnails and then square full images less costly
        // by forcing both the smaller thumb and the larger version to have exactly the same intrinsic dimensions.
        // If a drawable is replaced in an ImageView by another drawable with different intrinsic dimensions,
        // the ImageView requests a layout. Scrolling rapidly while replacing thumbs with larger images triggers
        // lots of these calls and causes significant amounts of jank.
        float viewRatio = view.getWidth() / (float) view.getHeight();
        float drawableRatio = resource.getIntrinsicWidth() / (float) resource.getIntrinsicHeight();
        if (Math.abs(viewRatio - 1f) <= SQUARE_RATIO_MARGIN
                && Math.abs(drawableRatio - 1f) <= SQUARE_RATIO_MARGIN) {
            resource = new SquaringDrawable(resource, view.getWidth());
        }
    }
    super.onResourceReady(resource, animation);
    this.resource = resource;
    resource.setLoopCount(maxLoopCount);
    resource.start();
}

GlideDrawableImageViewTarget的onResourceReady方法调用其父类ImageViewTarget的onResourceReady方法

public void onResourceReady(Z resource, GlideAnimation<? super Z> glideAnimation) {
    if (glideAnimation == null || !glideAnimation.animate(resource, this)) {
        setResource(resource);
    }
}

ImageViewTarget的onResourceReady方法中调用的抽象方法setResource在子类GlideDrawableImageViewTarget中实现,该方法中调用了ImageView的setImageDrawable方法设置图像。至此,整个加载流程就完成了。

protected void setResource(GlideDrawable resource) {
    view.setImageDrawable(resource);
}

最后简单归纳一下整个加载流程的图

深入解析Glide源码的更多相关文章

  1. Glide源码导读

    最近比较无聊,为了找点事干,就花了两天时间把Glide的源码大概看了一下.刚开始看Glide的源码头脑还是比较乱的,因为作者引入了几个概念,又大量用了泛型,如果不了解这些概念读起代码来就比较痛苦,我也 ...

  2. Python解析器源码加密系列之(二):一次使用标准c的FILE*访问内存块的尝试

    摘要:由于近期打算修改Python解释器以实现pyc文件的加密/解密,出于保密的要求,解密之后的数据只能放在内存中,不能写入到文件中.但是后续的解析pyc文件的代码又只能接受FILE*作为入参,所以就 ...

  3. HtmlAgilityPack --解析Html源码

    最近项目需要从网络上抓取一下数据解析Html源码,奈何正则表达式难写,于是网上搜索找到了“ HtmlAgilityPack”类库,敏捷开发,果然效率非同寻常. 在此做笔记,写下心得,顺便给自己总结一下 ...

  4. mvc5 解析route源码实现自己的route系统

    Asp.net mvc5 解析route源码实现自己的route系统   url route 路由系统的责任是找到匹配的路由,创建路由数据,并将请求分配给一个处理程序. 选择动作是 MVC 的处理程序 ...

  5. 浩哥解析MyBatis源码(十)——Type类型模块之类型处理器

    原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6715063.html 1.回顾 之前的两篇分别解析了类型别名注册器和类型处理器注册器,此二 ...

  6. 解析 ViewTreeObserver 源码(下)

    继上篇内容,本文介绍 ViewTreeObserver 的使用,以及体会其所涉及的观察者模式,期间会附带回顾一些基础知识.最后,我们简单聊一下 Android 的消息传递,附高清示意图,轻松捋清整个传 ...

  7. Jsoup解析网页源码时常用的Element(s)类

    Jsoup解析网页源码时常用的Element(s)类 一.简介 该类是Node的直接子类,同样实现了可克隆接口.类声明:public class Element extends Node 它表示由一个 ...

  8. 用Beautiful Soup解析html源码

    #xiaodeng #python3 #用Beautiful Soup解析html源码 html_doc = """ <html> <head> ...

  9. 二十三、并发编程之深入解析Condition源码

    二十三.并发编程之深入解析Condition源码   一.Condition简介 1.Object的wait和notify/notifyAll方法与Condition区别 任何一个java对象都继承于 ...

随机推荐

  1. Django-MTV(Day66)

    阅读目录 Django基本命令 视图层路由配置系统 视图层之视图函数 MTV模型 Django的MTV分别代表: Model(模型):负责业务对象与数据库的对象(ORM) Template(模板):负 ...

  2. save a web page as a single file (mht format) using Delphi code

    Here's how to save a web page as a single file (mht format) using Delphi code: uses CDO_TLB, ADODB_T ...

  3. HihoCoder - 1339 Dice Possibility(概率dp)

    题意:求用N(1<=N<=100)个骰子掷出M(1<=M<=600)的概率 分析:直接求概率可能出现6^100次方,会爆精度.可以用一个数组dp[i][j]记录用i个骰子掷出j ...

  4. linux中相关服务不能访问的排错技巧

    Linux相关服务不能访问的排错步骤,以HTTP服务为例: 一.服务端排查思路: 1.检查SELinux是否关闭(针对CentOS6系统)  (1)临时关闭      setenforce 0  (2 ...

  5. 菩提树下的杨过.Net 的《hadoop 2.6全分布安装》补充版

    对菩提树下的杨过.Net的这篇博客<hadoop 2.6全分布安装>,我真是佩服的五体投地,我第一次见过教程能写的这么言简意赅,但是又能比较准确表述每一步做法的,这篇博客主要就是在他的基础 ...

  6. iconfont的使用

    首先你要有一个图标库的账号,我们使用的是阿里矢量图标库,其次你要有一套已经设计好的图标原图.如果你具备了这些,就可以和我一起看iconfont的使用姿势了. 写在前面 不结合其他矢量库或UI框架一起使 ...

  7. Linux centos7 zookeeper集群搭建

    Zookeeper集群搭建 描述:本章节主要单服务器搭建集群,在一个服务器上启动多个不同端口的zookeeper服务,非真实环境. 真实环境下zookeeper集群会搭建在多个物理服务器上,并非单一的 ...

  8. 王译潇20162314 实验报告三plus结对编程四则运算第一阶段

    北京电子科技学院BESTI实验报告 课程:程序设计与数据结构 班级: 1623 姓名: 王译潇 学号:20162314 指导教师:娄佳鹏老师.王志强老师 实验日期:2017年5月12号 实验密级: 非 ...

  9. React Native 常用学习链接地址

    Android Studio下载http://www.android-studio.org/ 第二章:Android Studio概述(一)http://ask.android-studio.org/ ...

  10. bzoj 3479: [Usaco2014 Mar]Watering the Fields

    3479: [Usaco2014 Mar]Watering the Fields Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 174  Solved ...