美文网首页
Glide源码顺藤摸瓜之into主线

Glide源码顺藤摸瓜之into主线

作者: 天上飘的是浮云 | 来源:发表于2021-11-30 08:44 被阅读0次

前言:上文《Glide源码顺藤摸瓜之with和load主线》,已经撸过了Glide的with和load主线,主要有生命周期方法的绑定、监听、分发和回调。这篇主要摸一摸into主线。

一、Glide的into主线关键类:

这条主线是Glide的重中之重:在这条主线里包括了Glide的核心功能:切换子线程去请求数据、它的缓存处理机制以及获取图片的stream后,切换为主线程转为为对应的格式交由ImageView显示。

    1. RequestManager:老生常谈,用来管理和start Glide请求的类。它根据绑定额生命周期的回调事件,自动的暂停、开始或者重启请求。
    1. RequestBuilder:
    1. DrawableImageViewTarget:继承至ImageViewTarget,它是最终请求成功返回后,将Drawable渲染到ImageView的Target
  @Override
  protected void setResource(@Nullable Drawable resource) {
    view.setImageDrawable(resource);
  }
    1. BitmapImageViewTarget:同DrawableImageViewTarget只不过它是BitMap类型
  @Override
  protected void setResource(Bitmap resource) {
    view.setImageBitmap(resource);
  }
    1. SingleRequest:它是一个图片资源请求
    1. TargetTracker:用来管理Target类似DrawableImageViewTarget和BitmapImageViewTarget,在生命周期回调中的加载动画的启停,因为它也监听了生命周期方法。由RequestManager回调它。
RequestManager.java
  @Override
  public synchronized void onStart() {
    resumeRequests();
    targetTracker.onStart();
  }

TargetTracker.java
  @Override
  public void onStart() {
    for (Target<?> target : Util.getSnapshot(targets)) {
      target.onStart();
    }
  }

ImageViewTarget.java
  @Override
  public void onStart() {
    if (animatable != null) {
      animatable.start();
    }
  }
    1. RequestTracker:它用来管理Request队列,根据生命周期的回调取消、重启请求。
    1. Engine:负责启动加载和管理活动缓存和内存缓存的资源。
    1. ActiveResources:活动缓存
    1. LruResourceCache:继承至LruCache,利用trimMemory()函数实现对应用内存监控,根据内存消耗程度,适时释放资源。
    1. LruCache:内存缓存,利用Lru算法,最近使用算法。来管理内存缓存,它实际是使用LikedHashMap实现。
    1. EngineJob:其实它并不是一个Runnable或者线程啥的,它实现了DecodeJob.Callback回调方法,用来管理DecodeJob执行完请求后的回调,并回调给最外层。
    1. DecodeJob:首先它继承至Runnable,

二、Glide的into主线的源码跟踪:

    1. 点击进入into方法,它其实是进入了另一个into重载方法里。

这里还需要注意的是:

glideContext.buildImageViewTarget(view, transcodeClass)方法,它返回的DrawableImageViewTarget对象实例(如代码块中的2和3),它将负责请求图片资源数据回来后渲染设置到ImageView中。

另外需要注意的是Executors.mainThreadExecutor(),它是用来切换回主线程的,同OKHttp也是通过Handler(Looper.getMainLooper)切换回主线程。

public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
    Util.assertMainThread();
    ...

    return into(
        glideContext.buildImageViewTarget(view, transcodeClass),
        /*targetListener=*/ null,
        requestOptions,
        Executors.mainThreadExecutor());
  }


2. GlideContext.java
  public <X> ViewTarget<ImageView, X> buildImageViewTarget(
      @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
    return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
  }


3. ImageViewTargetFactory.java
  public <Z> ViewTarget<ImageView, Z> buildTarget(...) {
    if (Bitmap.class.equals(clazz)) {
      return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
    } else if (Drawable.class.isAssignableFrom(clazz)) {
      return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
    } else {
     ...
    }
  }

4. Executor.java
  private static final Executor MAIN_THREAD_EXECUTOR =
      new Executor() {
        private final Handler handler = new Handler(Looper.getMainLooper());

        @Override
        public void execute(@NonNull Runnable command) {
          handler.post(command);
        }
      };

    1. 进入到into重载方法中,我们需要聚焦的是:

buildRequest()方法:它最终返回的是一个SingleRequest对象

