从源码看Glide图片加载

by admin on 2019年9月8日

基于com.github.bumptech.glide:glide:3.7.0那是一篇飞快过源码,而非品味细枝末节的深入分析,不然简书的2W
byte的限定,大概要分好几期能力从头到尾的讲完。

0.基础知识 Glide中有局地单词,笔者不知底用哪些汉语能够确切的发表出含义,用斯洛伐克语单词大概在编写中进一步方便,还会有一对词在Glide中有特地的含义,笔者晓得的或然也不深远,这里先记下一下。

一集成接纳

在Glide中,图片的加载会尾随那Activity也许Fragment的生命周期实行相应的加载,结束等操作,本节我们由此源码来深入分析一下Glide是怎么做到那点的

Glide源码有广大值得学习的地点,种种设计情势用的堪比AOSP,但是也实际上是有够复杂,从前撸了回顾的图样加载框架-%E6%A1%86%E6%9E%B6%E8%AE%BE%E8%AE%A1/),是参照他事他说加以考察Volley设计的,今后该像Glide源码学习了.

  • ### 引入

    在github上()
    ,Glide的合法Sample使用的是之类的一段的代码:

(1)View:
一般景色下,指Android中的View及其子类控件(包涵自定义的),越发指ImageView。那么些控件可在上面绘制Drawable
(2)Target:
Glide中十分重要的概念,目的。它即能够指封装了叁个View的Target(ViewTarget),也得以不带有View(SimpleTarget)。
(3)Drawable:
指Android中的Drawable类只怕它的子类,如BitmapDrawable等。或然Glide中基础Drawable完成的自定义Drawable(如GifDrawable等)
(4)Request –
加载伏乞,能够是互连网须要大概另外任何下载图片的央求,也是Glide中的一个类。
(5)Model:数据源的提供者,如Url,文件路线等,能够从model中获得InputStream。
(6)Signature:具名,能够独一地方统一规范识三个指标。
(7)recycle():Glide中Resource类有此方法,表示该财富不被引用,能够归入池中(此时并不曾自由空间)。Android中Bitmap也会有此方法,表示释放Bitmap占用的内部存款和储蓄器。

1.引入glide和okhttp3

用法

在我的GlideSample中的StartActivity类中

Glide.with(StartActivity.this).load(R.mipmap.pizza).into(mIvShow);

调用形式

咱俩先看一下Glide的用法,相信大家都会. 精粹之处在于

  • 成效庞大,RESTful调用
  • 不用大家管理裁撤难点,自绑定生命周期
  • 不用在Application初始化

Glide.with(TodayFragment.this)
        .load(gankDay.results.福利.get(0).getUrl())
        .centerCrop()
        .crossFade()
        .error(R.drawable.jay)
        .into(mImageView);

1.人命关天特征 (1)援助Memory和Disk图片缓存。
(2)扶助gif和webp格式图片。
(3)依照Activity/Fragment生命周期自动管理诉求。
(4)使用Bitmap Pool可以使Bitmap复用。
(5)对于回收的Bitmap会主动调用recycle,减小系统回收压力。

compile’com.squareup.okhttp3:okhttp:3.2.0′

分析

// 使用的上下文Context,可以是Application,Activity,Fragment实例
Glide.with()  

我们看来源码,这里传出的5种等级次序参数

with(Context context)  //  any Context
with(android.app.Activity)
with(android.app.Fragment)
with(android.support.v4.app.Fragment)
with(android.support.v4.app.FragmentActivity)

我们以with(android.support.v4.app.FragmentActivity)为例看下

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

随即看下retriever.get(activity)方法

    public RequestManager get(FragmentActivity activity) {
        if (Util.isOnBackgroundThread()) {
           // 不在主线程,返回一个ApplicationContext关联的RequestManager
            return get(activity.getApplicationContext());
        } else {
            // 重点在这里,我们返回一个Fragment相关的RequestManager
            assertNotDestroyed(activity);
            // 获取activity对应的FragmentManager,主要目的是和Activity结合,
            // 塞入一个空的fragment对象,用于暴露出生命周期方法,这个在后面会看到
            FragmentManager fm = activity.getSupportFragmentManager();
            return supportFragmentGet(activity, fm);
        }
    }

此处大家很扎眼的看到假诺调用with()方法的时候不是在主线程,那么大家会回去四个和ApplicationContext关联的RequestManager

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

借使是在主线程操作,那么大家会回到贰个Fragment相关的RequestManager,这里涉及到四个很精细的用法,如何将Activity的生命周期暴揭示来与您的包装控件结合使用

    RequestManager supportFragmentGet(Context context, FragmentManager fm) {
        // 获取一个自定义的Fragment
        SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
        RequestManager requestManager = current.getRequestManager();
        if (requestManager == null) {
            // 生成RequestManager对象,看看,这里暴露出了Lifecycle接口,LIfecycle实现类中是一个监听LifecycleListener
            requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
            current.setRequestManager(requestManager);
        }
        return requestManager;
    }

SupportRequestManagerFragment中关系了贰个Lifecycle接口的兑现类ActivityFragmentLifecycle

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

里面,ActivityFragmentLifecycle类对外提供了增加监听的办法

@Override
    public void addListener(LifecycleListener listener) {
        ......
    }

况兼ActivityFragmentLifecycle类方法参加到了那个Fragment的生命周期中,如下所示

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

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

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

最后在ActivityFragmentLifecycle中调用了监听中的对应的生命周期方法

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

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

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

观察没,只要增多了监听达成类,就会博获得对应的生命周期,进而对外提供了生命周期方法

with是怎么的

with起到绑定生命周期的成效,这里的with或者是各种类型,Glide都帮我们复写了.with的作用重尽管帮大家给当下指标绑定上生命周期.

以Fragment为调用方比方.

public static RequestManager with(Fragment fragment) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(fragment);
}

