美文网首页
Glide开源库源码分析及基本用法

Glide开源库源码分析及基本用法

作者: 碧云天EthanLee | 来源:发表于2021-07-23 19:19 被阅读0次
概述

Glide 是这几年关注度比较高的图片加载框架。它涉及到生命周期管理、网络加载、图片解析、缓存与显示等内容。这篇文章就从源码出发,从生命周期管理、数据加载等方面来分析分析Glide的一些原理。然后讲一讲一些基本用法。

Glide源码:Glide

一、生命周期管理

还是老规矩,从最简单的使用作为切入:

 Glide.with(this)
                .load(url)
                .into(glideImage);

这是最简单的使用方式,而且又是一个链式结构。我们知道,图片加载过程中若页面退出,按理说是需要在Activity或者 Fragment的生命周期方法里调用停止图片加载相应方法的。但 Glide却不需要这样做,那么它是怎么管理加载的生命周期的呢?我们点进上面 Glide.with()这个方法,看它如何管理生命周期。

//Glide.java
  @NonNull
  public static RequestManager with(@NonNull FragmentActivity activity) {
    return getRetriever(activity).get(activity);
  }

  // RequestManagerRetriever.java
  public RequestManager get(@NonNull FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      assertNotDestroyed(activity);
      frameWaiter.registerSelf(activity);
      FragmentManager fm = activity.getSupportFragmentManager();
     // 注释 1 supportFragmentGet() 方法
      return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }

Glide.with() 方法有好几个重载方法,
参数可以传 Activity 、Fragment 、Context,这里不建议传 Context作为参数,因为最终可能会使得加载的生命周期与 Application同步。这点就不做分析了,可看 Context参数的重载方法。这里我们以 Activity 作为参数的方法展开讲讲。

看上面注释 1处的地方,获取了 FragmentManager 对象作为参数,在方法返回处调用了 supportFragmentGet()方法,我们点进这个方法看一下:

 // RequestManagerRetriever.java
 @NonNull
  private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {
     // 注释 2,创建一个 Fragment 通过 FragmentManager 绑定 Activity
    SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      // TODO(b/27524013): Factor out this Glide.get() call.
      Glide glide = Glide.get(context);
      //  注释 3,创建 RequestManager 对象(Lifecycle 对象作为参数)
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      ......
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

我们可以看到,上面贴出来的这些方法的返回值都是 RequestManager 。上面代码注释 2和注释 3标注了两个重要的地方,注释 2处在getSupportRequestManagerFragment()方法里,创建了一个Fragment,并用 FragmentManager 与Activity绑定。这样 新创建的Fragment就可以感知 Activity的生命周期,进而对图片加载的生命周期进行管理。我们可以点进 getSupportRequestManagerFragment() 方法看一下:

 // RequestManagerRetriever.java
  private SupportRequestManagerFragment getSupportRequestManagerFragment(
      @NonNull final FragmentManager fm, @Nullable Fragment parentHint) {
    SupportRequestManagerFragment current =
        (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
      current = pendingSupportRequestManagerFragments.get(fm);
      if (current == null) {
        current = new SupportRequestManagerFragment();
        current.setParentFragmentHint(parentHint);
        pendingSupportRequestManagerFragments.put(fm, current);
        fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
        handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
      }
    }
    return current;
  }

看到这里我们需要看一下这个新建的 SupportRequestManagerFragment 的一些源码,看看它生命周期管理的工具 Lifecycle:

// RequestManagerFragment .java
public class RequestManagerFragment extends Fragment {
  private static final String TAG = "RMFragment";
  private final ActivityFragmentLifecycle lifecycle;
   ......
  RequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
    this.lifecycle = lifecycle;
  }
......
 ActivityFragmentLifecycle getGlideLifecycle() {
    return lifecycle;
  }
......
@Override
  public void onStart() {
    super.onStart();
  // 注释 4,在 Fragment 生命周期回调方法里,调用生命周期管理器 lifecycle管理加载生命周期
    lifecycle.onStart();
  }

  @Override
  public void onStop() {
    super.onStop();
  // 注释 5,在 Fragment 生命周期回调方法里,调用生命周期管理器 lifecycle管理加载生命周期
    lifecycle.onStop();
  }

  @Override
  public void onDestroy() {
    super.onDestroy();
  // 注释 6,在 Fragment 生命周期回调方法里,调用生命周期管理器 lifecycle管理加载生命周期
    lifecycle.onDestroy();
    unregisterFragmentWithRoot();
  }
}

