其他分享
首页 > 其他分享> > 你真的懂了Glide图片框架了吗?它来了,它来了,它带着资源走来了...

你真的懂了Glide图片框架了吗?它来了,它来了,它带着资源走来了...

作者:互联网

简言:

       之前写过关于Glide的文章,都是一些如何使用的案例,比较注重使用了,没有考虑它的源码是如何实现的,今天为大家讲解一下源码,从源码的角度让你了解Glide这个神奇的图片框架。

1.Gilde 简介

在泰国举行的谷歌发布者论坛上,谷歌为我们介绍了一个叫Gilde的图片加载库,作者是bumptech。

这个库被广泛的运用在goole的开源项目中,包括2014年goole I/O大会上发布的官方app

2.使用gilde的优点:

1)使用简单

2)可支配度高,自适应程度高

3)支持常见图片格式 jpg png gif webp

4)支持多种数据源,网络,本地资源,assets等

5)高效缓存策略,支持Memory 和Disk图片缓存,默认bitmap格式采用RGB_565内存至少减少一半

6)生命周期集成,根据activity/Fragment生命周期自动管理请求

7)高效处理bitmap 使用bitmap pool使bitmap复用,主动调用recycle回收需要回收的bitmap,减少系统回收压力。

3.Glide的基本概念

Model它代表图片的数据源,例如URL,本地文件,然后通过ModelLoader从数据源中获取原始数据Data,在对原始数据Data进行Decoder解码,解码之后的资源Resource,并通过Transform进行图片的裁剪转换,转换之后的资源我们称之为TransformResource,转换之后我们还需要对图像进行Transcode转码操作,转码之后的资源我们就称之为TranscodedResource,最后将我们所显示的资源封装成Target,并进行显示。这就是Glide图片加载的整体流程,

4.通过源码进行分析

1)我们针对Glide3.7这个版本进行源码分析简介,这个版本相对于还是比较稳定的。

compile 'com.github.bumptech.glide:glide:3.7.0'

2)简单实用的代码:

    Glide
                .with(getApplicationContext())
                .load(url)
                .into(imageView);

我们几乎都会这么简单的使用了,这里没什么好讲的了,接下来我们看一下他复杂的使用,我们并对每一个属性进行讲解,我们看代码:

  Glide.with(getApplicationContext()) // 指定Context
                .load(url)// 指定图片的URL
                .placeholder(R.mipmap.ic_launcher)// 指定图片未成功加载前显示的图片
                .error(R.mipmap.ic_launcher)// 指定图片加载失败显示的图片
                .override(300, 300)//指定图片的尺寸
                .fitCenter()//指定图片缩放类型为
                .centerCrop()// 指定图片缩放类型为
                .skipMemoryCache(true)// 跳过内存缓存
                .diskCacheStrategy(DiskCacheStrategy.NONE)//跳过磁盘缓存
                .diskCacheStrategy(DiskCacheStrategy.SOURCE)//仅仅只缓存原来的全分辨率的图像
                .diskCacheStrategy(DiskCacheStrategy.RESULT)//仅仅缓存最终的图像
                .diskCacheStrategy(DiskCacheStrategy.ALL)//缓存所有版本的图像
                .priority(Priority.HIGH)//指定优先级.Glide将会用他们作为一个准则,并尽可能的处理这些请求,但是它不能保证所有的图片都会按照所要求的顺序加载。优先级排序:IMMEDIATE > HIGH > NORMAL > LOW
                .into(imageView);//指定显示图片的Imageview

这里说个题外话,注意到我们with方法传递的上下文了吗?如果传入的是当前activity的上下文,或者传递的是getApplicationContext,他们分别代表什么?

当传入的是activity被销毁时,这个图片加载的生命周期也会被销毁,反之,如果山下文传递的是getApplicationContext时,只有程序被销毁时,图片加载的生命周期才会被销毁。

其它属性的配置在代码中已经做了标注,就不做过多的解释了,我们下边会对每一个参数进行源码分析,我们针对几个需要注意的点进行讲解一下:

1)placeholder这个方法:不要加载网络图片,加载本地图片,本身该方法主要解决网络慢时,指定的占位图,如果在加载网络图片,该方法就没有意义了,这里注意一下。

2)override这个方法主要解决的就是内存浪费,防止内存溢出泄露等。

3)fitCenter,centerCrop,这两个方法主要防止图片失真,显示模糊,做的处理。

 

3.源码分析