我们去RequestManagerRetriever看看.

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

RequestManager supportFragmentGet(Context context, final FragmentManager fm) {
    SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag(TAG);
    if (current == null) {
        current = pendingSupportRequestManagerFragments.get(fm);
        if (current == null) {
            current = new SupportRequestManagerFragment();
            pendingSupportRequestManagerFragments.put(fm, current);
            fm.beginTransaction().add(current, TAG).commitAllowingStateLoss();
            handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
        }
    }
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
        requestManager = new RequestManager(context, current.getLifecycle());
        current.setRequestManager(requestManager);
    }
    return requestManager;
}

能够观察首要流程就是,去
FragmentManager找寻fragment,fm.findFragmentByTag(TAG);,
假设找不到,就实类化四个current = new SupportRequestManagerFragment();,并加多进去

SupportRequestManagerFragment是什么样啊?大家进去看

public class SupportRequestManagerFragment extends Fragment {
    private RequestManager requestManager;
    private final ActivityFragmentLifecycle lifecycle;

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

SupportRequestManagerFragment是三番两次于Fragment,并促成了逐个生命周期的回调,最后回调lifecycle接口.这里就贯彻了生命周期的监听.

ActivityFragmentLifecycle是多少个观看者,里面有四个Set集结存放了LifecycleListener,
那是正统的观察者方式的写法,每一趟回调都会遍历会集分发事件.代码如下.

class ActivityFragmentLifecycle implements Lifecycle {
    private final Set<LifecycleListener> lifecycleListeners =
            Collections.synchronizedSet(Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>()));
    private boolean isStarted;
    private boolean isDestroyed;

    @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 : lifecycleListeners) {
            lifecycleListener.onStart();
        }
    }

    void onStop() {
        isStarted = false;
        for (LifecycleListener lifecycleListener : lifecycleListeners) {
            lifecycleListener.onStop();
        }
    }

    void onDestroy() {
        isDestroyed = true;
        for (LifecycleListener lifecycleListener : lifecycleListeners) {
            lifecycleListener.onDestroy();
        }
    }
}

此刻我们再回到RequestManagerRetriever的中间,该走下一步了,大家要重返的是RequestManager,
无差别于的老路,先去拿,拿不到就实类化.

RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
    requestManager = new RequestManager(context, current.getLifecycle());
    current.setRequestManager(requestManager);
}
return requestManager;

通过current.getLifecycle()RequestManagerFragment的生命周期传给RequestManager,又把这些RequestManager设置进RequestManagerFragment,那边也便是是互争持有了.其实设置生命周期给RequestManager大可不必这么写,因为Current已经具有RequestManager了.

提及底大家重回RequestManager,大家未来看RequestManager是如何?

 Glide .with(myFragment) .load .centerCrop() .placeholder(R.drawable.loading_spinner) .crossFade() .into(myImageView);

2. 总体规划设计

compile’com.github.bumptech.glide:glide:3.6.1′

总结

看过源代码,给自家叁个什么样启示,由于Fragment在onAttach()之后,与Activity有雷同的生命周期,那么大家就能够透过给Activity增多多少个不展现分界面包车型地铁fragment,何况在生命周期方法中,调用揭穿的监听的照顾措施,那样来到达对外暴光生命周期方法的目标,怎么样,是还是不是挺奇妙的

好了,这里就先批注到此地了,后边我们会持续依据介绍暴揭露来的接口,怎么跟图片加载结合在一块儿

RequestManager-特别关键

更优质的来了!!!

看一下RequestManager代码

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

    ...
    this.glide = Glide.get(context);
    lifecycle.addListener(this);
    ...
    @Override
    public void onStart() {
        // onStart might not be called because this object may be created after the fragment/activity's onStart method.
        resumeRequests();
    }

    /**
     * Lifecycle callback that unregisters for connectivity events (if the android.permission.ACCESS_NETWORK_STATE
     * permission is present) and pauses in progress loads.
     */
    @Override
    public void onStop() {
        pauseRequests();
    }

    /**
     * Lifecycle callback that cancels all in progress requests and clears and recycles resources for all completed
     * requests.
     */
    @Override
    public void onDestroy() {
        requestTracker.clearRequests();
    }

}

咱俩收获多少个有用音讯,

  1. implements LifecycleListener,完毕了这几个接口,我们地点还讲到观察者形式,在ActivityFragmentLifecycle里面,此时RequestManager富有了生命周期的回调,我们从代码能够看来,它在每一个生命周期里面进行了撤废,暂停,恢复需要的操作.
  2. 有着一个大局的Glide变量,Glide类是单例的.大家看经过Glide.get(context);拿到Glide类.

咱俩知道,非常多框架须求在Application里面开端化,因为自然要负有Context,又不想绑定某些Activity的Context,由此用ApplicationContext.那就导致了要在Application在这之中初始化的结果.富含作者的SherlockImageLoader-%E6%A1%86%E6%9E%B6%E8%AE%BE%E8%AE%A1/)也是这般写的.以往见到必要更始了.

小编们看看get方法.

    /**
     * Get the singleton.
     *
     * @return the singleton
     */
    public static Glide get(Context context) {
        if (glide == null) {
            synchronized (Glide.class) {
                if (glide == null) {
                    Context applicationContext = context.getApplicationContext();
                    List<GlideModule> modules = new ManifestParser(applicationContext).parse();

                    GlideBuilder builder = new GlideBuilder(applicationContext);
                    for (GlideModule module : modules) {
                        module.applyOptions(applicationContext, builder);
                    }
                    glide = builder.createGlide();
                    for (GlideModule module : modules) {
                        module.registerComponents(applicationContext, glide);
                    }
                }
            }
        }
        return glide;
    }

从下边能够看来,get时候传出context,但并非历次传的context都会被用到的,唯有首先次使用的时候这么些Context会被用到,也只是用它来取得Application的Context.
然后选择ApplicationContext来惰性开首化大家的全局Glide对象.