上面我们看到,注释 4、注释 5、注释 6处,在 Fragment的生命周期分别调用了 生命周期管理对象 lifecycle的相关方法,以管理加载生命周期。最后我们再看一下 ActivityFragmentLifecycle的 onStart() 、onStop()和 onDestroy()方法的实现吧:

  // ActivityFragmentLifecycle.java
 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();
    }
  }

上面是一种观察者设计模式,只要 Fragment的生命周期发生变化,生命周期管理器 Lifecycle就会遍历各个观察者,并调用个观察者的生命周期方法。

好了,我们再回过头来看一下,RequestManager 是怎么把自己注册成Fragment生命周期的观察者的。再看回上面注释 3处:

// RequestManagerRetriever.java
requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);

这里创建了 RequestManager对象,并且从上面的参数看,Fragment用于生命周期管理的 Lifecycle也作为参数传给了 RequestManager。我们先看看 上面build()方法做了啥:

// RequestManagerRetriever.java
 private static final RequestManagerFactory DEFAULT_FACTORY =
      new RequestManagerFactory() {
        @NonNull
        @Override
        public RequestManager build(
            @NonNull Glide glide,
            @NonNull Lifecycle lifecycle,
            @NonNull RequestManagerTreeNode requestManagerTreeNode,
            @NonNull Context context) {
          //注释 7 创建 RequestManager对象
          return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
        }
      };

看上面的注释 7处,RequestManager对象终于被创建出来了。我们来看一下 RequestManager类里用于生命周期管理的一些方法和参数:

// RequestManager.java

 // 注释 8, RequestManager实现了用于生命周期管理的接口 LifecycleListener,
 //并实现了 onStart()、 onStop() 、onDestroy()方法。