target.setRequest(request)方法: target根据上面实际是DrawableImageViewTarget对象,setRequest在它的父类ViewTarget,实际就是给View.setTag()设置Tag而已。

最重要的是requestManager.track(target, request),这又跑到RequestManager家里去了。下面继续跟踪

  private <Y extends Target<TranscodeType>> Y into(...) {
    Preconditions.checkNotNull(target);
    

    Request request = buildRequest(target, targetListener, options, callbackExecutor);

    requestManager.clear(target);
    target.setRequest(request);
    requestManager.track(target, request);

    return target;
  }
    1. 跟踪requestManager.track(target, request)进入到RequestManager的track方法中。
      targetTracker是用来管理Target在生命周期回调中的开启、暂停等(实际是加载动画的开启和暂停等)。
  synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
  }

    1. 而requestTracker.runRequest()会将请求加入requests队列中,并开始执行request的begin()方法,在RequestTracker类中又两个队列,requests和pendingRequests。他们俩根据生命周期回调相互管理着request的启停。这里具体后面在细讲。
RequestTracker.java
  public void runRequest(@NonNull Request request) {
    requests.add(request);
    if (!isPaused) {
      request.begin();
    } else {
      request.clear();
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Paused, delaying request");
      }
      pendingRequests.add(request);
    }
  }

    1. request.begin();因为我们前面之后request就是SingleRequest了。这里最重要的就是onSizeReady()方法了。
  public void begin() {
      ...
      if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
        onSizeReady(overrideWidth, overrideHeight);
      } else {
      }
      ...
    }
  }
    1. 在onSizeReady方法中,调用了engin.load()。467行需要注意一下,它传入this作为engin的回调方法,实际上就是SingleRequest自己。
SingleRequest.java
public void onSizeReady(int width, int height) {
    ...
      loadStatus =
          engine.load(
              glideContext,
              model,
              requestOptions.getSignature(),
              this.width,
              this.height,
              requestOptions.getResourceClass(),
              transcodeClass,
              priority,
              requestOptions.getDiskCacheStrategy(),
              requestOptions.getTransformations(),
              requestOptions.isTransformationRequired(),
              requestOptions.isScaleOnlyOrNoTransform(),
              requestOptions.getOptions(),
              requestOptions.isMemoryCacheable(),
              requestOptions.getUseUnlimitedSourceGeneratorsPool(),
              requestOptions.getUseAnimationPool(),
              requestOptions.getOnlyRetrieveFromCache(),
467行              this,  这里得注意回调方法就是SingleRequst自己
              callbackExecutor);
        ...
    }
  }
    1. 在Engine的load方法中,它将使用设置的图片信息生成一个Key,然后通过这个Key去活动缓存和内存缓存中去获取缓存,如果有就返回,没有的话就调用了waitForExistingOrStartNewJob()方法。
Engine.java
  public <R> LoadStatus load(...) {
    

    EngineKey key =
        keyFactory.buildKey(
            model,
            signature,
            width,
            height,
            transformations,
            resourceClass,
            transcodeClass,
            options);

    EngineResource<?> memoryResource;
    synchronized (this) {
      memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);

      if (memoryResource == null) {
        return waitForExistingOrStartNewJob(
            glideContext,
            ...
            startTime);
      }
    }
    ...
  }

这里生成Key的话,进入到EventKey中,主要是对设置的属性进行hashCode值的拼接

EventKey.java

 public int hashCode() {
    if (hashCode == 0) {
      hashCode = model.hashCode();
      hashCode = 31 * hashCode + signature.hashCode();
      hashCode = 31 * hashCode + width;
      hashCode = 31 * hashCode + height;
      hashCode = 31 * hashCode + transformations.hashCode();
      hashCode = 31 * hashCode + resourceClass.hashCode();
      hashCode = 31 * hashCode + transcodeClass.hashCode();
      hashCode = 31 * hashCode + options.hashCode();
    }
    return hashCode;
  }
    1. 从缓存中获取数据,如果获取到了就将缓存资源回调给SingleRequest。它将先从活动缓存中取,取不到再去内存缓存中获取。

这里活动缓存ActiveResources:内部使用一个Map缓存这资源弱引用,Map<Key, ResourceWeakReference> activeEngineResources;