好大家RequestManager先暂停一下,大家看with完了,大家得到RequestManager后该干什么.

Glide.with(TodayFragment.this).load(gankDay.results.福利.get(0).getUrl())…

咱俩会调用load()方法,或者是fromUri(),loadFromMediaStore(),load(File file)..等五种重载.然而我们会获取二个新的靶子叫DrawableTypeRequest,很令人瞩目,那是用来扶助大家初步化乞请的类.我们去看看.

public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> implements DownloadOptions {
  public BitmapTypeRequest<ModelType> asBitmap() {
    return optionsApplier.apply(new BitmapTypeRequest<ModelType>(this, streamModelLoader,
            fileDescriptorModelLoader, optionsApplier));
  }
  @Override
  public DrawableRequestBuilder<ModelType> animate(ViewPropertyAnimation.Animator animator) {
      super.animate(animator);
      return this;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public DrawableRequestBuilder<ModelType> animate(int animationId) {
      super.animate(animationId);
      return this;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public DrawableRequestBuilder<ModelType> placeholder(int resourceId) {
      super.placeholder(resourceId);
      return this;
  }
}

果不其然是,是贰个Builder,大家得以用来设置各类方式,各类景况.这一个Builder极度的大.因为要思索到全世界的须要啊.里面包车型大巴动画和编解码等都以无数的,然则那些皆以敷衍有滋有味的业务.

我们能够看一下UML图就领会了.

builder

接头了是Builder后,大家从来跳去builder的into方法看.

大家就以此来作为出发点。能够见到整个乞求使用的如今盛行的流式代码,我们来各个粉碎。

图片 1

2.

into()

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

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

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

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

    Request previous = target.getRequest();

    if (previous != null) {
        previous.clear();
        requestTracker.removeRequest(previous);
        previous.recycle();
    }
    //创建请求对象
    Request request = buildRequest(target);
    target.setRequest(request);
    //将target加入lifecycle
    lifecycle.addListener(target);
    //执行请求
    requestTracker.runRequest(request);

    return target;
}

我们通晓了三点:

  1. Util.assertMainThread();这里会检讨是还是不是主线程,不是的话会抛出非常,所以into方法必得在主线程中调用.
  2. 当你从未调用transform方法,並且你的ImageView设置了ScaleType,那么她会凭仗你的装置,对图片做管理(具体管理能够查看DrawableRequestBuilder的applyCenterCrop或许applyFitCenter方法,大家本人自定义BitmapTransformation也得以参照这里的管理).
  3. view在那边被封装成一个Target.

大家看看下面代码里面包车型地铁buildRequest方法.

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,
            requestListener,
            requestCoordinator,
            glide.getEngine(),
            transformation,
            transcodeClass,
            isCacheable,
            animationFactory,
            overrideWidth,
            overrideHeight,
            diskCacheStrategy);
}

个中有三个享元形式,有一些类似于Message.obtain同样,都是去生成Request,何况都以复用.

那是叁个插曲,回到into()内部来,最后生成了Request后,
调用requestTracker.runRequest(request);

/**
     * Starts tracking the given request.
     */
    public void runRequest(Request request) {
    //添加request对象到集合中
        requests.add(request);
        if (!isPaused) {
        //如果当前状态是非暂停的,调用begin方法发送请求
            request.begin();
        } else {
        //将请求加入到挂起的请求集合
            pendingRequests.add(request);
        }
    }

咱俩得以观望.将Request加多进二个set后,依旧调用了Requestbegin方法,这个Request是GenericRequest

咱俩步向看GenericRequestbegin方法

@Override
public void begin() {
    startTime = LogTime.getLogTime();
    if (model == null) {
        onException(null);
        return;
    }

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

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

在那边回调了target.onLoadStarted(getPlaceholderDrawable());办法,去设置占位图.这里的Target有很五种

但是都以回调他们的生命周期onLoadStart了.

这里大家来注意多少个细节,首先固然model等于null,model也正是大家在其次步load()方法中传播的图片UCR-VL地址,这一年会调用onException()方法。假设您跟到onException()方法里面去探访,你会意识它最后会调用到一个setErrorPlaceholder()当中.即是加载错误图片

GenericRequest类中还会有个根本措施,刚刚的begin措施里面会调用到.

大家看看代码.

/**
 * A callback method that should never be invoked directly.
 */
@Override
public void onSizeReady(int width, int height) {
    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
    }
    if (status != Status.WAITING_FOR_SIZE) {
        return;
    }
    status = Status.RUNNING;

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

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

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

在上头大家来看了非常多最重要词Loader,ResourceTranscoder,loadProvider,loadedFromMemoryCache,这一个不就是大家设计图纸加载框架最基本的地方么,加载器,转码器,加载器管理器,缓存池都在那边有影子.

加载器,转码器等是怎么依据项目决断的大家得以跳过,加载器和转码器有一点数不尽种,又是二个大的悬空树.可是还是不是第一,大家看这几个只要看其一级接口就行了.

咱俩一贯去看engin怎么load的.

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

    final String id = fetcher.getId();
    EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
            loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
            transcoder, loadProvider.getSourceEncoder());
    // 从缓存加载
    EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
    if (cached != null) {
        // 获取数据成功,会回调target的onResourceReady() 结束
        cb.onResourceReady(cached);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Loaded resource from cache", startTime, key);
        }
        return null;
    }
    // 尝试从活动Resources 中获取,它表示的是当前正在使用的Resources,与内存缓存不同之处是clear缓存时不会clear它。
    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;
    }
    //判断jobs中是否已经存在任务,如果存在说明任务之前已经提交了
    EngineJob current = jobs.get(key);
    if (current != null) {
        current.addCallback(cb);
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            logWithTimeAndKey("Added to existing load", startTime, key);
        }
        return new LoadStatus(cb, current);
    }
    //缓存没有获取到,创建EngineJob 对象
    EngineJob 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);
}

