Glide源码分析-下载图片

Glide:提供了一些列静态方法(with)用来获取RequestManager,并维护了Engine、BitmapPool、DiskCache、MemoryCache这几个类。Glide实现了ComponentCallbacks2接口,当内存不足时,会调用trimMemory方法,
在这个方法里,调用ArrayPool、BitmapPool、MemoryCache的trimMemory(level),减少缓存大小。

MemoryCache:将资源添加到内存或者从内存移除资源,实现类是LruResourceCache。

BitmapPool:Bitmap重用池,HONEYCOMB以上版本,实现类是LruBitmapPool,以下版本实现类是BitmapPoolAdapter。

ArrayPool:数组池的接口,用于存储不同类型的数组,实现类是LruArrayPool,一个固定大小的数组,数组使用LRU淘汰池策略保持池的最大字节大小下。

Engine:负责启动下载和管理活动、缓存资源。Engine类维护了EngineJob的集合,EngineKeyFactory、EngineJobFactory、DecodeJobFactory。

EngineJob:通过添加和移除回调的方式来管理下载。

EngineKeyFactory:生成EngineKey。

EngineJobFactory:Engine的静态内部类。用来创建EngineJob。

DecodeJob:解码从缓存或网络获取的资源。

DecodeHelper:解码帮助类,用来获取对应的ModelLoader,获取LoadData。

LoadData:包含了一组Key对应的确定的资源,如果缓存里没有资源,会通过DataFetcher获取。

DecodeJobFactory:Engine的静态内部类。用来生成DecodeJob。

HttpUrlFetcher:通过url从网络下载图片。

ModelLoader:工厂接口,用来将任意复杂的数据模型转化为具体的数据类型,可以使用一个DataFetcher获取数据资源为代表的模型。

Registry:管理组件注册。

HttpGlideUrlLoader:ModelLoader的实现类,将URL转化成Data(InputStream)。

Request:为Target下载资源。实现类为SingleRequest。

Target:Glide可以加载资源到Target实现类持有的ImageView等实例。继承了LifecycleListener,在加载的过程中,可以通知相关生命周期。

BaseTarget:加载资源的一个抽象基类,实现了基本方法 或 空实现。持有Request实例。

DiskCacheStrategy:硬盘缓存策略。

DataFetcherGenerator:用来注册到ModelLoaders。
DataCacheGenerator:实现DataFetcherGenerator接口,startNext方法中ModelLoader为ByteBufferFileLoader,DataFetcher为ByteBufferFetcher。

当调用Glide.with()方法时,在RequestManagerRetriever.supportFragmentGet中调用Glide.get(Context context)方法,可以获取Glide单例。