1)首先我们看with方法的源码:

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

 
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static RequestManager with(android.app.Fragment fragment) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(fragment);
    }

为什么with这么多重载方法,其实这个设计非常好,因为传入不同的参数,所对应的图片加载的生命周期就会不同,所以才设置这么多的重载方法,

我们继续看retriever.get()方法:

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

(Util.isOnMainThread() && !(context instanceof Application),首先判断是否是主线程,然后判断传递过来的上下文,如果是Application的,它会走return 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这个唯一的实例,

所以这个with方法,的核心源码主要就是获取一个RequestManager这个实例,来负责管理我们的图片请求。

2)load()方法

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

这个load方法也有很多重载方法,

DrawableTypeRequest<String>这个方法就是代表我们所有图片的请求。我们看看源码:

public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> implements DownloadOptions {
    private final ModelLoader<ModelType, InputStream> streamModelLoader;
    private final ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader;
    private final RequestManager.OptionsApplier optionsApplier;

    private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide,
            ModelLoader<A, InputStream> streamModelLoader,
            ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader, Class<Z> resourceClass,
            Class<R> transcodedClass,
            ResourceTranscoder<Z, R> transcoder) {
        if (streamModelLoader == null && fileDescriptorModelLoader == null) {
            return null;
        }

        if (transcoder == null) {
            transcoder = glide.buildTranscoder(resourceClass, transcodedClass);
        }
        DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class,
                resourceClass);
        ImageVideoModelLoader<A> modelLoader = new ImageVideoModelLoader<A>(streamModelLoader,
                fileDescriptorModelLoader);
        return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider);
    }

它是继承DrawableRequestBuilder<ModelType>这个类:

public class DrawableRequestBuilder<ModelType>
        extends GenericRequestBuilder<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable>
        implements BitmapOptions, DrawableOptions {

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

 这个类继承GenericRequestBuilder<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable>

主要就是一些参数的配置,例如缩略图,占位符,error图等参数的设置。

我们返回DrawableTypeRequest方法,看fromString这个方法的源码都做了些 什么?

public DrawableTypeRequest<String> fromString() {
        return loadGeneric(String.class);
    }

我们看一下loadGeneric这个方法,主要实现都在loadGeneric这个方法里面:

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

这个方法里面主要创建两个ModelLoader,把我们的数据来源加载成原始数据,

3)into()方法(重要)

我们看一下into方法的实现:

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

我们看一下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));
    }

首先判断是否在主线程。不在就抛出异常,

接着判断传入的view是否为null,这里就不多说了,

我们看一下applyCenterCrop(),这个方法:

 void applyCenterCrop() {
        // To be implemented by subclasses when possible.
    }

它是一个空实现,我们看一下他的子类:

 @Override
    void applyCenterCrop() {
        centerCrop();
    }

我们接着看centerCrop这个方法:

 @SuppressWarnings("unchecked")
    public DrawableRequestBuilder<ModelType> centerCrop() {
        return transform(glide.getDrawableCenterCrop());
    }

 我们看一下transform怎么操作的:

 /**
     * Transform resources with the given {@link Transformation}s. Replaces any existing transformation or
     * transformations.
     *
     * @param transformations the transformations to apply in order.
     * @return This request builder.
     */
    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;
    }

这里做了一些初始化的操作,对transform做了一些赋值。

 

我们回到into的方法,看一下return into(glide.buildImageViewTarget(view, transcodeClass));这个方法:

这里是构建一个ImageViewTarget对象,我们看一下是如何构建的:

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

这个方法其实就是通过ImageViewTargetFactrory工厂来构建Target,我们看一下工厂主要做了什么?

public class ImageViewTargetFactory {

    @SuppressWarnings("unchecked")
    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)");
        }
    }
}

这个是不是主要做了Target加载哪一种图片。

所以我们知道,这个BuildIamgeViewTarget主要做的就是让我知道返回哪一种Target对象,

 

我们接着看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;
    }

这里主要做的就是,创建一个加载图片的Request,并对之前绑定的request进行删除,并将新建的request绑定target,然后通过requestTracker这个request管理跟踪器,做相应的request的处理。

到这里简单实用的Glide框架的源码分析基本完事了,如果继续深入关于内存缓存,或者磁盘缓存的源码分析,请私信我,我将相关资源分享给您,into这个方法是Glide中重要的方法,如果深入探索还有很多东西,

 

 

 

 

标签:...,return,Glide,context,走来,new,null,public
来源: https://blog.csdn.net/wk_beicai/article/details/105216913