地点步骤为:

  1. 先依据调用loadFromCache从内部存款和储蓄器加载,成功赢得后直接回调重返.失利继续
  2. 品味从运动Resources 中获得,成功再次来到,失败继续
  3. 去看清job是不是早就存在,存在了就再次回到新的景色,没有则三番五次
  4. 开创job,创制decodejob,成立runnable,开启job.EngineRunnable的run()方法在子线程个中试行了

未来大家去看EngineRunnable终究干了啥.

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

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

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

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

妈的切近没干什么事情,就至关心爱惜要调了decode()主意啊,之后都回调成功恐怕失利的结果了.表达鲜明就在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();
}

上面一看,decode()又去调用decodeFromCache()decodeFromSource()了.抓头,这么快就decode了?source在哪来的呦,我们间接点进去看,我们传入的是url的时候,近日而言,图片还没下载下来呢.

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

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

有一丝期待,我们看看了原本那一个中不是decode大家的图片.並且是decode大家的url能源.
看到了首要词fetcher.loadData(priority);

因为事先就用uml生成工具看了Glide的uml图,fetcher可是担任load义务的人.

我们看一下fetcher的uml

fetcher.png

其间可是有加载方法的.大家去看一个Fetcher,就使用率最高的HttpUrlFetcher吧.

    public InputStream loadData(Priority priority) throws Exception {
        return this.loadDataWithRedirects(this.glideUrl.toURL(), 0, (URL)null);
    }

    private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl) throws IOException {
        if(redirects >= 5) {
            throw new IOException("Too many (> 5) redirects!");
        } else {
            try {
                if(lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
                    throw new IOException("In re-direct loop");
                }
            } catch (URISyntaxException var7) {
                ;
            }

            this.urlConnection = this.connectionFactory.build(url);
            this.urlConnection.setConnectTimeout(2500);
            this.urlConnection.setReadTimeout(2500);
            this.urlConnection.setUseCaches(false);
            this.urlConnection.setDoInput(true);
            this.urlConnection.connect();
            if(this.isCancelled) {
                return null;
            } else {
                int statusCode = this.urlConnection.getResponseCode();
                if(statusCode / 100 == 2) {
                    this.stream = this.urlConnection.getInputStream();
                    return this.stream;
                } else if(statusCode / 100 == 3) {
                    String redirectUrlString = this.urlConnection.getHeaderField("Location");
                    if(TextUtils.isEmpty(redirectUrlString)) {
                        throw new IOException("Received empty or null redirect url");
                    } else {
                        URL redirectUrl = new URL(url, redirectUrlString);
                        return this.loadDataWithRedirects(redirectUrl, redirects + 1, url);
                    }
                } else if(statusCode == -1) {
                    throw new IOException("Unable to retrieve response code from HttpUrlConnection.");
                } else {
                    throw new IOException("Request failed " + statusCode + ": " + this.urlConnection.getResponseMessage());
                }
            }
        }
    }

意料之中,在这里加载url,从互连网获取财富.
感恩,大家算是找到调用urlConnection的源码了!能够看来我们获得了互连网央浼的InputStream,

对应于HttpUrlFetcher的是ImageVideoBitmapDecoder,
它是抽出InputStream,因为这一个InputStream种类对于这两货来讲都以T类型.相对应的.

代码如下,能够观望,我们的通过decode,成功获得bitmap.刚刚的InputStream早就被打包到ImageVideoWrapper source里面了.通过InputStream is = source.getStream();拿到.

public class ImageVideoBitmapDecoder implements ResourceDecoder<ImageVideoWrapper, Bitmap> {
    private static final String TAG = "ImageVideoDecoder";
    private final ResourceDecoder<InputStream, Bitmap> streamDecoder;
    private final ResourceDecoder<ParcelFileDescriptor, Bitmap> fileDescriptorDecoder;

    public ImageVideoBitmapDecoder(ResourceDecoder<InputStream, Bitmap> streamDecoder,
            ResourceDecoder<ParcelFileDescriptor, Bitmap> fileDescriptorDecoder) {
        this.streamDecoder = streamDecoder;
        this.fileDescriptorDecoder = fileDescriptorDecoder;
    }

    @SuppressWarnings("resource")
    // @see ResourceDecoder.decode
    @Override
    public Resource<Bitmap> decode(ImageVideoWrapper source, int width, int height) throws IOException {
        Resource<Bitmap> result = null;
        InputStream is = source.getStream();
        if (is != null) {
            try {
                result = streamDecoder.decode(is, width, height);
            } catch (IOException e) {
                if (Log.isLoggable(TAG, Log.VERBOSE)) {
                    Log.v(TAG, "Failed to load image from stream, trying FileDescriptor", e);
                }
            }
        }

        if (result == null) {
            ParcelFileDescriptor fileDescriptor = source.getFileDescriptor();
            if (fileDescriptor != null) {
                result = fileDescriptorDecoder.decode(fileDescriptor, width, height);
            }
        }
        return result;
    }

    @Override
    public String getId() {
        return "ImageVideoBitmapDecoder.com.bumptech.glide.load.resource.bitmap";
    }
}

都拿到了bitmap了,上面马到成功了

啊哎作者去,太长了,写了三钟头,好不轻易获得bitmap了.接下来就是什么样展现怎么回调了.
显示回调部分,未来有机遇再深入分析.


本文小编:安德森/Jerey_Jobs

博客地址 :
http://jerey.cn/

简书地址 :
Anderson大码渣