而若是没有从活动缓存中获取数据,则会去内存缓存中获取,如果找到会直接从内存缓存中移除掉,并存入活动缓存中。cache.remove(key) > activeResources.activate(key, cached)

Engine.java
  private EngineResource<?> loadFromMemory(
      EngineKey key, boolean isMemoryCacheable, long startTime) {
    EngineResource<?> active = loadFromActiveResources(key);
    if (active != null) {
      return active;
    }

    EngineResource<?> cached = loadFromCache(key);
    if (cached != null) {
      return cached;
    }

    return null;
  }

  private EngineResource<?> loadFromActiveResources(Key key) {
    EngineResource<?> active = activeResources.get(key);
    if (active != null) {
      active.acquire();
    }

    return active;
  }

  private EngineResource<?> loadFromCache(Key key) {
    EngineResource<?> cached = getEngineResourceFromCache(key);
    if (cached != null) {
      cached.acquire();
      activeResources.activate(key, cached);
    }
    return cached;
  }
    1. 若缓存中都没有的话,就会调用waitForExistingOrStartNewJob()方法。在这里面将会执行EnginJob.start(DecodeJob),也就是在线程池中执行DecodeJob,executor.execute(decodeJob)
  private <R> LoadStatus waitForExistingOrStartNewJob(...) {

    EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);

    EngineJob<R> engineJob =
        engineJobFactory.build(
            key,
            ...
            onlyRetrieveFromCache);

    DecodeJob<R> decodeJob =
        decodeJobFactory.build(
            glideContext,
            ...
            engineJob);

    engineJob.addCallback(cb, callbackExecutor);
    engineJob.start(decodeJob);
  }
    1. 在EngineJob中直接通过GlideExecutor来执行DecodeJob
EngineJob.java
  public synchronized void start(DecodeJob<R> decodeJob) {
    this.decodeJob = decodeJob;
    GlideExecutor executor =
        decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
    executor.execute(decodeJob);
  }

三、Glide进入硬盘缓存和开始网络请求

3.1 前边跟踪到了EngineJob.start(),然后GlideExecutor.execute(decodeJob)执行了DecodeJob。而DecodeJob其实就是个Runnable,我们看看run()方法。
public void run() {
      ...
      runWrapped();
      ...
}

  private void runWrapped() {
    switch (runReason) {
      case INITIALIZE:
        stage = getNextStage(Stage.INITIALIZE);
        currentGenerator = getNextGenerator();
        runGenerators();
        break;
    }
  }
3.2 进入到runWrapped()方法中,然后会进入到INITIALIZE项中,可以看到getNextGenerator()方法和runGenerators()方法。

getNextGenerator()方法其实是根据stage获得当前的Generator,然后通过runGenerators()执行generator.starNext()方法。

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

  private void runGenerators() {
    ...
    while (!isCancelled
        && currentGenerator != null
        && !(isStarted = currentGenerator.startNext())) {
      stage = getNextStage(stage);
      currentGenerator = getNextGenerator();

     ...
    }
 
  }
3.3 其实这一步应该到了getNextGenerator()方法中,但是在这之前,我们应该提一下,再回顾一下Glide实例创建的时候做的事情,这对于下面分析getNextGenerator()方法很有帮助。

