源码分析,Glide使用简介及流程分析

日期:2019-09-07编辑作者:编程应用

图片 1Glide

那篇小说将会为大家梳理一下Glide3.5版本的大旨流程,为了便利阅读,文章中的源码部分将轻松部分有关至极捕获与日志相关代码。

Glide是谷歌(Google)推荐的一套快速便捷的图形加载框架,笔者是bumptech,成效庞大且使用方便,实际的android应用开拓中,有成都百货上千的开采者在接纳它,今天,老衲就带大家来教学下Glide的行使及贯彻的逻辑流程。

选拔示例

先是依据惯例,先来叁个最简易的事例:

Glide.with(context).load(path).into(imageView);

丰富简洁的一句代码,上边大家依据那个调用的流水生产线一步步的来张开剖析。

Glide的选择与前一篇的Picasso类似,都以链式调用,极度方便。不过,与另外的图纸加载框架分歧的是,Glide帮忙GIF的加载与解码。那是该框架的三个优点,以下为常用API

1.Glide.with(Context context)

    public static RequestManager with(Context context) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(context);
    }

那一个措施很好驾驭,个中RequestManagerRetriever.get()方法的功能为获得RequestManagerRetriever的单例对象,然后调用当中的get方法获得RequestManager对象。

在那之中RequestManager类实现了LifecycleListener接口,重要作用是依赖Fragment或Activity的生命周期来调用onStart,onStop,onDestroy方法,以此调控央浼的展开,结束与重启。

//设置默认和出错时的图片 Glide.with.load.placeholder.error.into(mImageView)//普通的图片加载Glide.with.load.into(mImageView);//可理解为加载动态图的第一帧的Bitmap,比如GifGlide.with.load.asBitmap().into(imageView);//GIF加载,URL指向的资源必须是gif,如果是普通图片则不显示。//相反,如果指向正确但没有执行asGif方法,则只是作为普通图片展示Glide.with.asGif().load.into(mImageView);//缩略图的加载Glide.with(yourFragment).load.thumbnail.into

RequestManagerRetriever.get(Context context)

RequestManagerRetriever中,get方法的多少过多可是逻辑上都以大约,先放上代码:

    //下面会省略部分异常判断的代码

    public RequestManager get(Context context) {
        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) {
                //获取ContextWrapper中的mBase并作为参数重新调用该方法
                return get(((ContextWrapper) context).getBaseContext());
            }
        }

        return getApplicationManager(context);
    }

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

    //该方法会在Glide.with(Fragment)方法中调用
    public RequestManager get(Fragment fragment) {
        if (Util.isOnBackgroundThread()) {
            return get(fragment.getActivity().getApplicationContext());
        } else {
            FragmentManager fm = fragment.getChildFragmentManager();
            return supportFragmentGet(fragment.getActivity(), fm);
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public RequestManager get(Activity activity) {
        if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
            return get(activity.getApplicationContext());
        } else {
            android.app.FragmentManager fm = activity.getFragmentManager();
            return fragmentGet(activity, fm);
        }
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    public RequestManager get(android.app.Fragment fragment) {
        if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
            return get(fragment.getActivity().getApplicationContext());
        } else {
            android.app.FragmentManager fm = fragment.getChildFragmentManager();
            return fragmentGet(fragment.getActivity(), fm);
        }
    }

在上述措施中能够看看,那一个艺术的职能为基于传入的Context类型的两样调用区别措施组织不相同的RequestManager对象。

内需细心的是:在那之中如果传入的Context为Application或该格局不在主线程中进行,则会再次回到Application级其他RequestManager单例对象,也正是说图片的加载不会与Activity或Fragment的生命周期绑定。

率先条是大好些个人承认的思想,其余则是老衲自身在深入分析源码时对该框架的一部分觉醒。如有不对请提出

RequestManagerRetriever.supportFragmentGet(Context context, FragmentManager fm)

  1. 对象池:Glide原理的为主是为bitmap维护三个对象池。对象池的第一目标是因而压缩大指标内部存款和储蓄器的分红以重用来升高质量。对象池的定义参见对象池的选取
  2. 生命周期绑定:图片的加载职责会与activity或然Fragment的生命周期绑定,当分界面试行onStop的使用自动暂定,而当试行onStart的时候又会自行重新张开,同样的,动态Gif图的加载也是那样,以用来节省电量,同临时候Glide会对互连网状态做监听,当互联网状态发生转移时,会重启失利的任务,以减掉任务因网络连接难点而小败的可能率。
  3. 预览图的应用为加速加载速度,升高体验,优先加载预览图
  4. AbsListView内图片的预加载:

RequestManagerRetriever.fragmentGet(Context context, android.app.FragmentManager fm)

安分守纪惯例,首先介绍一下事情逻辑中须求选取的类。有印象就可以

RequestManagerRetriever.getApplicationManager(Context context)

出于这五个格局能够归到一类里,所以就在此处一同剖析

    private RequestManager getApplicationManager(Context context) {
        //返回applicationManager的单例对象
        if (applicationManager == null) {
            synchronized (this) {
                if (applicationManager == null) {
                    applicationManager = new RequestManager(context.getApplicationContext(),
                            new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
                }
            }
        }

        return applicationManager;
    }

    RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
        //RequestManagerFragment这个类与下面的SupportRequestManagerFragment类似,都是一个包含了ActivityFragmentLifecycle的对象且不可见的Fragment
        RequestManagerFragment current = getRequestManagerFragment(fm);
        RequestManager requestManager = current.getRequestManager();
        if (requestManager == null) {
            requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
            current.setRequestManager(requestManager);
        }
        return requestManager;
    }

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

上边这一部分正是Glide能够绑定生命周期的显要代码了,通过上述代码能够窥见,Glide中会在Activity或Fragment中增添一个不可见的Fragment,那几个Fragment对象中会持有Lifecycle的指标。因为Activity与个中间的Fragment的生命周期是绑定的,所以在Activity试行生命周期的办法时,Glide中对应的Fragment也会进展对应的生命周期,这样就相当于贯彻了对Activity生命周期的监听。

还会有内部的RequestManagerTreeNode类,能够通过这几个类获取到RequestManagerFragment对象下属的装有子RequestManagerFragment以高达统一宰制其生命周期的功能。

Glide用来管理和始发央求的类,完成了LifecycleListener接口相提并论写了之类方法,能够利用Activity和Fragment的生命周期事件机制的开启,甘休及重启央求职务。

2.RequestManager.load(T model)

    public <T> DrawableTypeRequest<T> load(T model) {
        return (DrawableTypeRequest<T>) loadGeneric(getSafeClass(model)).load(model);
    }

以此办法也独有短短的一行,在那之中getSafeClass(T model)方法效果是回来传入参数的Class对象,下文就不再赘述了

/** * 开始图片加载请求,一般在Activity或者Fragment的onStart方法内执行,用来重启失败或暂停的任务。 */@Overridepublic void onStart() { resumeRequests();}/** * 暂停图片加载请求,一般在Activity或Fragment的onStop方法内执行,用来暂停任务。*/@Overridepublic void onStop() { pauseRequests();}/** * 取消正在执行的请求,以及释放已完成请求的资源。*/@Overridepublic void onDestroy() { requestTracker.clearRequests();}

RequestManager.loadGeneric(Class<T> modelClass)

    private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
        //获取ModelLoader对象,用于将传入的数据转换为可以解码的另一种类型
        ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
        ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader =
                Glide.buildFileDescriptorModelLoader(modelClass, context);

        //apply方法为使用类型为DefaultOptions的options对DrawableTypeRequest对象进行预处理
        //在默认设置下,options为null,即该方法不做任何处理
        return optionsApplier.apply(
                //DrawableTypeRequest为图片加载的请求类,与图片的加载相关的配置都是由这个类来完成的
                //如图片的显示位置,占位图,图片加载的优先级等等
                new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
                        glide, requestTracker, lifecycle, optionsApplier));
    }