github地址 :
https://github.com/Jerey-Jobs

  • ### 早先核算

    • Glide注释写的很清楚,是二个提供必要接口的单例,和大家听得多了自然能详细说出来的假相方式很一般,它是三个要求的输入,你能够见见,类中的非常多办法都以静态的,直接通过Glide来调起的。那么我们直接奔向核心,看一看with方法,你会发觉有相当多种载,然则最终都是统一踏入了fragmentGet只怕是supportFragmentGet来赢得三个RequestManager对象

     RequestManager supportFragmentGet(Context context, FragmentManager fm) { //根据传入的Fragment来获取RequestManager SupportRequestManagerFragment current = getSupportRequestManagerFragment; RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode; current.setRequestManager(requestManager); } return requestManager;}
    

基本概念
RequestManager:伏乞保管,每贰个Activity都会创制八个RequestManager,依据对应Activity的生命周期管理该Activity上就此的图样伏乞。
Engine:加载图片的内燃机,依照Request创制EngineJob和DecodeJob。
EngineJob:图片加载。
DecodeJob:图片管理。
流程图
此地是轮廓的完整流程图, 具体的细节中流程上边继续深入分析。

compile’com.github.bumptech.glide:okhttp3-integration:1.4.0@aar’//
那么些是用来对接 okhttp3.x 的

图片 2

然后在AndroidManifest.xml文本加多

 会根据你具体传入的类型的不同,最终选择3.0+的Fragment还是AppCompat的Fragment。由于两种不同的Fragment的FragmentManager是不同的,此处有两种方法`getSupportRequestManagerFragment` 和`getRequestManagerFragment`,实际上原理是一样的。

3. 宗旨类介绍

android:name=”com.bumptech.glide.integration.okhttp3.OkHttpGlideModule”

SupportRequestManagerFragment getSupportRequestManagerFragment(final
FragmentManager fm)
{//当前fragment栈中是还是不是有大家需求的fragment在SupportRequestManagerFragment
current = (SupportRequestManagerFragment)
fm.findFragmentByTag(FRA庆大霉素ENT_TAG);if (current == null)
{//借使空中楼阁,去大家的缓存Map中取current =
pendingSupportRequestManagerFragments.get;if (current == null)
{//假若依然没有去生成那几个Fragmentcurrent = new
SupportRequestManagerFragment();pendingSupportRequestManagerFragments.put(fm,
current);fm.beginTransaction().add(current,
FRA维生霉素ENT_TAG).commitAllowingStateLoss();//抹去缓存map中该key值handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER,
fm).sendToTarget();}}return current;}

3.1 Gilde 用以保存整个框架中的配置。
关键方法:

android:value=”GlideModule”/>

 Glide利用生成额外的无界面Fragment到Framgent栈中,用来同步context的生命周期。 * RequestManager A class for managing and starting requests for Glide 用来管理和发起请求的类。 我们顺着load方法去看,又是个重载方法,根据传入的type的类型不同,返回不同类型的`GenericRequestBuilder`
public static RequestManager with(FragmentActivity activity) {
 RequestManagerRetriever retriever = RequestManagerRetriever.get();
 return retriever.get(activity);
}

在混淆配置文件中

public DrawableTypeRequest<String> load(String string) {return
(DrawableTypeRequest<String>) fromString().load;}public
DrawableTypeRequest<String> fromString() {return
loadGeneric(String.class);}private <T>
DrawableTypeRequest<T> loadGeneric(Class<T> modelClass)
{…}

用于创制RequestManager,这里是Glide通过Activity/Fragment生命周期管理Request原理所在,那一个类很器重、很着重、很重视,主要的业务本人只说三回。
重大原理是创办三个自定义Fragment,然后通过自定义Fragment生命周期操作RequestManager,进而达成管理Request。

#glide图库

DrawableRequestBuilder.java

图片 3

-keepclass com.bumptech.glide..** {*;}

@Overridepublic DrawableRequestBuilder<ModelType> load(ModelType
model) {super.load;return this;}

3.2 RequestManagerRetriever

-keepclass com.bumptech.glide.integration.okhttp3.OkHttpGlideModule

GenericRequestBuilder.java
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;
}

#or

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

此间推断是还是不是只当前RequestManagerFragment是还是不是存在RequestManager,保险一个Activity对应二个RequestManager,
那样有利于管理八个Activity上拥有的Request。创设RequestManager的时候会将RequestManagerFragment中的回调接口赋值给RequestManager,达到RequestManager监听RequestManagerFragment的生命周期。

#-keep public class * implements com.bumptech.glide.module.GlideModule

 最后得到的是一个`DrawableRequestBuilder<ModelType>`对象,强转成`DrawableTypeRequest<ModelType>`。 * GenericRequestBuilder的不断构造 我们通过centerCrop方法去进中央裁剪,DrawableTypeRequest的centerCrop方法在父类DrawableRequestBuilder中

3.3 RequestManager 分子变量:
(1)Lifecycle lifecycle,用于监听RequestManagerFragment生命周期。
(2)RequestTracker requestTracker,
用于保存当前RequestManager全体的伏乞和带管理的乞请。
非常重要措施:

@Overridepublic DrawableRequestBuilder<ModelType>
transform(Transformation<GifBitmapWrapper>… transformation)
{super.transform(transformation);return this;}

@Override
//开始暂停的请求
public void onStart() {
 resumeRequests();
}
//停止所有的请求
@Override
public void onStop() {
 pauseRequests();
}

//关闭所以的请求
@Override
public void onDestroy() {
 requestTracker.clearRequests();
}

//创建RequestBuild
public DrawableTypeRequest<String> load(String string) {
 return (DrawableTypeRequest<String>) fromString().load(string);
}

public <Y extends Target<TranscodeType>> Y into(Y target) {
 ...
 Request previous = target.getRequest();
 //停止当前target中的Request。
 if (previous != null) {
 previous.clear(); //这个地方很关键,见Request解析
 requestTracker.removeRequest(previous);
 previous.recycle();
 }
 ...
 return target;
}
GenericRequestBuilder.java