public class RequestManager
    implements ComponentCallbacks2, LifecycleListener, ModelTypes<RequestBuilder<Drawable>> {
       ......
       final Lifecycle lifecycle;
       ......
 private final Runnable addSelfToLifecycle =
      new Runnable() {
        @Override
        public void run() {
          //  注释 10,将当前对象注册为观察者
          lifecycle.addListener(RequestManager.this);
        }
      };
      ......
RequestManager(
      Glide glide,
      // 注释 9,构造器里传进 Fragment生命周期管理对象 Lifecycle 
      Lifecycle lifecycle,
      RequestManagerTreeNode treeNode,
      RequestTracker requestTracker,
      ConnectivityMonitorFactory factory,
      Context context) {
    this.glide = glide;
    this.lifecycle = lifecycle;
}

   ......
  @Override
  public synchronized void onStart() {
    // 注释 11,执行加载生命周期
    resumeRequests();
    targetTracker.onStart();
  }

  @Override
  public synchronized void onStop() {
// 注释 12,执行加载生命周期
    pauseRequests();
    targetTracker.onStop();
  }

  @Override
  public synchronized void onDestroy() {
// 注释 13,执行加载生命周期
    targetTracker.onDestroy();
    for (Target<?> target : targetTracker.getAll()) {
      clear(target);
    }
    targetTracker.clear();
    requestTracker.clearRequests();
    lifecycle.removeListener(this);
    lifecycle.removeListener(connectivityMonitor);
    Util.removeCallbacksOnUiThread(addSelfToLifecycle);
    glide.unregisterRequestManager(this);
  }

可以看到上面注释 8处, RequestManager实现了生命周期的接口 LifecycleListener,并实现了 onStart()、 onStop() 、onDestroy()方法。注释 10的地方用 Fragment传过来的 lifecycle将当前 RequestManager对象注册成 Fragment生命周期的观察者。上面分析过,Fragment的生命周期发生改变时,lifecycle对象就会遍历所有观察者,然后调用观察者相应的生命周期的方法,也就是上面注释 11、注释 12、注释 13处的 onStart()、 onStop() 、onDestroy()方法。从而达到框架图片加载生命周期与 Fragment(或者说 Activity)同步的目的。这样我们使用 Glide时就不用手动管理生命周期啦~

二、数据逐级加载

*内存缓存

下面我们来看数据加载。因为 RequestManager.load()方法只是将路径保存,所以我们往下看 RequestBuilder.into() 方法。

// RequestBuilder.java
    private <Y extends Target<TranscodeType>> Y into(
            @NonNull Y target,
            @Nullable RequestListener<TranscodeType> targetListener,
            BaseRequestOptions<?> options,
            Executor callbackExecutor) {
        ......
        // 打包 request
        Request request = buildRequest(target, targetListener, options, callbackExecutor);
        ......
        requestManager.clear(target);
        target.setRequest(request);
        // target 和 request 往下执行
        requestManager.track(target, request);
        return target;
    }
    // RequestBuilder.java
    synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
        targetTracker.track(target);
        // 执行请求
        requestTracker.runRequest(request);
    }

    // RequestTracker.java
    public void runRequest(@NonNull Request request) {
        requests.add(request);
        if (!isPaused) {
            // 开始执行 request
            request.begin();
        } else {
          ......
        }
    }
    // SingleRequest.java
    public void begin() {
        synchronized (requestLock) {
            ......
            if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
                // 尺寸已经准备好,进行下一步加载
                onSizeReady(overrideWidth, overrideHeight);
            } else {
                target.getSize(this);
            }
            ......
        }
    }
    // SingleRequest.java
    public void onSizeReady(int width, int height) {
        synchronized (requestLock) {
            ......
            loadStatus =
                    // 启动 Engine.java 的 load方法
                    engine.load(
                            ......
                            ......
                           );
          ......
        }
    }
    // Engine.java
    public <R> Engine.LoadStatus load(
           ......
          ) {
        long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
        // 生成 key值 ,从缓存中取
        EngineKey key =
                keyFactory.buildKey(
                        ......
                        );
        EngineResource<?> memoryResource;
        synchronized (this) {
            // 注释 14,  从内存缓存中取数据
            memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
           // 注释 15,上一步内存获取的数据为空,尝试从下一级缓存中获取
            if (memoryResource == null) {
                return waitForExistingOrStartNewJob(
                        ......
                );
            }
        }
        cb.onResourceReady(
                memoryResource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
        return null;
    }

上面一路追踪到了 Engine.load() 方法。数据加载时逐级从缓存中加载的,包括内存缓存、磁盘缓存、网络加载等等在内。上面注释 14是先从内存缓存中尝试获取数据,如果没有,则到上面注释 15 处往下级缓存中寻找。现在我们先看一下注释 14处内存缓存的取法:

  // Engine.java
    private EngineResource<?> loadFromMemory(
            EngineKey key, boolean isMemoryCacheable, long startTime) {
        // 注释16, 从弱引用缓存中获取资源
        EngineResource<?> active = loadFromActiveResources(key);
        if (active != null) {
            return active;
        }
        // 注释 17, LRU 缓存
        EngineResource<?> cached = loadFromCache(key);
        if (cached != null) {
            if (VERBOSE_IS_LOGGABLE) {
                logWithTimeAndKey("Loaded resource from cache", startTime, key);
            }
            return cached;
        }
        return null;
    }

从上面注释 16、注释 17中可以看到,内存缓存又分为两级,一级是从弱引用使用过的资源中加载,没有的话第二级再从LRU内存缓存中获取。下面我们来看看 LRU内存缓存:

// Engine.java
    private EngineResource<?> loadFromMemory(
            EngineKey key, boolean isMemoryCacheable, long startTime) {
        // 弱引用缓存
        EngineResource<?> active = loadFromActiveResources(key);
        if (active != null) {
            return active;
        }
        // LRU 缓存
        EngineResource<?> cached = loadFromCache(key);
        if (cached != null) {
            if (VERBOSE_IS_LOGGABLE) {
                logWithTimeAndKey("Loaded resource from cache", startTime, key);
            }
            return cached;
        }

        return null;
    }
    // Engine.java
    private EngineResource<?> loadFromCache(Key key) {
        // 内存缓存
        EngineResource<?> cached = getEngineResourceFromCache(key);
        .......
        return cached;
    }
    // Engine.java
    private EngineResource<?> getEngineResourceFromCache(Key key) {
        // 注释 18, cached 的实现类是 LruResourceCache
        Resource<?> cached = cache.remove(key);
        .......
        return result;
    }

上面一路追踪到了注释 18 的地方,cached 的实现类是 LruResourceCache。现在我们看看这个 LRU缓存实现类 LruResourceCache以及它的父类 LruCache:

 // LruResourceCache.java
    public class LruResourceCache extends LruCache<Key, Resource<?>> implements MemoryCache {
        private ResourceRemovedListener listener;
        public LruResourceCache(long size) {
            // 看父类 LruCache
            super(size);
        }}
    // LruCache.java
    public class LruCache<T, Y> {
        // 注释 19, Lru 内存缓存,使用 LinkedHashMap保存对象
        private final Map<T, com.bumptech.glide.util.LruCache.Entry<Y>> cache = new LinkedHashMap<>(100, 0.75f, true);
        // 缓存数量
        protected synchronized int getCount() {
            return cache.size();
        }
        // 根据 key 取缓存数据
        public synchronized Y get(@NonNull T key) {
            com.bumptech.glide.util.LruCache.Entry<Y> entry = cache.get(key);
            return entry != null ? entry.value : null;
        }
        // 保存数据
        public synchronized Y put(@NonNull T key, @Nullable Y item) {
            final int itemSize = getSize(item);

            LruCache.Entry<Y> old = cache.put(key, item == null ? null : new com.bumptech.glide.util.LruCache.Entry<>(item, itemSize));

            return old != null ? old.value : null;
        }
        // 注释20, 移除最近最少使用的数据 (LRU)
        protected synchronized void trimToSize(long size) {
            Map.Entry<T, com.bumptech.glide.util.LruCache.Entry<Y>> last;
            Iterator<Map.Entry<T, com.bumptech.glide.util.LruCache.Entry<Y>>> cacheIterator;
            while (currentSize > size) {
                cacheIterator = cache.entrySet().iterator();
                last = cacheIterator.next();
                final com.bumptech.glide.util.LruCache.Entry<Y> toRemove = last.getValue();
                currentSize -= toRemove.size;
                final T key = last.getKey();
                cacheIterator.remove();
                onItemEvicted(key, toRemove.value);
            }
        }
    }

看到上面应该就一目了然了,注释 19 处用一个 LinkedHashMap对象来保存内存缓存数据,这里有 get和 put方法分别用于读写数据。注释 20处,当数据量过大超过设置长度时,会移除最近最少使用的数据 (LRU)。

*磁盘缓存及网络加载

上面分析完了内存缓存,下面我们继续分析磁盘加载及网络加载。回到上面注释 15 的地方:

    // Engine.java
    public <R> Engine.LoadStatus load(
           ......
          ) {
       .......
        EngineResource<?> memoryResource;
        synchronized (this) {
            // 注释 14,  从内存缓存中取数据
            memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
           // 注释 15,上一步内存获取的数据为空,尝试从下一级缓存中获取
            if (memoryResource == null) {
                return waitForExistingOrStartNewJob(
                        ......
                );
            }
        }
        cb.onResourceReady(
                memoryResource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
        return null;
    }

下面继续往下看 waitForExistingOrStartNewJob() 这个方法:

 // Engine.java
    private <R> Engine.LoadStatus waitForExistingOrStartNewJob(
            ......
            ......
            ) {
        DecodeJob<R> decodeJob =
                decodeJobFactory.build(
                     ......
                     ......
                        );
        ......
        // 看start方法
        engineJob.start(decodeJob);
        return new Engine.LoadStatus(cb, engineJob);
    }
    // EngineJob.java
    public synchronized void start(DecodeJob<R> decodeJob) {
        this.decodeJob = decodeJob;
        //注释 21, GlideExecutor是一个线程池,那么 DecodeJob必然是一个 Runnable ,我们可以点进去看一下
        GlideExecutor executor =
                decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
        // 注释 22, 执行 Runnable
        executor.execute(decodeJob);
    }

看上面注释21 GlideExecutor 是一个线程池,注释 22执行了线程池 execute()方法。那么,DecodeJob对象必然是一个 Runnable对象,我们可以点进去看一看:

// DecodeJob.java
    class DecodeJob<R>
            implements DataFetcherGenerator.FetcherReadyCallback,
            Runnable,
            Comparable<com.bumptech.glide.load.engine.DecodeJob<?>>,
            FactoryPools.Poolable {
        public void run() {
            runWrapped();
        }

        private void runWrapped() {
            switch (runReason) {
                case INITIALIZE:
                    stage = getNextStage(com.bumptech.glide.load.engine.DecodeJob.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);
            }
        }

        private DataFetcherGenerator getNextGenerator() {
            switch (stage) {
                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);
            }
        }
    }

上面的 Runnable对象的run方法执行了相关的任务逻辑,这里面有多种缓存形式。我们看一下这个 DataCacheGenerator磁盘缓存及网络加载的相关的逻辑:

// DataCacheGenerator.java
    public boolean startNext() {
        while (modelLoaders == null || !hasNextModelLoader()) {
            sourceIdIndex++;
            if (sourceIdIndex >= cacheKeys.size()) {
                return false;
            }
            Key sourceId = cacheKeys.get(sourceIdIndex);
            Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
            cacheFile = helper.getDiskCache().get(originalKey);
            if (cacheFile != null) {
                this.sourceKey = sourceId;
                modelLoaders = helper.getModelLoaders(cacheFile);
                modelLoaderIndex = 0;
            }
        }
        boolean started = false;
        while (!started && hasNextModelLoader()) {
            // 注释 23, 逐级缓存获取
            // 循环从 modelLoaders中获取对应的加载数据的 ModelLoader
            // ModelLoader 用于加载数据,它有多个子类,分别用于本地资源加载和网络加载等等
            ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
            // 注释24, 获取对应的 LoadData,如果获取不到,则 started == false,进入下一次循环
            loadData =
                    modelLoader.buildLoadData(
                            cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());

            if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
                started = true;
                //注释 25, 调用对用的 Fetcher 来获取数据
                loadData.fetcher.loadData(helper.getPriority(), this);
            }
        }
        return started;
    }

