美文网首页
2019-11-19Glide 源码流程分析<2>

2019-11-19Glide 源码流程分析<2>

作者: 猫KK | 来源:发表于2019-11-19 19:26 被阅读0次

    接着上一篇来到这里

    loadData.fetcher.loadData(helper.getPriority(), this);
    

    我们已经知道了这个fetcher就是HttpUrlFetcher,所以看HttpUrlFetcher.loadData()方法

      @Override
      public void loadData(
          @NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
        long startTime = LogTime.getLogTime();
        try {
          //获取InputStream
          InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
          //获取成功回调
          callback.onDataReady(result);
        } catch (IOException e) {
          if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "Failed to load data for url", e);
          }
          //获取失败回调
          callback.onLoadFailed(e);
        } finally {
          if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
          }
        }
      }
    
      private InputStream loadDataWithRedirects(
          URL url, int redirects, URL lastUrl, Map<String, String> headers) throws IOException {
        if (redirects >= MAXIMUM_REDIRECTS) {
          throw new HttpException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
        } else {
          // 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 HttpException("In re-direct loop");
            }
          } catch (URISyntaxException e) {
            // Do nothing, this is best effort.
          }
        }
        //获取urlConnection,请求网络数据
        urlConnection = connectionFactory.build(url);
        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);
    
        // Stop the urlConnection instance of HttpUrlConnection from following redirects so that
        // redirects will be handled by recursive calls to this method, loadDataWithRedirects.
        urlConnection.setInstanceFollowRedirects(false);
    
        // Connect explicitly to avoid errors in decoders if connection fails.
        urlConnection.connect();
        // Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352.
        stream = urlConnection.getInputStream();
        if (isCancelled) {
          return null;
        }
        final int statusCode = urlConnection.getResponseCode();
        //获取成功
        if (isHttpOk(statusCode)) {
          return getStreamForSuccessfulRequest(urlConnection);
        } else if (isHttpRedirect(statusCode)) {
          String redirectUrlString = urlConnection.getHeaderField("Location");
          if (TextUtils.isEmpty(redirectUrlString)) {
            throw new HttpException("Received empty or null redirect url");
          }
          URL redirectUrl = new URL(url, redirectUrlString);
          // Closing the stream specifically is required to avoid leaking ResponseBodys in addition
          // to disconnecting the url connection below. See #2352.
          cleanup();
          return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
        } else if (statusCode == INVALID_STATUS_CODE) {
          throw new HttpException(statusCode);
        } else {
          throw new HttpException(urlConnection.getResponseMessage(), statusCode);
        }
      }
    
      private InputStream getStreamForSuccessfulRequest(HttpURLConnection urlConnection)
          throws IOException {
        //获取成功,返回InputStream
        if (TextUtils.isEmpty(urlConnection.getContentEncoding())) {
          int contentLength = urlConnection.getContentLength();
          stream = ContentLengthInputStream.obtain(urlConnection.getInputStream(), contentLength);
        } else {
          if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "Got non empty content encoding: " + urlConnection.getContentEncoding());
          }
          stream = urlConnection.getInputStream();
        }
        return stream;
      }
    

    上面很简单,就是请求网络,获取图片,获取成功后回调到SourceGenerator.onDataReady方法中

      @Override
      public void onDataReady(Object data) {
        DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
        //根据前面data不为null,diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource()为true
        if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
          //所以会进来这里
          dataToCache = data;
          //调用reschedule
          cb.reschedule();
        } else {
          cb.onDataFetcherReady(
              loadData.sourceKey,
              data,
              loadData.fetcher,
              loadData.fetcher.getDataSource(),
              originalKey);
        }
      }
    

    所以又回到DecodeJob.reschedule中

      @Override
      public void reschedule() {
        //改变runReason的值
        runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
        callback.reschedule(this);
      }
    

    callback.reschedule(this);最后又会回调到自身的run()方法中,需要注意的是runReason的值为RunReason.SWITCH_TO_SOURCE_SERVICE;

      @Override
      public void run() {
          //...
          runWrapped();
       //...
      }
    
      private void runWrapped() {
        //当前runReason为SWITCH_TO_SOURCE_SERVICE
        switch (runReason) {
          case INITIALIZE:
            stage = getNextStage(Stage.INITIALIZE);
            currentGenerator = getNextGenerator();
            runGenerators();
            break;
          case SWITCH_TO_SOURCE_SERVICE:
            //直接调用runGenerators,没有设置stage和currentGenerator
            //所以currentGenerator还是为SourceGenerator
            runGenerators();
            break;
          case DECODE_DATA:
            decodeFromRetrievedData();
            break;
          default:
            throw new IllegalStateException("Unrecognized run reason: " + runReason);
        }
      }
    
      private void runGenerators() {
        currentThread = Thread.currentThread();
        startFetchTime = LogTime.getLogTime();
        boolean isStarted = false;
        //调用startNext方法
        while (!isCancelled
            && currentGenerator != null
            && !(isStarted = currentGenerator.startNext())) {
          stage = getNextStage(stage);
          currentGenerator = getNextGenerator();
    
          if (stage == Stage.SOURCE) {
            reschedule();
            return;
          }
        }
        // We've run out of stages and generators, give up.
        if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
          notifyFailed();
        }
    
        // Otherwise a generator started a new load and we expect to be called back in
        // onDataFetcherReady.
      }
    

    因为没有从新设置currentGenerator,所以currentGenerator还是为SourceGenerator,又进到SourceGenerator.startNext()方法中

      @Override
      public boolean startNext() {
        //刚才已经对dataToCache赋值了,所以不为null
        if (dataToCache != null) {
          Object data = dataToCache;
          dataToCache = null;
          cacheData(data);
        }
    
        if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
          return true;
        }
        //....
      }
    

    看cacheData(data);方法做了什么

      private void cacheData(Object dataToCache) {
        long startTime = LogTime.getLogTime();
        try {
          Encoder<Object> encoder = helper.getSourceEncoder(dataToCache);
          DataCacheWriter<Object> writer =
              new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
          originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
          //写缓存,保存成一个文件
          helper.getDiskCache().put(originalKey, writer);
          if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(
                TAG,
                "Finished encoding source to cache"
                    + ", key: "
                    + originalKey
                    + ", data: "
                    + dataToCache
                    + ", encoder: "
                    + encoder
                    + ", duration: "
                    + LogTime.getElapsedMillis(startTime));
          }
        } finally {
          loadData.fetcher.cleanup();
        }
        //创建一个DataCacheGenerator对象,注意最后一个参数穿的是this
        sourceCacheGenerator =
            new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
      }
    

    回到startNext()方法中

      @Override
      public boolean startNext() {
        //刚才已经对dataToCache赋值了,所以不为null
        if (dataToCache != null) {
          Object data = dataToCache;
          dataToCache = null;
          cacheData(data);
        }
        //sourceCacheGenerator前面赋值了,所以进到sourceCacheGenerator.startNext()方法中
        if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
          return true;
        }
        //....
      }
    

    所以进到sourceCacheGenerator.startNext()方法中

      @Override
      public boolean startNext() {
        while (modelLoaders == null || !hasNextModelLoader()) {
          sourceIdIndex++;
          if (sourceIdIndex >= cacheKeys.size()) {
            return false;
          }
          //获取缓存的key
          Key sourceId = cacheKeys.get(sourceIdIndex);
          @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
          Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
          //获取缓存文件
          cacheFile = helper.getDiskCache().get(originalKey);
          if (cacheFile != null) {
            this.sourceKey = sourceId;
            //获取解码器,和前面一样,不过这回传的是file
            modelLoaders = helper.getModelLoaders(cacheFile);
            modelLoaderIndex = 0;
          }
        }
        //和前面的操作一样
        loadData = null;
        boolean started = false;
        while (!started && hasNextModelLoader()) {
          ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
          loadData =
              modelLoader.buildLoadData(
                  cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
          if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
            started = true;
            loadData.fetcher.loadData(helper.getPriority(), this);
          }
        }
        return started;
      }
    

    和前面的操作一样,通过一样的方法获取,不同的是传的参数是file类型,根据前面的分析可以知道最后是这个

    .append(File.class, ByteBuffer.class, new ByteBufferFileLoader.Factory())
    

    根据前面的分析

        @NonNull
        @Override
        public ModelLoader<File, ByteBuffer> build(@NonNull MultiModelLoaderFactory multiFactory) {
          return new ByteBufferFileLoader();
        }
    
    
      @Override
      public LoadData<ByteBuffer> buildLoadData(
          @NonNull File file, int width, int height, @NonNull Options options) {
        return new LoadData<>(new ObjectKey(file), new ByteBufferFetcher(file));
      }
    
      @Override
      public boolean handles(@NonNull File file) {
        return true;
      }
    

    所以会走到ByteBufferFetcher.loadData方法中

        @Override
        public void loadData(
            @NonNull Priority priority, @NonNull DataCallback<? super ByteBuffer> callback) {
          ByteBuffer result;
          try {
            //获取资源
            result = ByteBufferUtil.fromFile(file);
          } catch (IOException e) {
            if (Log.isLoggable(TAG, Log.DEBUG)) {
              Log.d(TAG, "Failed to obtain ByteBuffer for file", e);
            }
            callback.onLoadFailed(e);
            return;
          }
          //获取成功,回调出去
          callback.onDataReady(result);
        }
    

    回调回到DataCacheGenerator.onDataReady方法中

      @Override
      public void onDataReady(Object data) {
         //又通过cb回调出去,这里的cb是DataCacheGenerator
        cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);
      }
    

    所以又回到DataCacheGenerator.onDataFetcherReady中

      @Override
      public void onDataFetcherReady(
          Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
        //又通过cb回调出去,这里的cb是DecodeJob
        cb.onDataFetcherReady(sourceKey, data, fetcher, loadData.fetcher.getDataSource(), sourceKey);
      }
    

    回到DecodeJob.onDataFetcherReady()方法中

      @Override
      public void onDataFetcherReady(
          Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
        this.currentSourceKey = sourceKey;
        this.currentData = data;
        this.currentFetcher = fetcher;
        this.currentDataSource = dataSource;
        this.currentAttemptingKey = attemptedKey;
        //判断线程
        if (Thread.currentThread() != currentThread) {
          runReason = RunReason.DECODE_DATA;
          callback.reschedule(this);
        } else {
          GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
          try {
            decodeFromRetrievedData();
          } finally {
            GlideTrace.endSection();
          }
        }
      }
    
      private void decodeFromRetrievedData() {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
          logWithTimeAndKey(
              "Retrieved data",
              startFetchTime,
              "data: "
                  + currentData
                  + ", cache key: "
                  + currentSourceKey
                  + ", fetcher: "
                  + currentFetcher);
        }
        Resource<R> resource = null;
        try {
          //解码资源
          resource = decodeFromData(currentFetcher, currentData, currentDataSource);
        } catch (GlideException e) {
          e.setLoggingDetails(currentAttemptingKey, currentDataSource);
          throwables.add(e);
        }
        if (resource != null) {
          //获取成功,回调出去
          notifyEncodeAndRelease(resource, currentDataSource);
        } else {
          runGenerators();
        }
      }
    

    下面来看decodeFromData是如何工作的

      private <Data> Resource<R> decodeFromData(
          DataFetcher<?> fetcher, Data data, DataSource dataSource) throws GlideException {
          //..
          Resource<R> result = decodeFromFetcher(data, dataSource);
          //...
      }
    
      private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
          throws GlideException {
        LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
        return runLoadPath(data, dataSource, path);
      }
    
      private <Data, ResourceType> Resource<R> runLoadPath(
          Data data, DataSource dataSource, LoadPath<Data, ResourceType, R> path)
          throws GlideException {
          //...
          return path.load(
              rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
    //...
      }
    
      public Resource<Transcode> load(
          DataRewinder<Data> rewinder,
          @NonNull Options options,
          int width,
          int height,
          DecodePath.DecodeCallback<ResourceType> decodeCallback)
          throws GlideException {
        List<Throwable> throwables = Preconditions.checkNotNull(listPool.acquire());
        try {
          return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
        } finally {
          listPool.release(throwables);
        }
      }
    
      private Resource<Transcode> loadWithExceptionList(
          DataRewinder<Data> rewinder,
          @NonNull Options options,
          int width,
          int height,
          DecodePath.DecodeCallback<ResourceType> decodeCallback,
          List<Throwable> exceptions)
          throws GlideException {
            //....
            result = path.decode(rewinder, width, height, options, decodeCallback);
        //...
        return result;
      }
    
      public Resource<Transcode> decode(
          DataRewinder<DataType> rewinder,
          int width,
          int height,
          @NonNull Options options,
          DecodeCallback<ResourceType> callback)
          throws GlideException {
        Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
        Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
        return transcoder.transcode(transformed, options);
      }
    

    最后来到transcoder.transcode(transformed, options);中,其中transcoder为BitmapDrawableTranscoder对象

      @Nullable
      @Override
      public Resource<BitmapDrawable> transcode(
          @NonNull Resource<Bitmap> toTranscode, @NonNull Options options) {
        //返回一个对象
        return LazyBitmapDrawableResource.obtain(resources, toTranscode);
      }
    

    得到对象,回到前面

      private void decodeFromRetrievedData() {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
          logWithTimeAndKey(
              "Retrieved data",
              startFetchTime,
              "data: "
                  + currentData
                  + ", cache key: "
                  + currentSourceKey
                  + ", fetcher: "
                  + currentFetcher);
        }
        Resource<R> resource = null;
        try {
          //解码资源
          resource = decodeFromData(currentFetcher, currentData, currentDataSource);
        } catch (GlideException e) {
          e.setLoggingDetails(currentAttemptingKey, currentDataSource);
          throwables.add(e);
        }
        if (resource != null) {
          //获取成功,回调出去
          notifyEncodeAndRelease(resource, currentDataSource);
        } else {
          runGenerators();
        }
      }
    

    调用notifyEncodeAndRelease回调出去

      private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
        if (resource instanceof Initializable) {
          ((Initializable) resource).initialize();
        }
    
        Resource<R> result = resource;
        LockedResource<R> lockedResource = null;
        if (deferredEncodeManager.hasResourceToEncode()) {
          lockedResource = LockedResource.obtain(resource);
          result = lockedResource;
        }
        //通知已经完成
        notifyComplete(result, dataSource);
    
        stage = Stage.ENCODE;
        //....
      }
    
      private void notifyComplete(Resource<R> resource, DataSource dataSource) {
        setNotifiedOrThrow();
        //通过callback回调出去,其中callback为EngineJob对象
        callback.onResourceReady(resource, dataSource);
      }
    

    去到EngineJob.onResourceReady方法中

      @Override
      public void onResourceReady(Resource<R> resource, DataSource dataSource) {
        synchronized (this) {
          this.resource = resource;
          this.dataSource = dataSource;
        }
        notifyCallbacksOfResult();
      }
    
      void notifyCallbacksOfResult() {
        ResourceCallbacksAndExecutors copy;
        Key localKey;
        EngineResource<?> localResource;
        synchronized (this) {
          //....
          hasResource = true;
          copy = cbs.copy();
          incrementPendingCallbacks(copy.size() + 1);
    
          localKey = key;
          localResource = engineResource;
        }
    
        engineJobListener.onEngineJobComplete(this, localKey, localResource);
    
        for (final ResourceCallbackAndExecutor entry : copy) {
          //回调到CallResourceReady.run()方法中
          entry.executor.execute(new CallResourceReady(entry.cb));
        }
        decrementPendingCallbacks();
      }
    

    回调到CallResourceReady.run()方法中

        @Override
        public void run() {
          // Make sure we always acquire the request lock, then the EngineJob lock to avoid deadlock
          // (b/136032534).
          synchronized (cb.getLock()) {
            synchronized (EngineJob.this) {
              if (cbs.contains(cb)) {
                // Acquire for this particular callback.
                engineResource.acquire();
                callCallbackOnResourceReady(cb);
                removeCallback(cb);
              }
              decrementPendingCallbacks();
            }
          }
        }
    
      void callCallbackOnResourceReady(ResourceCallback cb) {
        try {
          //回调cb.onResourceReady
          cb.onResourceReady(engineResource, dataSource);
        } catch (Throwable t) {
          throw new CallbackException(t);
        }
      }
    

    其中cb是在EngineJob初始化的时候传过来了

    
        EngineJob<R> engineJob =
            engineJobFactory.build(
                key,
                isMemoryCacheable,
                useUnlimitedSourceExecutorPool,
                useAnimationPool,
                onlyRetrieveFromCache);
    
        //...
        jobs.put(key, engineJob);
        //为cb赋值
        engineJob.addCallback(cb, callbackExecutor);
        engineJob.start(decodeJob);
    
        if (VERBOSE_IS_LOGGABLE) {
          logWithTimeAndKey("Started new load", startTime, key);
        }
        return new LoadStatus(cb, engineJob);
    

    往前回溯,所以来到SingleRequest.onResourceReady方法中

      @Override
      public void onResourceReady(Resource<?> resource, DataSource dataSource) {
            //...
            onResourceReady((Resource<R>) resource, (R) received, dataSource);
           //...
      }
    
      @GuardedBy("requestLock")
      private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
        //....
            //回调到target的onResourceReady中
            target.onResourceReady(result, animation);
           //...
      }
    

    其中target就是前面说到的DrawableImageViewTarget对象

      @Override
      public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
        if (transition == null || !transition.transition(resource, this)) {
          setResourceInternal(resource);
        } else {
          maybeUpdateAnimatable(resource);
        }
      }
    
      private void setResourceInternal(@Nullable Z resource) {
        // Order matters here. Set the resource first to make sure that the Drawable has a valid and
        // non-null Callback before starting it.
        setResource(resource);
        maybeUpdateAnimatable(resource);
      }
    
      @Override
      protected void setResource(@Nullable Drawable resource) {
        view.setImageDrawable(resource);
      }
    

    最后调用setImageDrawable将图片设置上去,注意,前两个方法是在父类中的。

    相关文章

      网友评论

          本文标题:2019-11-19Glide 源码流程分析<2>

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