3.4 DrawableRequestBuilder 用来创建Request。
那一个中富含十分多格局,主若是布局加载图片的url、大小、动画、ImageView对象、自定义图片管理接口等。

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

3.5 Request 根本是操作伏乞,方法都很简短。

 return this;}

 修改内部参数,并且以构造者模式返回自己本身以供继续修改使用。 之后的`placeholder`方法也是继续修改GenericRequestBuilder的参数,为请求增加占屏图片。 `crossFade`方法则是增加了animationFactory参数
@Override
public void clear() {
 ...
 if (resource != null) {
 //这里会释放资源
 releaseResource(resource);
 }
 ...
}

GenericRequestBuilder<ModelType, DataType, ResourceType,
TranscodeType> animate(GlideAnimationFactory<TranscodeType>
animationFactory) {if (animationFactory == null) {throw new
NullPointerException(“Animation factory must not be
null!”);}this.animationFactory = animationFactory;

此地的基本原理是当有Target使用Resource(Resource见下文)时,Resource中的援引记数值会加一,当释放能源Resource中的援用记数值减一。当未有Target使用的时候就能放出能源,放进Lrucache中。

 return this;}

 期间方法不单单有transform,包括priority修改优先级,encoder修改编码方式,diskCacheStrategy修改硬盘缓存策略等等。 * ###最后的into方法 之前都是在买材料囤货,就是这个方法开始做请求。 DrawableRequestBuilder.java

3.6 EngineResource 福如东海Resource接口,使用装饰格局,里面含有实际的Resource对象

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

void release() {
 if (--acquired == 0) {
 listener.onResourceReleased(key, this);
 }
} 

void acquire() {
 ++acquired;
} 

@Override
public void recycle() {
 isRecycled = true;
 resource.recycle();
}
GenericRequestBuilder.java

acquire和release八个艺术是对财富援用计数;recycle释放能源,一般在Lrucache饱和时会触发。

public Target<TranscodeType> into(ImageView view)
{//判定是还是不是在主线程Util.assertMainThread();if (view == null) {throw new
IllegalArgumentException(“You must pass in a non null
View”);}//就算imageView自个儿有填充方式,伏乞那么做相应的拍卖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.}}

3.7 Engine(重要) 恳请引擎,首要做央浼的先河的起首化。
3.7.1 load方法 这几个主意相当长,将分成几步剖析
(1)获取MemoryCache中缓存
首先成立当前Request的缓存key,通过key值从MemoryCache中获得缓存,剖断缓存是或不是留存。

 return into(glide.buildImageViewTarget(view, transcodeClass));
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
 ....
 EngineResource<?> cached = getEngineResourceFromCache(key);
 if (cached != null) {
 cached.acquire();
 activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
 }
 return cached;
}

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

 final EngineResource result;
 ...
 return result;
}

}

(入眼)从缓存中拿走的时候使用的cache.remove(key),然后将值保存在activeResources中,然后将Resource的引用计数加一。
优点:
>
正使用的Resource将会在activeResources中,不会油不过生在cache中,当MemoryCache中缓存饱和的时候照旧系统内部存款和储蓄器不足的时候,清理Bitmap能够直接调用recycle,不用思量Bitmap正在采纳导致至极,加速系统的回收。
(2)获取activeResources中缓存
activeResources通过弱引用保存recouse ,也是通过key获取缓存,

 然后通过传入view和转码类型(transcodeClass)来创建相应的Target。ImageViewTargetFactory.java ```public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) { if (GlideDrawable.class.isAssignableFrom { return (Target<Z>) new GlideDrawableImageViewTarget; } else if (Bitmap.class.equals { return (Target<Z>) new BitmapImageViewTarget; } else if (Drawable.class.isAssignableFrom { return (Target<Z>) new DrawableImageViewTarget; } else { throw new IllegalArgumentException("Unhandled class: " + clazz + ", try .as*.transcode(ResourceTranscoder)"); } }

 OK,我们继续往下看,看下重载的方法into

public <Y extends Target<TranscodeType>> Y into { 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.recycle(); } Request request = buildRequest; target.setRequest; lifecycle.addListener; requestTracker.runRequest; return target; }
private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable)

Glide会先去看那些target在此之前有未有过供给,假如那个target在此之前有过央求要把这几个诉求clear掉,并且recycle。也便是说,如果一个imageView上我们要频仍做加载央求,那么最后以最终一回呼吁为准。那么些在listView也许是RecyclerView中采用就一定频仍了。看到target.getRequest()方法,根据此前大家说的或是会生成的两种差别的target,大家这里去看BitmapImageViewTarget,最终的getRequest方法是在父类ViewTarget

(3)剖断当前的伸手任务是还是不是业已存在

public Request getRequest() { Object tag = getTag(); Request request = null; if (tag != null) { if (tag instanceof Request) { request =  tag; } else { throw new IllegalArgumentException("You must not call setTag() on a view Glide is targeting"); } } return request; }private Object getTag() { if (tagId == null) { return view.getTag(); } else { return view.getTag; } }
EngineJob current = jobs.get(key);
if (current != null) {
 current.addCallback(cb);
 return new LoadStatus(cb, current);
}

由此很扎眼了,Glide玩的套路是把request对象通过setTag的点子和View绑定的

倘若职责乞请已经存在,直接将回调事件传递给曾经存在的EngineJob,用于恳求成功后触发回调。
(4)实践央求职责

 继续看request是如何build出来的 ```
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);

private Request buildRequest(Target<TranscodeType> target)
{//固然完成未有事先级的明确,设置为预先级普通if (priority == null)
{priority = Priority.NORMAL;}return buildRequestRecursive(target,
null);}private Request buildRequestRecursive(Target<TranscodeType>
target, ThumbnailRequestCoordinator parentCoordinator) {if
(thumbnailRequestBuilder != null) {//缩略图的相应的request创制…} else
if (thumbSizeMultiplier != null) {// Base case: thumbnail multiplier
generates a thumbnail request, but cannot recurse….} else {// Base
case: no thumbnail.return obtainRequest(target, sizeMultiplier,
priority, parentCoordinator);}}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);}