上面这个 startNext()方法实现了主要逻辑。注释 23处使用了while 循环逐级获取数据。当加载数据的 LoadData 对象为空时,started 为 false,走进下一次循环。ModelLoader 用于加载数据,它有多个子类,分别用于本地资源加载和网络加载等。一旦从磁盘缓存中加载不到数据,就会切换到网络加载的线程池进行网络加载。下面我们来看看最后网络加载的 ModelLoader实现类 HttpGlideUrlLoader以及其对应的 HttpUrlFetcher实现的加载逻辑。

根据上面注释 24和 注释 25的顺序,我们先看获取 LoadData 对象的 HttpGlideUrlLoader.buildLoadData() 方法,再看一下注释 25处 HttpUrlFetcher调用的 loadData()方法。

// HttpGlideUrlLoader .java
public class HttpGlideUrlLoader implements ModelLoader<GlideUrl, InputStream> {
  public static final Option<Integer> TIMEOUT =
     Option.memory("com.bumptech.glide.load.model.stream.HttpGlideUrlLoader.Timeout", 2500);
  @Nullable private final ModelCache<GlideUrl, GlideUrl> modelCache;
  public HttpGlideUrlLoader() {
    this(null);
  }
  public HttpGlideUrlLoader(@Nullable ModelCache<GlideUrl, GlideUrl> modelCache) {
    this.modelCache = modelCache;
  }
  @Override
  public LoadData<InputStream> buildLoadData(
      @NonNull GlideUrl model, int width, int height, @NonNull Options options) {
    // GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time
    // spent parsing urls.
    GlideUrl url = model;
    if (modelCache != null) {
      url = modelCache.get(model, 0, 0);
      if (url == null) {
        modelCache.put(model, 0, 0, model);
        url = model;
      }
    }
    int timeout = options.get(TIMEOUT);
    // 注释 26, 返回 LoadData对象,Fetcher是 HttpUrlFetcher
    return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
  }
}