可以看到在实例化Glide对象的时候,它采用注册机的方式,将很多Decode解码器,Encode解码器,Transcoder转码器,Loader加载器,注册到了Register中,相当于把各种配方储存好,以便日后查找。每一条数据包括了输入的类型、输出类型和相匹配的各种Decode解码器,Encode解码器,Transcoder转码器,Loader加载器。
为后面在进行数据加载转换的时候找到相对应的工具,提供类似数据库的作用。

    Glide(...) {
        ...

        registry = new Registry();
        registry.register(new DefaultImageHeaderParser());
        
        ...

        registry.append(Bitmap.class, Bitmap.class, UnitModelLoader.Factory.<Bitmap>getInstance())
        .append(GifDrawable.class, new GifDrawableEncoder())
                /* GIF Frames */
                // Compilation with Gradle requires the type to be specified for UnitModelLoader here.
                .append(
                        GifDecoder.class, GifDecoder.class, UnitModelLoader.Factory.<GifDecoder>getInstance())

        /* Files */
        .register(new ByteBufferRewinder.Factory())
                .append(File.class, ByteBuffer.class, new ByteBufferFileLoader.Factory())
        .append(File.class, InputStream.class, new FileLoader.StreamFactory())

        .append(Uri.class, InputStream.class, new DataUrlLoader.StreamFactory<Uri>())
        .append(String.class, InputStream.class, new StringLoader.StreamFactory())
        .append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())
        .append(
                String.class, AssetFileDescriptor.class, new StringLoader.AssetFileDescriptorFactory())
        .append(Uri.class, InputStream.class, new HttpUriLoader.Factory())
        .append(Uri.class, InputStream.class, new AssetUriLoader.StreamFactory(context.getAssets()))
        .append(
                Uri.class,
                        ParcelFileDescriptor.class,
        new AssetUriLoader.FileDescriptorFactory(context.getAssets()))
        .append(Uri.class, InputStream.class, new MediaStoreImageThumbLoader.Factory(context))
        .append(Uri.class, InputStream.class, new UrlUriLoader.StreamFactory())
        .append(URL.class, InputStream.class, new UrlLoader.StreamFactory())
        .append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())
        .register(Bitmap.class, byte[].class, bitmapBytesTranscoder)
                .register(
                        Drawable.class,
                                byte[].class,
                                new DrawableBytesTranscoder(
                                bitmapPool, bitmapBytesTranscoder, gifDrawableBytesTranscoder))
                .register(GifDrawable.class, byte[].class, gifDrawableBytesTranscoder);
        ...
    }
3.4 在getNextGenerator()方法中,我们可以看到有三种Generator。

它前面两个其实是一个一个Genertaor寻找缓存,找到了就返回,没找到就到最后一个SourceGenerator开始进行网络请求 了。

  • ResourceCacheGenerator:它是磁盘中获取,不过它是已经被处理过尺寸、宽高或者说裁剪采样转换过的磁盘缓存资源。
  • DataCacheGenerator:它是从磁盘中获取数据,磁盘中使用的是Lru最近使用算法储存。它不同于ResourceCacheGenerator,它是未经处理的原始资源数据。
  • SourceGenerator:如果前面两种磁盘缓存都没有数据的话,它将执行网络请求,然后将请求的资源数据缓存到磁盘中。
3.5 下面依次看到它们的startNext()方法

ResourceCacheGenerator.startNext()

ResourceCacheGenerator.java

    @Override
    public boolean startNext() {

        while (modelLoaders == null || !hasNextModelLoader()) {
            ...
1.            currentKey =
                    new ResourceCacheKey( // NOPMD AvoidInstantiatingObjectsInLoops
                            // helper.getArrayPool(),
            sourceId,
            helper.getSignature(),
            helper.getWidth(),
            helper.getHeight(),
            transformation,
            resourceClass,
            helper.getOptions());

2.            cacheFile = helper.getDiskCache().get(currentKey);

            if (cacheFile != null) {
                sourceKey = sourceId;
                modelLoaders = helper.getModelLoaders(cacheFile);
                modelLoaderIndex = 0;
            }
        }

        boolean started = false;
        while (!started && hasNextModelLoader()) {
            ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
3.            loadData =
                    modelLoader.buildLoadData(
                            cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
            if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
                started = true;
 4.               loadData.fetcher.loadData(helper.getPriority(), this);
            }
        }

        return started;
    }

代码精简了下,大家可以自行跟踪下,看到代码中标出的1、2、3、4点,咱们来一一分析下:

  • 第1点:通过各种参数如:sourceId(实际就是我们最开始传入的图片连接url、文件路径等等)、签名、宽高、转码方式等等。来生成一个ResourceCacheKey。
  • 第2点:通过helper.getDiskCache().get()方法,通过key来查找是否有缓存的资源,这里的getDiskCache()实际返回的是DiskLruCacheWrapper对象。而它的DiskLruCacheWrapper.get()方法中getDiskCache()返回的就是DiskLruCache对象,它使用LinkHashMap结构来实现Lru算法。
DiskLruCacheWrapper.java
  @Override
  public File get(Key key) {
    String safeKey = safeKeyGenerator.getSafeKey(key);
    try {
      final DiskLruCache.Value value = getDiskCache().get(safeKey);
      if (value != null) {
        result = value.getFile(0);
      }
    } catch (IOException e) {
    }
    return result;
  }

  private synchronized DiskLruCache getDiskCache() throws IOException {
    if (diskLruCache == null) {
      diskLruCache = DiskLruCache.open(directory, APP_VERSION, VALUE_COUNT, maxSize);
    }
    return diskLruCache;
  }
  • 第3点:首先modelLoader实际上就是我们上面讲到创建Glide实例时注册机方式里取出的加载器。如我们这里传入的时File类型,那么就会去找File.class类型的Loader加载器。


    File.class类型的加载器