3.8 EngineRunnable 诉求实施Runnable,首要功效央浼财富、管理能源、缓存财富。

 我们看到真正的生成请求方法`obtainRequest`,传入了大量的参数,我们不一一深究是什么东西,我们先接着看生成了请求之后的下一个方法,` requestTracker.runRequest;`
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();
}

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

加载DiskCache和互联网能源。加载DiskCache包罗三个,因为Glide暗中同意是保存管理后的财富(压缩和剪裁后),缓存形式能够自定义配置。假使客商端标准设计,ImageView大小超越45%一样能够节约图片加载时间和Disk能源。

requestTracker内部维护了一个请求列表,那我们直接进入到request实现类,去看看begin方法到底做了什么。

3.9 DecodeJob public Resource<Z> decodeResultFromCache() throws Exception  
从缓存中拿走管理后的能源。上面有关Key的原委,Key是一个对象,能够赢得key和orginKey。decodeResultFromCache便是通过key获取缓存,decodeSourceFromCache()便是经过orginKey获取缓存。
private Resource<Z> transformEncodeAndTranscode(Resource<T>
decoded)
管理和包装能源;缓存财富。
保存原财富
private Resource<T> cacheAndDecodeSourceData(A data) throws
IOException 
保留管理后的财富
private void writeTransformedToCache(Resource<T> transformed)

@Overridepublic void begin() {startTime =
LogTime.getLogTime();//正是从前提到的load传入类型,即使都未有加载类型就抛非常if
(model == null) {onException;return;}

3.10 Transformation Resource<T> transform(Resource<T> resource, int outWidth,
int outHeight);
拍卖资源,那其间出现BitmapPool类,达到Bitmap复用。
3.11 ResourceDecoder 用以将文件、IO流转化为Resource
3.12 BitmapPool 用以寄放从LruCache中remove的Bitmap,
用于前面成立Bitmap时候的再度利用。

 status = Status.WAITING_FOR_SIZE; //如果已经拿到了尺寸就进入加载流程,否则继续View的尺寸 if (Util.isValidDimensions(overrideWidth, overrideHeight)) { onSizeReady(overrideWidth, overrideHeight); } else { target.getSize; } //如果正在请求,那么就为view填充占位图 if (!isComplete() && !isFailed() && canNotifyStatusChanged { target.onLoadStarted(getPlaceholderDrawable; } if (Log.isLoggable(TAG, Log.VERBOSE)) { logV("finished run method in " + LogTime.getElapsedMillis(startTime)); }

4.杂谈 Glide的架构扩充性高,不过难以领会,各样接口、泛型,要求确定的读书技巧听得多了就能说的详细运用。
Glide的优点:
(1)帮助对管理后的财富Disk缓存。
(2)通过BitmapPool对Bitmap复用。
(3)使用activityResources缓存正在采纳的resource,对于BitmapPool饱和移除的Bitmap直接调用recycle加快内存回收。

}

你可能感兴趣的小说:

  • Android中Glide加载圆形图片和圆角图片实例代码
  • Android关于Glide的应用(高斯模糊、加载监听、圆角图形)
  • Android
    Glide图片加载(加载监听、加载动画)
  • Android中Glide加载库的图纸缓存配置究极指南
  • Android
    App中应用Glide加载图片的科目
  • Android的Glide库加载图片的用法及其与Picasso的自己检查自纠
  • Android
    使用Glide加载互连网图片等比例缩放的落实际意况势
 终于我们找到最终的加载方法在这个onSizeReady回调中

@Overridepublic void onSizeReady(int width, int height) { //参数准备 ... loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder, priority, isMemoryCacheable, diskCacheStrategy, this); loadedFromMemoryCache = resource != null; if (Log.isLoggable(TAG, Log.VERBOSE)) { logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime)); }

}

 最终GenericRequest把加载任务都扔到了engin中去了

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

 final String id = fetcher.getId(); //创建每一次任务的加载的唯一标识key EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(), loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(), transcoder, loadProvider.getSourceEncoder; // 通过key查找内存缓存中是否存在引擎资源,如果有就直接可以拿来用,触发onResourceReady回调 EngineResource<?> cached = loadFromCache(key, isMemoryCacheable); if (cached != null) { //触发资源就绪回调,直接加载资源 cb.onResourceReady; if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Loaded resource from cache", startTime, key); } return null; } // 通过key查找是否存在弱引用可以利用 EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable); if (active != null) { cb.onResourceReady; if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Loaded resource from active resources", startTime, key); } return null; } //再没有就去本地的map列表中通过key查找是否存在EngineJob,这与上面的EngineResource不同 EngineJob current = jobs.get; if (current != null) { //加入内部的callback队列,最终也会执行如上的onResourceReady回调 current.addCallback; if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Added to existing load", startTime, key); } return new LoadStatus(cb, current); } //如果都没有,去创建一个EngineJob,去做加载请求 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; //执行job engineJob.start; if (Log.isLoggable(TAG, Log.VERBOSE)) { logWithTimeAndKey("Started new load", startTime, key); } return new LoadStatus(cb, engineJob);}

 这里涉及到多级缓存,以及最终的请求任务加载,我们打开`EngineRunnable`,来看下最终是怎么请求的。 * ###藏得最深的DecodeJob EngineRunnable.java```@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; } }private Resource<?> decode() throws Exception { if (isDecodingFromCache { //缓存中已经有了我们需要的data return decodeFromCache(); } else { //缓存中还没有我们需要的data,我们需要先去获得data,再将data转为我们需要的model类型 return decodeFromSource(); } }