从不视图的fragment,轻易的来说,正是在每三个Activity恐怕Fragment上又添加了八个Fragment,该Fragment没有View,仅仅用来存款和储蓄RequestManager并管理Glide乞请

DrawableTypeRequest.load(T model)

    //DrawableTypeRequest.load(T model)
    public DrawableRequestBuilder<T> load(ModelType model) {
        super.load(model);
        return this;
    }

    //GenericRequestBuilder.load(T model)
    public DrawableRequestBuilder<T> load(T model) {
        super.load(model);
        return this;
    }

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

经过代码能够看来,就算该形式名字称为load,不过方法中只是将盛传的model保存了下来,而真正的加载,则是在into()方法中打开的。

用来成立并从Activity恐怕Fragment检索已存在的RequestManager

3.DrawableRequestBuilder.into(ImageView view)

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

    //GenericRequestBuilder.into(ImageView view)
    //下面将省略部分异常捕获代码
    public Target<TranscodeType> into(ImageView view) {
        if (!isTransformationSet && view.getScaleType() != null) {
            //针对不同的图片展示方式进行处理,由子类DrawableRequestBuilder进行具体实现
            switch (view.getScaleType()) {
                case CENTER_CROP:
                    applyCenterCrop();
                    break;
                case FIT_CENTER:
                case FIT_START:
                case FIT_END:
                    applyFitCenter();
                    break;
            }
        }

        return into(glide.buildImageViewTarget(view, transcodeClass));
    }

担负初叶加载职分,以及处理活跃的,已缓存的财富

Glide.buildImageViewTarget(ImageView imageView, Class<R> transcodedClass)

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

    //ImageViewTargetFactory.buildTarget(ImageView view, Class<Z> clazz)
    public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) {
        //根据传入的class对象决定Target的类型,默认情况下为GlideDrawable
        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);
        }
    }

上述代码中冒出的三个Target类担负将加载出的图形在ImageView中展现出来,並且由于Target类承继LifecycleListener接口,能够看看也正是Target类担当实践对于其所绑定的Activity或Fragment的生命周期的监听。

Bitmap内部存款和储蓄器池,用来复用对象

GenericRequestBuilder.into(T target)

    //省略部分异常捕获代码
    public <Y extends Target<TranscodeType>> Y into(Y target) {
        Request previous = target.getRequest();

        //如果Taget中已存在Request请求,将其清除
        if (previous != null) {
            previous.clear();
            requestTracker.removeRequest(previous);
            previous.recycle();
        }

        //构建新的Request对象并放入Target中
        Request request = buildRequest(target);
        target.setRequest(request);
        //添加生命周期监听
        lifecycle.addListener(target);
        //开始请求
        //requestTracker负责追踪并控制Request的状态,如cancel,restart
        requestTracker.runRequest(request);

        return target;
    }

由此后面长久的希图职业,终于在那个措施中规范开班了图片的央浼。

LruBitmapPool//基于LruPoolStrategy策略的BitmapPoolBitmapPoolAdapter//该实现类拒绝了对象的复用,get方法总是返回null

RequestTracker.runRequest(Request request)

    //RequestTracker.runRequest(Request request)
    public void runRequest(Request request) {
        //将request加入队列
        requests.add(request);
        if (!isPaused) {
            //开始执行请求
            request.begin();
        } else {
            //如果RequestTracker为暂停状态,将request加入等待队列
            pendingRequests.add(request);
        }
    }

对象池内对象的万分计策,依照不一致的正经,有如下二种相称计谋

GenericRequest.begin()

    public void begin() {
        startTime = LogTime.getLogTime();

        status = Status.WAITING_FOR_SIZE;
        //如果没有为图片设置尺寸,则使用控件尺寸作为图片尺寸
        if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
            onSizeReady(overrideWidth, overrideHeight);
        } else {
            //在获取到控件的宽高时,调用onSizeReady方法回调
            target.getSize(this);
        }

        if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
            //在控件中放入占位图
            target.onLoadStarted(getPlaceholderDrawable());
        }
    }

在target.getSize(this)那句语句中盛传的回调方法,就要控件的ViewTreeObserver.OnPreDrawListener方法中,相当于控件将在绘制时调用。

//校验bitmap内存大小和图片格式,内部的实现基于数组1. SizeConfigStrategy//仅要求bitmap尺寸完全匹配,内部的实现基于HashMap2. AttributeStrategy//校验bitmap尺寸和图片格式,内部实现基于TreeMap3. SizeStrategy

GenericRequest.onSizeReady(int width, int height)

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

        //获取GifBitmapWrapperDrawableTranscoder,用于将加载出的Bitmap转换为Drawable
        ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
        loadedFromMemoryCache = true;
        //调用引擎加载图片
        loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
                priority, isMemoryCacheable, diskCacheStrategy, this);
        loadedFromMemoryCache = resource != null;
    }

用来跟踪,撤销和重启正在扩充中,大概已变成,战败的央浼