这里有四种,而这四种如果需要找到具体的加载器,那么还要根据第二个参数类型,也就是输入类型。这里分析下ByteBufferFileLoader.Factory,它的build()方法会返回一个ByteBufferFileLoader对象,其实这就是工厂模式啦~

通过调用ByteBufferFileLoader.buildLoadData()方法会返回一个LoadData实例。而这个LoadData实例有两个参数,第一个是Key,第二是一个DataFetcher的实现类。这里是ByteBufferFetcher。

public class ByteBufferFileLoader implements ModelLoader<File, ByteBuffer> {

  @Override
  public LoadData<ByteBuffer> buildLoadData(
      @NonNull File file, int width, int height, @NonNull Options options) {
    return new LoadData<>(new ObjectKey(file), new ByteBufferFetcher(file));
  }

  public static class Factory implements ModelLoaderFactory<File, ByteBuffer> {

    public ModelLoader<File, ByteBuffer> build(@NonNull MultiModelLoaderFactory multiFactory) {
      return new ByteBufferFileLoader();
    }
  }
}
  • 第4点: loadData.fetcher.loadData(),它实际就是调用通过第3点中返回的LoadData里的Fetcher对象的loadData()方法。这里接着第3点的分析的话,就是ByteBufferFetcher.loadData()方法。它就是将缓存文件转成ByteBuffer类型然后回调给前台。
    public void loadData(
        @NonNull Priority priority, @NonNull DataCallback<? super ByteBuffer> callback) {
      ByteBuffer result;
      try {
        result = ByteBufferUtil.fromFile(file);
      } catch (IOException e) {
      
        callback.onLoadFailed(e);
        return;
      }

      callback.onDataReady(result);
    }
3.5 如果ResourceCacheGenerator没有找到缓存数据的话,就会接着去DataCacheGenerator里的startNext()方法找缓存数据。
DataCacheGenerator.java
  public boolean startNext() {
    while (modelLoaders == null || !hasNextModelLoader()) {
  
1.      Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
2.       cacheFile = helper.getDiskCache().get(originalKey);
      if (cacheFile != null) {
        this.sourceKey = sourceId;
        modelLoaders = helper.getModelLoaders(cacheFile);
        modelLoaderIndex = 0;
      }
    }

    boolean started = false;
    while (!started && hasNextModelLoader()) {
      ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
3.      loadData =
          modelLoader.buildLoadData(
              cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
      if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
        started = true;
4.        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }

这里的1、2、3、4点其实和上面的ResourceCacheGenerator里的一致,只不过它的cacheKey不一样,Key originalKey = new DataCacheKey(sourceId, helper.getSignature());它是一个DataCacheKey,我们也可以看到这里生成Key,就不想ResourceCacheGenerator有很多参数了。这里就两个参数,sourceId是指我们调用Glide加载图片时传入的uri或者文件路径啥的,还有签名。这也可以验证这里就是去寻找原始未经处理的缓存资源。

3.7 如果前面两个Generator都没有在磁盘找到缓存资源,那么就会去最后一个终极大Boss-->SourceGenerator.startNext()方法中处理了。
SourceGenerator.java
  @Override
  public boolean startNext() {
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
1.      cacheData(data);
    }

     startNextLoad(loadData);
    }
    return started;
  }

  private void startNextLoad(final LoadData<?> toStart) {
  2.   loadData.fetcher.loadData(
        helper.getPriority(),
        new DataCallback<Object>() {... });
  }
    1. 有缓存的话就直接取缓存数据了
    1. 没有缓存的话,那么就依旧原来模式loadData.fetcher.loadData()。只不过这里的fetcher是HttpUrlFetcher,这里的loadData由HttpGlideUrlLoader生成。我们看看路径:
1. Glide.java
547行 .append(GlideUrl.class, InputStream.class, new HttpGlideUrlLoader.Factory())

2. HttpGliderUrlLoader.java
  public LoadData<InputStream> buildLoadData(...) {
    return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
  }