public static Glide get(Context context) {
    if (glide == null) {
      synchronized (Glide.class) {
        if (glide == null) {
        //先检查AndroidManifest.xml中是否有自己的配置,实现GlideModule接口,
        //如果有调用applyOptions的,设置自己的配置
          Context applicationContext = context.getApplicationContext();
          List modules = new ManifestParser(applicationContext).parse();

          GlideBuilder builder = new GlideBuilder(applicationContext);
          for (GlideModule module : modules) {
            module.applyOptions(applicationContext, builder);
          }
          //通过GlideBuilder创建Glide,在createGlide方法中,初始化线程池、各种缓存的类、Engine,
          //并用这些参数,新建Glide实例。
          glide = builder.createGlide();
          for (GlideModule module : modules) {
            module.registerComponents(applicationContext, glide.registry);
          }
        }
      }
    }
在Glide构造方法中,根据数据Class类型将编解码的类注册到registry中。
registry.register(ByteBuffer.class, new ByteBufferEncoder())
        .register(InputStream.class, new StreamEncoder(arrayPool))
......
初始化GlideContext。
glideContext = new GlideContext(context, registry, imageViewTargetFactory,
            defaultRequestOptions, engine, this, logLevel);

RequestManager.load方法的作用主要是根据ResourceType(这里是Drawable.class)新建RequestBuilder,并将url设置给RequestBuilder.model。
随后调用into(ImageView view)方法,设置需要展示图片的ImageView,并根据ResourceType,创建对应类型的Traget,这里是DrawableImageViewTarget。
构建好Target之后,调用into(Target target)方法,开启一个请求。

public > Y into(@NonNull Y target) {
    Util.assertMainThread();
    Preconditions.checkNotNull(target);
    if (!isModelSet) {
      throw new IllegalArgumentException("You must call #load() before calling #into()");
    }
    //从target获取request,如果不为null,先清除当前的request,
    //做的主要操作就是从RequestTracker.requests里移除request,
    //并调用Request的recycle方法,将request的数据(回调、等)置为null。
    //移除成功以后,将Target从TargetTracker.targets里移除,并将Target的request置为null。

    Request previous = target.getRequest();

    if (previous != null) {
      requestManager.clear(target);
    }

    requestOptions.lock();
    //为Target构建一个Request实例(实现类为SingleRequest).
    Request request = buildRequest(target);
    target.setRequest(request);//给target设置tag。
    //将target添加到TargetTracker.targets集合里,
    //将request添加到RequestTracker.requests集合里,并调用SingleRequest的begin方法,开始一个请求
    requestManager.track(target, request);

    return target;
  }

在SingleRequest的begin方法中,如果overrideWidth和overrideHeight不是有效值,先通过target.getSize(this)获取图片的尺寸。

ViewTarget#getSize
void getSize(SizeReadyCallback cb) {
      int currentWidth = getViewWidthOrParam();
      int currentHeight = getViewHeightOrParam();
      if (isSizeValid(currentWidth) && isSizeValid(currentHeight)) {
        int paddingAdjustedWidth = currentWidth == WindowManager.LayoutParams.WRAP_CONTENT
            ? currentWidth
            : currentWidth - ViewCompat.getPaddingStart(view) - ViewCompat.getPaddingEnd(view);
        int paddingAdjustedHeight = currentHeight == LayoutParams.WRAP_CONTENT
            ? currentHeight
            : currentHeight - view.getPaddingTop() - view.getPaddingBottom();
        //获取到view尺寸后,回调SingleRequest的onSizeReady方法,这个方法中,调用Engine.load方法, 开启一个下载任务。

        cb.onSizeReady(paddingAdjustedWidth, paddingAdjustedHeight);
      } else {
        // We want to notify callbacks in the order they were added and we only expect one or two
        // callbacks to
        // be added a time, so a List is a reasonable choice.
        if (!cbs.contains(cb)) {
          cbs.add(cb);
        }
        if (layoutListener == null) {
          final ViewTreeObserver observer = view.getViewTreeObserver();
          layoutListener = new SizeDeterminerLayoutListener(this);
          observer.addOnPreDrawListener(layoutListener);
        }
      }
    }

在这里也get了一个获取view尺寸的新方法,

private int getSizeForParam(int param, boolean isHeight) {
      if (param == LayoutParams.WRAP_CONTENT) {
        Point displayDimens = getDisplayDimens();
        return isHeight ? displayDimens.y : displayDimens.x;
      } else {
        return param;
      }
    }

private Point getDisplayDimens() {
      if (displayDimens != null) {
        return displayDimens;
      }
      WindowManager windowManager =
          (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE);
      Display display = windowManager.getDefaultDisplay();
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
        displayDimens = new Point();
        display.getSize(displayDimens);
      } else {
        displayDimens = new Point(display.getWidth(), display.getHeight());
      }
      return displayDimens;
    }

Engine.load方法

根据URL路径、图片尺寸等参数生成key以后,首先从内存缓存和弱引用里查找资源,如果不存在,进入下载流程。
......
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
        resourceClass, transcodeClass, options);