Engine.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)

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) {
        final String id = fetcher.getId();
        //获取图片所对应的key
        EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
                loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
                transcoder, loadProvider.getSourceEncoder());

        //判断图片是否已存在于一级Lru缓存中
        EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
        if (cached != null) {
            cb.onResourceReady(cached);
            return null;
        }

        //判断图片是否存在于Active缓存中
        EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
        if (active != null) {
            cb.onResourceReady(active);
            return null;
        }

        //判断是否有相同的图片正在加载
        //jobs为一个Map,用以记录有哪些图片加载的请求正在进行
        EngineJob current = jobs.get(key);
        if (current != null) {
            current.addCallback(cb);
            return new LoadStatus(cb, current);
        }

        //EngineJob对象负责图片的加载与在加载请求完成或被取消时执行相应的回调
        EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
        //DecodeJob负责对请求返回的数据进行解码
        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);
        //将会开启新线程来执行runnable中的run方法开始加载图片
        engineJob.start(runnable);

        return new LoadStatus(cb, engineJob);
    }

里头能够窥见Glide中使用了二级的内部存款和储蓄器缓存,在那之中第超级为LRU缓存(近年来起码使用),第二级为Active缓存,若是一张图片在LRU缓存中一度不设有了,可是照旧在其余地点被应用着,那么就能够去直接采纳那一张图纸。

网络状态改变的监听,本质是叁个布罗兹castReceiver,值得说的是,该类也是LifecycleListener的兑现类,所以,也是有onStart,onStop的章程,而里边的逻辑,正是对互联网状态监听广播的注册于反注册

EngineRunnable.run()

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

        Exception exception = null;
        Resource<?> resource = null;
        try {
            //该方法执行加载任务
            resource = decode();
        } catch (Exception e) {
            exception = e;
        }

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

        //根据加载返回的结果调用相应回调方法
        if (resource == null) {
            //如果从DISK缓存中加载数据失败,则修改缓存标记并重新执行,如果由数据源加载失败,则执行onException回调
            onLoadFailed(exception);
        } else {
            onLoadComplete(resource);
        }
    }
//注册网络状态改变的监听广播private void register() { if (isRegistered) { return; } isConnected = isConnected; context.registerReceiver(connectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); isRegistered = true;}//取消注册private void unregister() { if (!isRegistered) { return; } context.unregisterReceiver(connectivityReceiver); isRegistered = false;}//是否有网络链接private boolean isConnected(Context context) { ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); return networkInfo != null && networkInfo.isConnected();}@Overridepublic void onStart() { register();}@Overridepublic void onStop() { unregister();}

EngineRunnable.decode()

    private Resource<?> decode() throws Exception {
        if (isDecodingFromCache()) {
            //由缓存加载数据
            return decodeFromCache();
        } else {
            //由数据源加载数据
            return decodeFromSource();
        }
    }

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

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

在上头的decodeFromCache方法中,便是Glide缓存计策的第二层,也正是磁盘缓存,而磁盘缓存又分为三种,一是由源地址所获得的图纸原来的作品件,二是通过转变后的图形文件。Glide一大特点即为能够根据控件大小的两样对图片尺寸举行拍卖后再加载,而那管理后的图样文件也会被保存入缓存中,何况在图纸加载时事先级会更超过原图。

再就是由地点的代码能见到,不论是由缓存加载,仍旧由数据源加载,实际都是交由DecodeJob来扩充管理的。

援助复用及池存款和储蓄功能的奇特类别的接口,以下是其有些完成类

DecodeJob.decodeFromSource()

    public Resource<Z> decodeFromSource() throws Exception {
        //由数据源获取源数据并进行解码
        Resource<T> decoded = decodeSource();
        return transformEncodeAndTranscode(decoded);
    }
EngineResource //支持引用计数的ResourceBitmapResource //Bitmap的包装类DrawableResource //抽象类,根据ConstantState返回一个依赖于自身ConstantState的drawable的副本 BitmapDrawableResource //BitmapDrawable的包装类 GifDrawableResource //GifDrawable的包装类

DecodeJob.decodeSource()

    private Resource<T> decodeSource() throws Exception {
        Resource<T> decoded = null;
        try {
            //从数据源加载图片
            final A data = fetcher.loadData(priority);

            if (isCancelled) {
                return null;
            }
            //将由数据源加载的数据进行解码
            decoded = decodeFromSourceData(data);
        } finally {
            fetcher.cleanup();
        }
        return decoded;
    }

LifecycleListener接口的子类,Glide用来加载能源并在加载时通报相关评释周期事件的接口。ViewTarget是它的空洞完结类。标准的生命周期是onLoadStarted -> onResourceReady or onLoadFailed -> onLoadCleared,但是并不有限援救一定依照此顺序实施,举个例子:就算能源已经在内部存款和储蓄器中,则onLoadStarted就不会被调用,同样的,借使Target假如长久不被排除,则onLoadCleared永恒不会被调用。

DecodeJob.decodeFromSourceData(A data)

    //如果缓存策略为磁盘缓存,则会先将图片加载至磁盘缓存中,再由磁盘缓存中取出使用
    private Resource<T> decodeFromSourceData(A data) throws IOException {
        final Resource<T> decoded;
        if (diskCacheStrategy.cacheSource()) {
            decoded = cacheAndDecodeSourceData(data);
        } else {
            //使用loadProvider对源数据进行解码
            decoded = loadProvider.getSourceDecoder().decode(data, width, height);
        }
        return decoded;
    }
//加载开始时调用void onLoadStarted(@Nullable Drawable placeholder);//加载失败是调用void onLoadFailed(@Nullable Drawable errorDrawable);//加载结束时调用void onResourceReady(R resource, Transition<? super R> transition);//加载任务取消并且资源被释放时调用void onLoadCleared(@Nullable Drawable placeholder);//取回目标大小,Callback的实现类为SizeDeterminer,在ViewTarget.class中void getSize(SizeReadyCallback cb);

DecodeJob.transformEncodeAndTranscode(Resource<T> decoded)

    private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded) {
        //对获取的图片进行尺寸等转换,如生成适配控件的尺寸的图片等
        Resource<T> transformed = transform(decoded);
        //将转换后的图片写入缓存
        writeTransformedToCache(transformed);
        //对图片进行类型转换,如将Bitmap转换为Drawable
        Resource<Z> result = transcode(transformed);
        return result;
    }

在该形式在回到成功后,会将其当做参数调用onLoadComplete方法。