上面注释 26 是返回 LoadData对象的地方,网络加载的 Fetcher实现类是 HttpUrlFetcher。下面我们就看看 HttpUrlFetcher的loadData()方法是如何从网络上加载数据的吧:

public class HttpUrlFetcher implements DataFetcher<InputStream> {
  private static final String TAG = "HttpUrlFetcher";
  private static final int MAXIMUM_REDIRECTS = 5;

  private HttpURLConnection urlConnection;
  private InputStream stream;
  private volatile boolean isCancelled;

  @Override
  public void loadData(
      @NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
    long startTime = LogTime.getLogTime();
    try {
      // 注释 27,获取输入流 InputStream 然后回调结果
      InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
      callback.onDataReady(result);
    } catch (IOException e) {
 
    } finally {
      }
    }
  }
private InputStream loadDataWithRedirects(
      URL url, int redirects, URL lastUrl, Map<String, String> headers) throws HttpException {
   ......
    // 获取 HttpURLConnection 
    urlConnection = buildAndConfigureConnection(url, headers);
    try {
      // 连接
      urlConnection.connect();
      stream = urlConnection.getInputStream();
    } catch (IOException e) {
      throw new HttpException(
          "Failed to connect or obtain data", getHttpStatusCodeOrInvalid(urlConnection), e);
    }
   ......
    final int statusCode = getHttpStatusCodeOrInvalid(urlConnection);
    if (isHttpOk(statusCode)) {
     // 返回 InputStream 
      return getStreamForSuccessfulRequest(urlConnection);
    } else if (isHttpRedirect(statusCode)) {

      }
  }