......
EngineResource cached = loadFromCache(key, isMemoryCacheable);
......
EngineResource active = loadFromActiveResources(key, isMemoryCacheable);
......
//生成EngineJob 和 DecodeJob
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable,
        useUnlimitedSourceExecutorPool);
DecodeJob decodeJob = decodeJobFactory.build(
        glideContext,
        model,
        key,
        signature,
        width,
        height,
        resourceClass,
        transcodeClass,
        priority,
        diskCacheStrategy,
        transformations,
        isTransformationRequired,
        onlyRetrieveFromCache,
        options,
        engineJob);
    jobs.put(key, engineJob);
    engineJob.addCallback(cb);//cb是SingleRequest
    engineJob.start(decodeJob);
EngineJob#public void start(DecodeJob decodeJob) {
//首先根据是否从缓存中解码,来选择对应的线程池,开启任务,执行decodeJob的run方法。
//decodeJob.willDecodeFromCache()返回true,请见下面方法解析。
    this.decodeJob = decodeJob;
    GlideExecutor executor = decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
    Log.i(TAG,"executor.class = "+decodeJob.willDecodeFromCache());
    executor.execute(decodeJob);
  }

DecodeJob.run()中runWrapped方法,会根据RunReason的改变,生成不同的操作类,比如从缓存查找,从网络下载等,进行不同的操作,

private void runWrapped() {
     switch (runReason) {
      case INITIALIZE:
      //此时的stage = RESOURCE_CACHE。currentGenerator 为 ResourceCacheGenerator

        stage = getNextStage(Stage.INITIALIZE);
        currentGenerator = getNextGenerator();
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE:

        runGenerators();
        break;
      case DECODE_DATA:
        decodeFromRetrievedData();
        break;
      default:
        throw new IllegalStateException("Unrecognized run reason: " + runReason);
    }
  }
/**
   * 1.第一次调用,返回的stage为RESOURCE_CACHE, currentGenerator是ResourceCacheGenerator,调用startNext方法,返回false
   * 2.继续调用getNextStage(stage)方法,此时,返回的stage为DATA_CACHE,currentGenerator为DataCacheGenerator,调用startNext方法从硬盘缓存查找,如果没有缓存,返回false。
   * 3.继续调用getNextStage(stage)方法,返回stage为Stage.SOURCE。currentGenerator为SourceGenerator,调用reschedule()方法,
   * 将runReason 置为 RunReason.SWITCH_TO_SOURCE_SERVICE;调用EngineJob.reschedule方法,在这个方法中,又会通过线程池,调用DecodeJob的run方法。
   * 5.此时的currentGenerator 为 SourceGenerator,在startNext方法中,通过HttpUrlFetcher.loadData方法从网络获取图片,回调SourceGenerator的onDataReady方法,
   * 将Inputstream流数据赋值给SourceGenerator.dataToCache,并调用DecodeJob.reschedule方法,EngineJob.reschedule,又回到DecodeJob的getNextStage方法,此时返回stage为FINISHED
   *再次调用SourceGenerator的startNext方法,将数据缓存到硬盘,调用DataCacheGenerator.startNext方法,调用onDataReady,这个方法里又调用SourceGenerator的onDataFetcherReady
   * 然后到DecodeJob.onDataFetcherReady,将runReason 置为 RunReason.DECODE_DATA;终于来到decodeFromRetrievedData()这个方法了。
   * 6.decodeFromRetrievedData()将数据解析成BitmapDrawable,在notifyEncodeAndRelease方法中调用notifyComplete,调用EngineJob的onResourceReady方法,在这个方法里
   * 经过Engine.onEngineJobComplete--cb(SingleRequest).onResourceReady(engineResource, dataSource)--onResourceReady----target.onResourceReady(result, animation)
   * 给view设置资源。
   *
   */
private void runGenerators() {
    currentThread = Thread.currentThread();
    startFetchTime = LogTime.getLogTime();
    boolean isStarted = false;
    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.
  }

你可能感兴趣的:(Android)