加载财富的基类。Target的有的完结类。根据参数的种类,有两样的实现情势,并能通过ViewTreeObserver.OnDrawListener来决定View的大小。在要求检查实验大肆涉及到复用View的ViewGroup时(举个例子listview),该类用setTag方法来囤积一些标注,当检查测量试验到复用时,在此之前的加载职分和呼应的能源文件会被撤回或复用。

EngineRunnable.onLoadComplete(Resource resource)

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

    //EngineJob.onResourceReady
    public void onResourceReady(final Resource<?> resource) {
        this.resource = resource;
        //通过handler将加载出的resource发送给主线程的MAIN_THREAD_HANDLER处理
        MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
    }

    //EngineJob.MAIN_THREAD_HANDLER
    private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());

    //EngineJob.MainThreadCallback
    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;
        }
    }

    //EngineJob.handleResultOnMainThread
    private void handleResultOnMainThread() {
        if (isCancelled) {
            resource.recycle();
            return;
        } 
        //EngineResource为Resource的包装类,添加了查看这个对象被引用次数的功能
        engineResource = engineResourceFactory.build(resource, isCacheable);
        hasResource = true;

        engineResource.acquire();
        //将图片存入active缓存
        listener.onEngineJobComplete(key, engineResource);

        for (ResourceCallback cb : cbs) {
            if (!isInIgnoredCallbacks(cb)) {
                engineResource.acquire();
                //调用资源加载完成的回调方法
                cb.onResourceReady(engineResource);
            }
        }
        engineResource.release();
    }

鉴于地点这些办法的调用逻辑很清晰,所以就姑且写在共同了,上边包车型大巴流程为onLoadComplete作为回调方法被调用,随后将盛传的Resource参数使用Handler传给主线程管理,主线程依据message来调用加载成功或退步的法门。

ImageViewTarget:在ImageView中展示图片的基类,有如下两个子类 DrawableImageViewTarget:当参数是drawable的使用使用 //核心方法 @Override protected void setResource(Bitmap resource) { view.setImageBitmap; } BitmapImageViewTarget:当参数是bitmap 的时候使用 //核心方法 @Override protected void setResource(Bitmap resource) { view.setImageBitmap; }

GenericRequest.onResourceReady(Resource<?> resource, R result)

    private void onResourceReady(Resource<?> resource, R result) {
        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();
    }

至这么些主意停止,叁个最简便的图片加载流程就终于基本告竣了。

Fragment和Activity生命周期方法的监听类,主要用来监听onStart,onStop,onDestroy几个情势。完成类如下RequestTracker

小结

本篇小说轻便的梳理了Glide加载图片的主导流程,未有想到Glide如此轻松易用的表面下,内部的逻辑竟然如此的目眩神摇与壮大,不得不说,Glide源代码的复杂程度超越了自家的意料,在那之中引进的抽象概念与泛型的大度使用也给阅读也拉动了极大的孤苦,碍于自己水平有限,小说中难免有错误与疏漏之处,招待大家来研商指正。