// 获取 HttpURLConnection 
 private HttpURLConnection buildAndConfigureConnection(URL url, Map<String, String> headers)
      throws HttpException {
    HttpURLConnection urlConnection;
    try {
      urlConnection = connectionFactory.build(url);
    } catch (IOException e) {
      throw new HttpException("URL.openConnection threw", /*statusCode=*/ 0, e);
    }
    for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
      urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
    }
    urlConnection.setConnectTimeout(timeout);
    urlConnection.setReadTimeout(timeout);
    urlConnection.setUseCaches(false);
    urlConnection.setDoInput(true);
    urlConnection.setInstanceFollowRedirects(false);
    return urlConnection;
  }
}

上面这个类贴出了主要方法,看注释27.这个类应该就比较简单了,创建一个 HttpURLConnection 连接,然后获取输入流再回调。

三、Glide的一些常见用法
  • 设置加载尺寸
   Glide.with(this)
                .load(url)
                // 设置宽高
                .override(800, 800)
                .into(glideImage);

  • 设置加载过程中及加载错误时现实的图片
  Glide.with(this)
                .load(url)
                // 加载中显示的图片
                .placeholder(R.mipmap.ic_launcher)
                // 加载错误后显示的图片
                .error(R.mipmap.ic_launcher)
                .into(glideImage);

  • 显示缩略图
Glide.with(this)
                .load(url)
                // 显示缩略图
                .thumbnail(0.1f)
                .into(glideImage);

  • 静态图和动态图
 Glide.with(this)
                // 静态图
                .asBitmap()
                .load(url)
                .into(glideImage);

  Glide.with(this)
                // 动态图
                .asGif()
                .load(url)
                .into(glideImage);

  • 图片显示样式
  Glide.with(this)
                .load(url)
                // 裁剪图片将imageView填满
                .centerCrop()
                .into(glideImage);

    Glide.with(this)
                .load(url)
                // 将图像全显示出来
                .fitCenter()
                .into(glideImage);

  • 处理一下图片再显示
 Glide.with(this)
                .load(url)
                .into(new CustomTarget<Drawable>() {
                    @Override
                    public void onResourceReady(@NonNull @org.jetbrains.annotations.NotNull Drawable resource, @Nullable @org.jetbrains.annotations.Nullable Transition<? super Drawable> transition) {
                        // 处理一下 resource 再显示
                        glideImage.setImageDrawable(resource);
                    }
                    @Override
                    public void onLoadCleared(@Nullable @org.jetbrains.annotations.Nullable Drawable placeholder) {

                    }
                });

  • 磁盘缓存设置
 Glide.with(this)
                .load(url)
                // 设置磁盘缓存策略
                // DiskCacheStrategy.NONE:不缓存任何图片,即禁用磁盘缓存
                // DiskCacheStrategy.ALL :缓存原始图片 & 转换后的图片(默认)
                // DiskCacheStrategy.SOURCE:只缓存原始图片(原来的全分辨率的图像,即不缓存转换后的图片)
                // DiskCacheStrategy.RESULT:只缓存转换后的图片(即最终的图像:降低分辨率后 / 或者转换后 ,不缓存原始图片
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .into(glideImage);

  • 设置是否跳过内存缓存
 Glide.with(this)
                .load(url)
                // 设置是否跳过内存缓存
                .skipMemoryCache(true)
                .into(glideImage);

  • 清理缓存
        Glide.get(this).clearDiskCache();//清理磁盘缓存 需要在子线程中执行 
        Glide.get(this).clearMemory();//清理内存缓存 可以在UI主线程中进行

  • 设置下载优先级
Glide.with(this)
                .load(url)
                // 设置下载优先级
                .priority(Priority.NORMAL)
                .into(glideImage);

  • 变换
 Glide.with(this)
                .load(url)
                // 变换
                .transform(new MultiTransformation<>())
                .into(glideImage);

相关文章

网友评论

      本文标题:Glide开源库源码分析及基本用法

      本文链接:https://www.haomeiwen.com/subject/wclymltx.html