public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {
    public ModelLoader<GlideUrl, InputStream> build(MultiModelLoaderFactory multiFactory) {
      return new HttpGlideUrlLoader(modelCache);
    }
  }
3.8 基于前面,进入到HttpUrlFetcher.java中看看loadData方法
HttpUrlFetcher.java
  public void loadData(
      @NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
    ...
      InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
     ...
  }

进入到loadDataWithRedirects()方法中:

   private InputStream loadDataWithRedirects(...) throws IOException {
        ...

        urlConnection = connectionFactory.build(url);
        ...
        
        urlConnection.connect();
1.     stream = urlConnection.getInputStream();
        final int statusCode = urlConnection.getResponseCode();
        if (isHttpOk(statusCode)) {
 2.           return getStreamForSuccessfulRequest(urlConnection);
        } else if (isHttpRedirect(statusCode)) {
            String redirectUrlString = urlConnection.getHeaderField("Location");
            URL redirectUrl = new URL(url, redirectUrlString);
 3.           return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
        } else if (statusCode == INVALID_STATUS_CODE) {
            throw new HttpException(statusCode);
        } else {
            throw new HttpException(urlConnection.getResponseMessage(), statusCode);
        }
    }
    1. 它是使用HttpURLConnection来请求资源数据的。
    1. 如果请求成功了调用getStreamForSuccessfulRequest()方法,验证数据完整性,就是对于一下数据的length: ContentLengthInputStream.obtain(urlConnection.getInputStream(), contentLength)
    1. 如果有重定向的话,则获取header中的location自动的重定向url,并重新请求。

四、获取数据后回调显示

上面我们已经跟踪到了最后通过网络请求获取资源了,接下来按照开发逻辑就是回调数据,通知上层切换线程,并展示图片了。
下面我们来分析分析(三个Generator都是一致的):

    1. HttpUrlFetcher.loadData(57行 callback.onDataReady) -->
    1. SourceGenerator.onDataReadyInternal(148行 cb.onDataFetcherReady)(这里将网络获取数据存入磁盘缓存起来) --->
    1. DecodeJob.onDataFetcherReady --->
    1. DecodeJob.decodeFromRetrievedData() --->
    1. DecodeJob.notifyEncodeAndRelease() --->
    1. DecodeJob.notifyComplete(337行 callback.onResourceReady()) --->
    1. EngineJob.onResourceReady() --->
    1. EngineJob.notifyCallbacksOfResult()(261行 entry.executor.execute(new CallResourceReady(entry.cb))) --->
    1. EngineJob.CallResourceReady.run() ---->
    1. EngineJob.callCallbackOnResourceReady()(158行 cb.onResourceReady(engineResource, dataSource)) ---->
    1. SingleRequest.onResourceReady(631行 target.onResourceReady(result, animation) target就是我们之前说得ImageViewTarget) ---->
    1. ImageViewTarget.onResourceReady() --->
    1. ImageViewTarget.setResourceInternal() --->
    1. DrawableImageViewTarget.setResource()(它是ImageViewTarget的子类)
public class DrawableImageViewTarget extends ImageViewTarget<Drawable> {
  @Override
  protected void setResource(@Nullable Drawable resource) {
    view.setImageDrawable(resource);
  }
}

回调过程就没有详细写了,跟了个路径。到最后获取的图片资源通过一层层的回调,最终到了target中,在target的setResource方法中,交由原始的view去渲染,最终图片得以显示出来。

五、遗留的问题

基于这两篇文章,我们把Glide的三条主线摸清楚了,Glide的工程确实很庞大,看的有些累,我们基于主线,一条条的跑通,那么它的主要架构其实在心里已经有谱了,现在只剩下些边角需要我们受试一波:

  • 1、Glide如何切换为子线程请求数据?
  • 2、Glide通过网络请求获取数据后怎么缓存磁盘的?
  • 3、Glide获取图片数据后如何切换为主线程渲染?
  • 4、Glide的三级缓存如何交互以及如何监控内存?
  • 5、Glide如何监控网络实现重启图片加载?
  • 6、Glide如何根据Activity生命周期开始和暂停请求?

这一篇文章篇幅够长了,所以剩下的问题,咱们下一篇Glide继续来。

相关文章

网友评论

      本文标题:Glide源码顺藤摸瓜之into主线

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