RequestManager:负责监听Fragment和Activity中对应的方法 @Override public void onStart() { resumeRequests(); //重启暂停或者失败的任务 targetTracker.onStart(); } @Override public void onStop() { pauseRequests(); //暂停正在执行的任务 targetTracker.onStop(); }DefaultConnectivityMonitor:负责网络状态监听广播的注册于反注册 @Override public void onStart() { register(); } @Override public void onStop() { unregister(); }BaseTarget:空实现,真正的实现者是其子类ImageViewTarget,用来开始与暂停动画 @Override public void onStart() { if (animatable != null) { animatable.start(); } } @Override public void onStop() { if (animatable != null) { animatable.stop(); } }TargetTracker:该类调用的,其实是Target类中对应的方法 @Override public void onStart() { for (Target<?> target : Util.getSnapshot { target.onStart(); } } @Override public void onStop() { for (Target<?> target : Util.getSnapshot { target.onStop(); } }RequestFutureTarget:空实现,忽略NullConnectivityMonitor:空实现,忽略

数码提取的指雁为羹接口,依照财富的起点有例外的落到实处,例如

HttpUrlFetcher //加载网络图片数据AssetPathFetcher //加载Asset图片数据LocalUriFetcher //加载本地图片数据ThumbFetcher //加载MediaStore中的缩略图数据

缓存计谋的抽象类,独有Glide提供的永久的多少个对象,分别对应区别的布置

ALL:远程数据同时缓存Data和Resource,本地数据仅缓存ResourceNONE:不缓存任何数据DATA:解码之前直接将数据写入硬盘RESOURCE:解码之后写入硬盘AUTOMATIC:默认策略,根据DataFetcher以及ResourceEncoder的编码策略(EncodeStrategy)智能选择

1. Glide的起头化

public static Glide get(Context context) { if (glide == null) { synchronized (Glide.class) { if (glide == null) { Context applicationContext = context.getApplicationContext(); //查找manifest文件中注册的懒加载的配置信息,下面会介绍到 List<GlideModule> modules = new ManifestParser(applicationContext).parse(); GlideBuilder builder = new GlideBuilder(applicationContext); for (GlideModule module : modules) { module.applyOptions(applicationContext, builder); } //创建Glide实例 glide = builder.createGlide(); for (GlideModule module : modules) { module.registerComponents(applicationContext, glide.registry); } } } } return glide; }
成立Glide实例对象
Glide createGlide() { //依赖于优先级的线程池,用来执行Glide的加载,解码和转换任务(当从缓存中没有找到对应的对象时)//线程数量取决于当前唤醒的CPU核数,而不是CPU的总数if (sourceExecutor == null) { sourceExecutor = GlideExecutor.newSourceExecutor(); } //依赖于优先级的线程池,用来执行Glide的加载,解码和转换任务(当从缓存中有对应的对象时)//线程数量为1if (diskCacheExecutor == null) { diskCacheExecutor = GlideExecutor.newDiskCacheExecutor(); }//内存大小的计算器,计算结果取决于一些常量和当前设备的信息,最后会与介绍 if (memorySizeCalculator == null) { memorySizeCalculator = new MemorySizeCalculator.Builder.build(); } //网络活动监视器,用来检测网络状态if (connectivityMonitorFactory == null) { connectivityMonitorFactory = new DefaultConnectivityMonitorFactory(); } //bitmap对象池,用来存储bitmap对象if (bitmapPool == null) { //3.0以上使用基于LRU算法的bitmap对象池 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { int size = memorySizeCalculator.getBitmapPoolSize(); bitmapPool = new LruBitmapPool; } else { bitmapPool = new BitmapPoolAdapter(); } } //基于LRU算法的数组缓存池if (arrayPool == null) { arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes; } if (memoryCache == null) { memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize; } //硬盘缓存 if (diskCacheFactory == null) { diskCacheFactory = new InternalCacheDiskCacheFactory; } //负责开启加载任务以及管理活跃的或者缓存的图片资源if (engine == null) { engine = new Engine(memoryCache, diskCacheFactory, diskCacheExecutor, sourceExecutor); } return new Glide(context, engine, memoryCache, bitmapPool, arrayPool, connectivityMonitorFactory, logLevel, defaultRequestOptions.lock;}

Glide(Context context, Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, ArrayPool arrayPool, ConnectivityMonitorFactory connectivityMonitorFactory, int logLevel, RequestOptions defaultRequestOptions) { this.engine = engine; this.bitmapPool = bitmapPool; this.arrayPool = arrayPool; this.memoryCache = memoryCache; this.connectivityMonitorFactory = connectivityMonitorFactory; //图片的加载格式(ARGB_8888或RGB_565),默认ARGB_8888,判断规则如下 //如果支持透明或者使用了透明则使用ARGB_8888 //如果不支持透明则使用ARGB_565 DecodeFormat decodeFormat = defaultRequestOptions.getOptions().get(Downsampler.DECODE_FORMAT); //BitmapPool的预填充器,最后面有介绍 bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat); Resources resources = context.getResources(); //从给定的inputstream中解码图片 Downsampler downsampler = new Downsampler(resources.getDisplayMetrics(), bitmapPool, arrayPool); //Gif图片资源的解码器 ByteBufferGifDecoder byteBufferGifDecoder = new ByteBufferGifDecoder(context, bitmapPool, arrayPool); ... //包含了加载图片资源所需要的类,比如Registry,Engine,等等 glideContext = new GlideContext(context, registry, imageViewTargetFactory, defaultRequestOptions, engine, this, logLevel); }

2. 创制要求保管器RequestManager

率先依照context的连串,获得FragmentManager

public RequestManager get(Context context) { if (context == null) { ... } else if (Util.isOnMainThread() && !(context instanceof Application)) { if (context instanceof FragmentActivity) { //FragmentActivity return get((FragmentActivity) context); } else if (context instanceof Activity) { //Activity return get( context); } else if (context instanceof ContextWrapper) { //如果不属于以上两种,则递归查找父类Context return get(((ContextWrapper) context).getBaseContext; } } //返回ApplicationManager return getApplicationManager;}...//get()中会调用fragmentGet方法@TargetApi(Build.VERSION_CODES.HONEYCOMB)RequestManager fragmentGet(Context context, android.app.FragmentManager fm, android.app.Fragment parentHint) { //获取RequestManagerFragment RequestManagerFragment current = getRequestManagerFragment(fm, parentHint); //获取RequestManagerFragment对应的RequestManager RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode; current.setRequestManager(requestManager); } return requestManager;}

RequestManagerRetriever中动用三个map用来分别存放RequestManagerFragment和SupportRequestManagerFragment,Key都是FragmentManager。说白了正是每三个Activity可能FragmentActivity都有三个独一的FragmentManager,通过这一个FragmentManager作为key就能够找到该Activity对应的RequestManagerFragment,Glide就是通过那一个Fragment用来促成在生命周期中图纸加载的支配,譬喻Paused状态在行车制动器踏板加载,在Resumed的时候又自行重新加载

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm , android.app.Fragment parentHint) { RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG); if (current == null) { //pendingRequestManagerFragments是一个 current = pendingRequestManagerFragments.get; if (current == null) { current = new RequestManagerFragment(); current.setParentFragmentHint(parentHint); pendingRequestManagerFragments.put(fm, current); fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss(); handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget(); } } return current;}

2. 填充能源路线(网络路线或地点路线)

/** * 利用默认的请求参数创建RequestBuilder * 默认的参数包括,是否启动硬盘缓存,优先级,错误及加载中的默认图片等 * 详情请看BaseRequestOptions.java类 * @return A new request builder for loading a { Drawable} using the given model. */public RequestBuilder<Drawable> load(@Nullable Object model) { return asDrawable().load;}

3. 安装要加载图片的Target(ImageView)

public Target<TranscodeType> into(ImageView view) { Util.assertMainThread(); Preconditions.checkNotNull; if (!requestOptions.isTransformationSet() && requestOptions.isTransformationAllowed() && view.getScaleType() != null) { ... return into(context.buildImageViewTarget(view, transcodeClass));}public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) { Util.assertMainThread(); Preconditions.checkNotNull; if (!isModelSet) { //是否设置了url ... } //获取该Target之前的请求任务 Request previous = target.getRequest(); //如果有,取消该Target之前所有的任务并释放资源以备复用 if (previous != null) { requestManager.clear; } requestOptions.lock(); //创建请求 Request request = buildRequest; target.setRequest; // TODO:下载图片的任务 requestManager.track(target, request); return target;}

Glide的缩略图加载观念,为了越来越快的来得图片,一般的话,一张图纸的加载职务分为全尺寸图片和缩略图两部分,因为缩略图更加小,所以一般的话相对于全尺寸图片会加载更加快,但不相对,假设缩略图先加载完则先出示缩略图,然后等全尺寸图片加载成功后再加载全尺寸图片,可是,如若全尺寸图片先于缩略图下载达成,则缩略图则不会议及展览示。

private Request buildRequestRecursive(Target<TranscodeType> target, @Nullable ThumbnailRequestCoordinator parentCoordinator, TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, int overrideWidth, int overrideHeight) { //默认的该thumbnailBuilder对象为null,除非手动调用RequestBuilder类的thumbnail方法, //否则该if代码永远不会执行 if (thumbnailBuilder != null) { // Recursive case: contains a potentially recursive thumbnail request builder. if (isThumbnailBuilt) { throw new IllegalStateException("You cannot use a request as both the main request and a thumbnail, consider using clone() on the request passed to thumbnail; } TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions = thumbnailBuilder.transitionOptions; if (DEFAULT_ANIMATION_OPTIONS.equals(thumbTransitionOptions)) { thumbTransitionOptions = transitionOptions; } //缩略图权限 Priority thumbPriority = thumbnailBuilder.requestOptions.isPrioritySet() ? thumbnailBuilder.requestOptions.getPriority() : getThumbnailPriority; //缩略图宽高 int thumbOverrideWidth = thumbnailBuilder.requestOptions.getOverrideWidth(); int thumbOverrideHeight = thumbnailBuilder.requestOptions.getOverrideHeight(); //宽高校验 if (Util.isValidDimensions(overrideWidth, overrideHeight) && !thumbnailBuilder.requestOptions.isValidOverride { thumbOverrideWidth = requestOptions.getOverrideWidth(); thumbOverrideHeight = requestOptions.getOverrideHeight(); } //缩略图请求协调器,用来同时协调缩略图和原始图片的请求 ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator); //原始图片请求 Request fullRequest = obtainRequest(target, requestOptions, coordinator, transitionOptions, priority, overrideWidth, overrideHeight); isThumbnailBuilt = true; // Recursively generate thumbnail requests //递归生成缩略图请求 Request thumbRequest = thumbnailBuilder.buildRequestRecursive(target, coordinator, thumbTransitionOptions, thumbPriority, thumbOverrideWidth, thumbOverrideHeight); isThumbnailBuilt = false; coordinator.setRequests(fullRequest, thumbRequest); return coordinator; } else if (thumbSizeMultiplier != null) { //根据指定缩放系数加载缩略图 ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator); Request fullRequest = obtainRequest(target, requestOptions, coordinator, transitionOptions, priority, overrideWidth, overrideHeight); BaseRequestOptions<?> thumbnailOptions = requestOptions.clone().sizeMultiplier(thumbSizeMultiplier); Request thumbnailRequest = obtainRequest(target, thumbnailOptions, coordinator, transitionOptions, getThumbnailPriority, overrideWidth, overrideHeight); coordinator.setRequests(fullRequest, thumbnailRequest); return coordinator; } else { // 只加载原始图片 return obtainRequest(target, requestOptions, parentCoordinator, transitionOptions, priority, overrideWidth, overrideHeight); }}

迄今停止,Glide的流程就剖析完了,但是!!!和大家事先掌握到的Picasso恐怕Imageloader等图片加载框架分化,我们完全未有看到她的网络乞请已经缓存查找的事体逻辑,那这段逻辑究竟在哪吧。大家接二连三往下看

图形的加载

在地点的尾声一步,buildRequestRecursive方法,不管是否有缩略图,大家都会回去多个Request,那些Request会和Target一同被RequestManager接收

void track(Target<?> target, Request request) { targetTracker.track; //runRequest最终执行的是Request的begin方法,下面以SingleRequest为例讲解下流程 requestTracker.runRequest;}@Overridepublic void begin() { stateVerifier.throwIfRecycled(); startTime = LogTime.getLogTime(); //如果图片的来源没有设置,则加载失败,来源是指网络,本地硬盘或者资源文件等。 if (model == null) { if (Util.isValidDimensions(overrideWidth, overrideHeight)) { width = overrideWidth; height = overrideHeight; } ... onLoadFailed(new GlideException("Received null model"), logLevel); return; } status = Status.WAITING_FOR_SIZE; //如果Target的宽高已经获取并且合法,则开始进行下一步if (Util.isValidDimensions(overrideWidth, overrideHeight)) { onSizeReady(overrideWidth, overrideHeight); } else { //手动获取Target的宽高 target.getSize; } if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE) && canNotifyStatusChanged { target.onLoadStarted(getPlaceholderDrawable; } if (Log.isLoggable(TAG, Log.VERBOSE)) { ... }}@Overridepublic void onSizeReady(int width, int height) { stateVerifier.throwIfRecycled(); ... status = Status.RUNNING; //计算缩略图的尺寸 float sizeMultiplier = requestOptions.getSizeMultiplier(); this.width = Math.round(sizeMultiplier * width); this.height = Math.round(sizeMultiplier * height); ... //加载任务 loadStatus = engine.load(glideContext, model, requestOptions.getSignature(), this.width, this.height, requestOptions.getResourceClass(), transcodeClass, priority, requestOptions.getDiskCacheStrategy(), requestOptions.getTransformations(), requestOptions.isTransformationRequired(), requestOptions.getOptions(), requestOptions.isMemoryCacheable; ...}
加载财富

Glide图片的能源加载与别的图片加载框架的加载逻辑类似,都以根据内部存款和储蓄器,硬盘及网络的一一来加载图片,但是Glide得加载又稍显差别,他是的逻辑如下:

/** * 1. 检查内存缓存 * 2. 检查最近的活跃资源 * 3. 检查最近的加载任务 * 活跃资源指的是那些不止一次被加载并没有进行过资源释放的图片,一旦被释放, * 那么该资源则会从近期活跃资源中删除并进入到内存缓存中, * 但是如果该资源再次从内存缓存中读取,则会重新添加到活跃资源中 */public <R> LoadStatus load( GlideContext glideContext, Object model, Key signature, int width, int height, Class<?> resourceClass, Class<R> transcodeClass, Priority priority, DiskCacheStrategy diskCacheStrategy, Map<Class<?>, Transformation<?>> transformations, boolean isTransformationRequired, Options options, boolean isMemoryCacheable, ResourceCallback cb) { Util.assertMainThread(); long startTime = LogTime.getLogTime(); //内存缓存的唯一键值EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations, resourceClass, transcodeClass, options); //首先从缓存中查找EngineResource<?> cached = loadFromCache(key, isMemoryCacheable); if (cached != null) { cb.onResourceReady(cached, DataSource.MEMORY_CACHE); ... return null; } //如果缓存中没有找到,则去活跃资源中加载//memCache中该bitmap则会被remove掉bitmap并进入activeResource中EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable); if (active != null) { cb.onResourceReady(active, DataSource.MEMORY_CACHE); ... } return null; } //如果该任务之前已经在队列中,则添加新的callback,然后返回EngineJob current = jobs.get; if (current != null) { current.addCallback; ... return new LoadStatus(cb, current); } //如果是新的加载任务,先创建EngineJob和DecodeJob,然后开始任务EngineJob<R> engineJob = engineJobFactory.build(key, isMemoryCacheable); DecodeJob<R> decodeJob = decodeJobFactory.build(glideContext,model,key,signature,width,height,resourceClass,transcodeClass, priority,diskCacheStrategy,transformations, isTransformationRequired,options,engineJob); jobs.put(key, engineJob); engineJob.addCallback; //开始任务engineJob.start(decodeJob); ...return new LoadStatus(cb, engineJob);}/** * DecodeJob 类中run方法的实现,DecodeJob是一个Runnable的实现类 * 该方法的作用是, * 1.确定数据的加载来源(Resource,Data,Source) * 2.创建对应来源的DataFetcherGenerator * 3.执行DataFetcherGenerator */private void runWrapped() { switch (runReason) { case INITIALIZE://首次提交 stage = getNextStage(Stage.INITIALIZE); //确定资源的加载来源 currentGenerator = getNextGenerator(); runGenerators(); break; case SWITCH_TO_SOURCE_SERVICE://从硬盘获取资源失败 ,尝试重新获取 runGenerators(); break; case DECODE_DATA://获取数据成功,但不在同一线程 decodeFromRetrievedData(); break; default: throw new IllegalStateException("Unrecognized run reason: " + runReason); } }/** * 根据当前阶段获取下一阶段 * Data和Resource的区别: * Data:原始的图片数据 * Resource:经过处理后的数据 * 该方法的大致逻辑如下 * 1.如果是初始状态,则判断是否解码已缓存的Resource,true是解码Resource。 * false的话则会通过递归进入第二个判断分支 * 2.判断是否解码已缓存的Data,true是解码Data * false的话则会通过递归进入第三个判断分支 * 3.该阶段则需要从数据源去解码。 * 简单的来说,就是根据Resource--->Data--->source的顺序去解码加载数据 * 该阶段Stage的确定,影响着下一阶段DataFetcherGenerator相应子类的实例创建 */private Stage getNextStage(Stage current) { switch  { case INITIALIZE: return diskCacheStrategy.decodeCachedResource() ? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE); case RESOURCE_CACHE: return diskCacheStrategy.decodeCachedData() ? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE); case DATA_CACHE: return Stage.SOURCE; case SOURCE: case FINISHED: return Stage.FINISHED; default: throw new IllegalArgumentException("Unrecognized stage: " + current); }}/** * 根据不同的阶段创建不同的DataFetcherGenerator,该类使用已注册的ModelLoaders和Model * 来生成一系列的DataFetcher。有如下实现类 * DataFetcherGenerator:经过处理的资源数据缓存文件 * ResourceCacheGenerator:未经处理的资源数据缓存文件 * SourceGenerator:源数据的生成器,包含了根据来源创建的ModelLoader和Model(文件路径,URL...) */private DataFetcherGenerator getNextGenerator() { switch  { case RESOURCE_CACHE: return new ResourceCacheGenerator(decodeHelper, this); case DATA_CACHE: return new DataCacheGenerator(decodeHelper, this); case SOURCE: return new SourceGenerator(decodeHelper, this); case FINISHED: return null; default: throw new IllegalStateException("Unrecognized stage: " + stage); }}/** * 根据不同的状态来选择并执行生成器 * 从当前Generator 获取数据,如果获取成功则直接回调onDataFetcherReady, * 如果失败则通过reschedule重新调度 */private void runGenerators() { ... boolean isStarted = false; while (!isCancelled && currentGenerator != null && !(isStarted = currentGenerator.startNext { stage = getNextStage; currentGenerator = getNextGenerator(); if (stage == Stage.SOURCE) { reschedule(); return; } } // 加载失败 if ((stage == Stage.FINISHED || isCancelled) && !isStarted) { notifyFailed(); } }

一旦是第贰遍加载一张图片财富,最终会到来SourceGenerator的startNext来试行。

/** * SourceGenerator * DataFetcher的简介:Fetcher的意思是抓取,所以该类可以称为数据抓取器 * 作用就是根据不同的数据来源(本地,网络,Asset等) * 以及读取方式(Stream,ByteBuffer等)来提取并解码数据资源,实现类如下 * AssetPathFetcher:加载Asset数据 * HttpUrlFetcher:加载网络数据 * LocalUriFetcher:加载本地数据 * 其他实现类... * */@Overridepublic boolean startNext() { ... if (sourceCacheGenerator != null && sourceCacheGenerator.startNext { return true; } sourceCacheGenerator = null; loadData = null; boolean started = false; //是否有更多的ModelLoaderwhile (!started && hasNextModelLoader { loadData = helper.getLoadData().get(loadDataListIndex++); if (loadData != null&& (helper.getDiskCacheStrategy() .isDataCacheable(loadData.fetcher.getDataSource || helper.hasLoadPath(loadData.fetcher.getDataClass { started = true; //选择合适的LoadData,并使用LoadData中的fetcher来抓取数据 loadData.fetcher.loadData(helper.getPriority; } } return started;}

当走完上边的流水生产线,接下去就是我们最熟稔的互连网数据伏乞的模块了,因为该模块在整个的图样加载流程中并不是很要紧,所以就总结介绍一下,可是有多少个知识点仍然相比风趣的。

/** * HttpUrlFetcher * HttpUrlFetcher的简介:网络数据抓取器,通俗的来讲就是去服务器上下载图片,支持地址重定向 * */@Overridepublic void loadData(Priority priority, DataCallback<? super InputStream> callback) { long startTime = LogTime.getLogTime(); final InputStream result; try { result = loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders; } catch (IOException e) { ... callback.onLoadFailed; return; } ... callback.onDataReady;}private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers) throws IOException { //重定向次数过多 if (redirects >= MAXIMUM_REDIRECTS) { throw new HttpException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!"); } else { //通过URL的equals方法来比较会导致NetworkI/O开销,一般会有问题, //有兴趣的同学可以看下下面的链接或者直接阅读URL里equals方法的源码注释,一目了然 //http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html. try { if (lastUrl != null && url.toURI().equals(lastUrl.toURI { throw new HttpException("In re-direct loop"); } } catch (URISyntaxException e) { // Do nothing, this is best effort. } } //HttpUrlConnection下载图片 ...}

接下去,老衲带我们看下Glide中有何大家在普通费用的时候能用得上的技能

1.线程池内线程的个数的图谋方法

/** * 根据/sys/devices/system/cpu/下的文件来决定线程池内线程的数量 * 决定线程数量的不是一共得CPU核数,而是唤醒的CPU核数 * * See http://goo.gl/8H670N. */public static int calculateBestThreadCount() { File[] cpus = null; try { File cpuInfo = new File(CPU_LOCATION); final Pattern cpuNamePattern = Pattern.compile(CPU_NAME_REGEX); cpus = cpuInfo.listFiles(new FilenameFilter() { @Override public boolean accept(File file, String s) { return cpuNamePattern.matcher.matches; } catch (Throwable t) { ... } int cpuCount = cpus != null ? cpus.length : 0; int availableProcessors = Math.max(1, Runtime.getRuntime().availableProcessors; return Math.min(MAXIMUM_AUTOMATIC_THREAD_COUNT, Math.max(availableProcessors, cpuCount));}

2. 权力决断

以互连网须求的权柄为例

final int res = context .checkCallingOrSelfPermission("android.permission.ACCESS_NETWORK_STATE");final boolean hasPermission = res == PackageManager.PERMISSION_GRANTED;

Glide的懒加载配置

深入分析Manifest文件中登记的懒加载配置音讯
public List<GlideModule> parse() { List<GlideModule> modules = new ArrayList<>(); try { ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA); if (appInfo.metaData != null) { for (String key : appInfo.metaData.keySet { if (GLIDE_MODULE_VALUE.equals(appInfo.metaData.get { modules.add(parseModule; } } } } catch (PackageManager.NameNotFoundException e) { ... } return modules;}
3. Glide付给的懒加载示例(混淆代码的话请读者自身查看GlideModule类的讲解)
public class FlickrGlideModule implements GlideModule { Override public void applyOptions(Context context, GlideBuilder builder) { builder.setDecodeFormat(DecodeFormat.ALWAYS_ARGB_8888); } public void registerComponents(Context context, Glide glide) { glide.register(Model.class, Data.class, new MyModelLoader; } }

4. Glide的预填充机制

Glide最基本的一部分,就是Bitmap池的行使,Glide类中有二个preFillBitmapPool方法,用来预填充bitmap对象池,他的批注如下

 /** * 作用:根据给定的尺寸预填充Bitmap对象池 * 缺陷:太多的资源释放会导致GC频繁执行,这样就失去了Glide本身存在的意义。此方法要慎重使用。 * 若太多的Bitmap被添加到对象池使其完全被填满,会导致大多数甚至全部最近被添加的bitmap被驱逐 * bitmap会根据给定的尺寸的权重来分配,每一种尺寸只会填充对象池所占内存的一定比例。 * 比例的计算公式为weight / prefillWeightSum */public void preFillBitmapPool(PreFillType.Builder... bitmapAttributeBuilders) { bitmapPreFiller.preFill(bitmapAttributeBuilders);}public void preFill(PreFillType.Builder... bitmapAttributeBuilders) { if (current != null) { current.cancel(); } //PreFillType中保存着图片的宽高,Config以及weight等信息PreFillType[] bitmapAttributes = new PreFillType[bitmapAttributeBuilders.length]; for (int i = 0; i < bitmapAttributeBuilders.length; i++) { PreFillType.Builder builder = bitmapAttributeBuilders[i]; if (builder.getConfig() == null) { builder.setConfig(defaultFormat == DecodeFormat.ALWAYS_ARGB_8888 || defaultFormat == DecodeFormat.PREFER_ARGB_8888? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); } bitmapAttributes[i] = builder.build(); } //根据PreFillType中保存的图片信息创建预填充队列 PreFillQueue allocationOrder = generateAllocationOrder(bitmapAttributes); //创建用来填充对象池的线程对象, //该类通过Handler发布到主线程中尽量避免GC因高比例的Bitmap触发垃圾回收所导致的ANR, //通过延时减少GC线程的垃圾回收的次数 current = new BitmapPreFillRunner(bitmapPool, memoryCache, allocationOrder); handler.post;}// Visible for testing.PreFillQueue generateAllocationOrder(PreFillType[] preFillSizes) { //剩余内存 final int maxSize = memoryCache.getMaxSize() - memoryCache.getCurrentSize() + bitmapPool.getMaxSize(); int totalWeight = 0; //计算图片总权重 for (PreFillType size : preFillSizes) { totalWeight += size.getWeight(); } //计算每一份权重占用的字节 final float bytesPerWeight = maxSize /  totalWeight; Map<PreFillType, Integer> attributeToCount = new HashMap<PreFillType, Integer>(); for (PreFillType size : preFillSizes) { //根据权重计算出的图片的内存占用量 int bytesForSize = Math.round(bytesPerWeight * size.getWeight; //根据宽高和Config计算出的图片的内存占用量 int bytesPerBitmap = getSizeInBytes; int bitmapsForSize = bytesForSize / bytesPerBitmap; attributeToCount.put(size, bitmapsForSize); } return new PreFillQueue(attributeToCount);}

5. DefaultConnectivityMonitor 互连网状态监视器

平时的支付中选拔效能照旧相比较高的,可以直接拿来用,完整代码请参见源码

private final BroadcastReceiver connectivityReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { boolean wasConnected = isConnected; isConnected = isConnected; if (wasConnected != isConnected) { listener.onConnectivityChanged(isConnected); } }};public DefaultConnectivityMonitor(Context context, ConnectivityListener listener) { this.context = context.getApplicationContext(); this.listener = listener;}private void register() { if (isRegistered) { return; } isConnected = isConnected; context.registerReceiver(connectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); isRegistered = true;}private void unregister() { if (!isRegistered) { return; } context.unregisterReceiver(connectivityReceiver); isRegistered = false;}private boolean isConnected(Context context) { ConnectivityManager connectivityManager = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); return networkInfo != null && networkInfo.isConnected();}@Overridepublic void onStart() { register();}@Overridepublic void onStop() { unregister();}

本文由今晚最快开奖现场直播发布于编程应用,转载请注明出处:源码分析,Glide使用简介及流程分析

关键词:

利用Intent来开展App间的主导交互,系统深远学习

Intent是Android中存放一个操作的抽象描述的数据结构,可用于在不同的组件以及不同的app间进行传递,是消息的载体,有显...

详细>>

Android难题之——自定义View(上)

1、每个Activity包含一个Window对象(Window是abstract的,一般是由PhoneWindow实现)。2、PhoneWindow将DecorView设置为整个应用的...

详细>>

热修复热点框架简析,Android插件框架机制研商

笔者 百度任玉刚 插件化框架 途牛已上线使用帮衬代码能源文件以插件情势加入到host。 插件化的主干形式是将二个...

详细>>

阅读笔记,线程安全性

首先使代码正确运行,然后再提高代码速度。【正确编写并发程序的方法】 线程安全:当多个线程访问某个类(对象...

详细>>