四个法子,一个是缓存中管理过此类乞请,直接从缓存中呼吁,我们直接看第一个decodeFromSourcedecodeFromSource()->DecodeJob.decodeFromSource()->DecodeJob.decodeSource()->DecodeJob.decodeFromSourceData(),最后,我们找到这一句

 //将data进行decode,变成我们需要的decoded类型 decoded = loadProvider.getSourceDecoder().decode(data, width, height);

包涵,走另一条decodeFromCache,也会走到这一句。经过反复的倒推与追寻,我们发现在Glide的构造函数中,有着如此一坨代码

dataLoadProviderRegistry = new DataLoadProviderRegistry(); StreamBitmapDataLoadProvider streamBitmapLoadProvider = new StreamBitmapDataLoadProvider(bitmapPool, decodeFormat); dataLoadProviderRegistry.register(InputStream.class, Bitmap.class, streamBitmapLoadProvider); FileDescriptorBitmapDataLoadProvider fileDescriptorLoadProvider = new FileDescriptorBitmapDataLoadProvider(bitmapPool, decodeFormat); dataLoadProviderRegistry.register(ParcelFileDescriptor.class, Bitmap.class, fileDescriptorLoadProvider); ImageVideoDataLoadProvider imageVideoDataLoadProvider = new ImageVideoDataLoadProvider(streamBitmapLoadProvider, fileDescriptorLoadProvider); dataLoadProviderRegistry.register(ImageVideoWrapper.class, Bitmap.class, imageVideoDataLoadProvider); GifDrawableLoadProvider gifDrawableLoadProvider = new GifDrawableLoadProvider(context, bitmapPool); dataLoadProviderRegistry.register(InputStream.class, GifDrawable.class, gifDrawableLoadProvider); dataLoadProviderRegistry.register(ImageVideoWrapper.class, GifBitmapWrapper.class, new ImageVideoGifDrawableLoadProvider(imageVideoDataLoadProvider, gifDrawableLoadProvider, bitmapPool)); dataLoadProviderRegistry.register(InputStream.class, File.class, new StreamFileDataLoadProvider; register(File.class, ParcelFileDescriptor.class, new FileDescriptorFileLoader.Factory; register(File.class, InputStream.class, new StreamFileLoader.Factory; register(int.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory; register(int.class, InputStream.class, new StreamResourceLoader.Factory; register(Integer.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory; register(Integer.class, InputStream.class, new StreamResourceLoader.Factory; register(String.class, ParcelFileDescriptor.class, new FileDescriptorStringLoader.Factory; register(String.class, InputStream.class, new StreamStringLoader.Factory; register(Uri.class, ParcelFileDescriptor.class, new FileDescriptorUriLoader.Factory; register(Uri.class, InputStream.class, new StreamUriLoader.Factory; register(URL.class, InputStream.class, new StreamUrlLoader.Factory; register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory; register(byte[].class, InputStream.class, new StreamByteArrayLoader.Factory;

实际上Glide早已曾经把主旨全数的加载央求意况都曾经思量在内了。dataLoadProviderRegistry注册的是将data调换来resource的景观register方法注册是将model调换来data。

DecodeJob中的三个第一的类正是和上边包车型地铁事物有关的

private final DataFetcher<A> fetcher; private final DataLoadProvider<A, T> loadProvider;

fetcher担当把model调换来dataloadProvider再担任把data转变来我们必要的财富类型resource。在下面的decode流程中的decodeSource()方法大家能收看fetcher的调用,也唯有在这么些主意中大家能够看看fetcher的调用,因为唯有缓存中绝非现有的data,我们才会去做一遍model调换来data。追根溯源,你会意识,末了这几个fetcher正是上边register方法中的XXXXXLoader.getResourceFetcher再次回到的DataFetcher对象,大家就取贰个Http的央求看一下:

 register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory;]

此地说多美滋(Dumex)下,之所以选取GlideUrl转换到输入流是因为,全体的http和https的互联网url最终都会被转变来GlideUrl,具体原因见UriLoader.java

@Override public final DataFetcher<T> getResourceFetcher(Uri model, int width, int height) { ... if (isLocalUri { ... } else if (urlLoader != null && ("http".equals || "https".equals { result = urlLoader.getResourceFetcher(new GlideUrl(model.toString, width, height); } return result;}

HttpUrlFetcher.java

@Override public InputStream loadData(Priority priority) throws Exception { return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders; } 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; for (Map.Entry<String, String> headerEntry : headers.entrySet { urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue; } urlConnection.setConnectTimeout; urlConnection.setReadTimeout; urlConnection.setUseCaches; urlConnection.setDoInput; // 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; } }

互联网央浼正是在此间去实行的,使用的HttpUrlConnection。

  • ### 总结

    一次呼吁流程差相当的少如下

    • 率先通过Glide.with方法生成RequestManager对象来治本央求
    • 调用RequestManager.load方法来说我们的modelType传入,并得到相应的RequestBuilder对象。
    • 通过构造者格局不断去给RequestBuilder扩张条件,举例裁剪,优先级,占位图等等
    • 因而into方法传入指标target,并拉开诉求
    • 翻看目的View的tag中收获看看是或不是有request,要是有则清除。然后用新建的request来覆盖。
    • 实行request,三级缓存战略,先看缓存中是还是不是存在EngineResource,再看是或不是有EngineResource的若援用,最终看Map中是还是不是留存EngineJob。假设有则一贯再次来到结果并举办相应加载
    • new并执行EngineRunnable这个DecoderJob的封装
    • 在DecoderJob内部查看是还是不是存在对应的InputStream可能是ParcelFileDescriptor,借使已经存在,则一向将其通过loadProviderdecode成相应的Bitmap,gif等。不然就经过fetcher先将大家由此load传入的门道实行剖析成InputStream、ParcelFileDescriptor,再decode。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图