Glide源码——SingleRequest

在分析RequestBuilder代码的时候我们提到,在调用into()方法的最后调用了requestManager.track(target, request)方法,从这里开始才是真正的去加载图片。

synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
  targetTracker.track(target);
  requestTracker.runRequest(request);
}
public void runRequest(@NonNull Request request) {
  requests.add(request);
  if (!isPaused) {
    request.begin();
  } else {
    request.clear();
    pendingRequests.add(request); //pendingRequests的作用是给request加入强引用,使得不会被回收。
  }
}

Request是一个接口,在RequestBuilder调用into()方法中会生成Request的一个实例,常用的是SingleRequest:

public synchronized void begin() {
  stateVerifier.throwIfRecycled(); //这里用了一个辅助类来记录状态,看着像是依赖注入的写法;
  startTime = LogTime.getLogTime();
  if (model == null) {
    if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
      width = overrideWidth;
      height = overrideHeight;
    }
    // Only log at more verbose log levels if the user has set a fallback drawable, because
    // fallback Drawables indicate the user expects null models occasionally.
    int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
    onLoadFailed(new GlideException("Received null model"), logLevel);
    return;
  }
  if (status == Status.RUNNING) {
    throw new IllegalArgumentException("Cannot restart a running request");
  }
  if (status == Status.COMPLETE) { //如果一个request是完成的,那么直接回调结果,比如调用了notifyDataSetChanged,触发代码刷新;
    onResourceReady(resource, DataSource.MEMORY_CACHE);
    return;
  }

  status = Status.WAITING_FOR_SIZE;
  if (Util.isValidDimensions(overrideWidth, overrideHeight)) { //如果指定了宽高,那么直接走onSizeReady;
    onSizeReady(overrideWidth, overrideHeight);
  } else {
    target.getSize(this); //没有指定宽高,先根据target去获取宽高,有结果后回调到onSizeReady,onSizeReady是SizeReadyCallback接口的方法,SingleRequest实现了该接口;
  }

  if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
      && canNotifyStatusChanged()) {
    target.onLoadStarted(getPlaceholderDrawable()); //通知处于开始加载状态,显示占位图片;
  }
}

target有很多的实现类,这个在另一篇文章说,这里以ViewTarget为例,其getSize()方法源码:

void getSize(@NonNull SizeReadyCallback cb) {
  int currentWidth = getTargetWidth(); //获取宽的时候是获取layoutParam的宽减去padding部分,如果结果大于0则返回,否则获取view的宽减去padding部分;
  int currentHeight = getTargetHeight(); //获取高的时候是获取layoutParam的高减去padding部分,如果结果大于0则返回,否则获取view的高减去padding部分;
  if (isViewStateAndSizeValid(currentWidth, currentHeight)) {
    cb.onSizeReady(currentWidth, currentHeight);
    return;
  }

  // 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) {
    ViewTreeObserver observer = view.getViewTreeObserver();
    layoutListener = new SizeDeterminerLayoutListener(this);
    observer.addOnPreDrawListener(layoutListener);
  }
}

即如果可以获取到有效的宽高(不为0),那么直接返回,这里就是同步的实现。如果获取不到,则借用ViewTreeObserver的addOnPreDrawListener功能,在onPreDraw()的回调里获取到view宽高后再回调到SingleRequest的onSizeReady(),这里是异步的实现。至于为什么可以在onPreDraw()方法里获取到view的宽高,这个和view的渲染机制有关系,可以参考其他资料。

从上面也可以知道,Glide一定要获取到target的宽高才会去发起请求,至于为何一定要获取到宽高采取发起请求,个人理解应该与Glide加载机制依赖于宽高有关系,需要根据宽高来确定现有缓存中是否已经存在目标资源,存在的话可以直接返回

onSizeReady()的实现内容比较少,就是调用了engine.load()方法去加载图片(engine部分放到另一篇文章来说)然后engine加载图片完成后回调到onResourceReady()方法。SingleRequest实现了ResourceCallback接口,onResourceReady()方法就是ResourceCallback接口的方法,如果加载失败,那么回调到onLoadFailed(GlideException e)方法。

public synchronized void onResourceReady(Resource<?> resource, DataSource dataSource) {
  stateVerifier.throwIfRecycled();
  loadStatus = null;
  if (resource == null) {
    GlideException exception = ...
    onLoadFailed(exception);
    return;
  }

  Object received = resource.get();
  if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
    releaseResource(resource);
    GlideException exception = ...
    onLoadFailed(exception);
    return;
  }

  if (!canSetResource()) {
    releaseResource(resource);
    status = Status.COMPLETE; // We can't put the status to complete before asking canSetResource().
    return;
  }
  onResourceReady((Resource<R>) resource, (R) received, dataSource);
}

engine加载完图片后会以Resource的形式返回,Resource是一个泛型接口类,源码如下,get()返回真正的解码后的资源,getSize()返回资源字节大小:

public interface Resource<Z> {
  Class<Z> getResourceClass();

  /**
   * Returns an instance of the wrapped resource.
   *
   * <p> Note - This does not have to be the same instance of the wrapped resource class and in fact
   * it is often appropriate to return a new instance for each call. For example,
   * {@link android.graphics.drawable.Drawable Drawable}s should only be used by a single
   * {@link android.view.View View} at a time so each call to this method for Resources that wrap
   * {@link android.graphics.drawable.Drawable Drawable}s should always return a new
   * {@link android.graphics.drawable.Drawable Drawable}. </p>
   */
  @NonNull
  Z get();

  /**
   * Returns the size in bytes of the wrapped resource to use to determine how much of the memory
   * cache this resource uses.
   */
  int getSize();
  void recycle();
}

先对资源进行几个判断:

1.非空判断;

2.资源的class是否是指定的transcodeClass,如果不是那么走onLoadFailed()回调;

3.是否可以设置资源,即canSetResource(),这个还没有看明白是啥TODO 

然后进入onResourceReady()的真正实现:

private synchronized void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
  boolean isFirstResource = isFirstReadyResource(); // We must call isFirstReadyResource before setting status. 这里看不懂 TODO
  status = Status.COMPLETE;
  this.resource = resource;
  isCallingCallbacks = true;
  try {
    boolean anyListenerHandledUpdatingTarget = false; //当ResourceReady的时候是否由listener来处理target;
//listener有两类,一类是通过addListener()方法添加的,
//一类是通过into(Target target, RequestListener<R> requestListener, ...)方法添加的,都是RequestListener;
    if (requestListeners != null) {
      for (RequestListener<R> listener : requestListeners) {
        anyListenerHandledUpdatingTarget |=
            listener.onResourceReady(result, model, target, dataSource, isFirstResource);
      }
    }
    anyListenerHandledUpdatingTarget |=
        targetListener != null
            && targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);
    //如果listener没有处理target,那么调用target的onResourceReady()来加载图片;
    if (!anyListenerHandledUpdatingTarget) {
      Transition<? super R> animation =
          animationFactory.build(dataSource, isFirstResource);
      target.onResourceReady(result, animation);
    }
  } finally {
    isCallingCallbacks = false;
  }
  notifyLoadSuccess(); //通知requestCoordinator加载成功了,requestCoordinator还需要写一篇文章来介绍,TODO;
}

如果加载失败的话,源码:

private synchronized void onLoadFailed(GlideException e, int maxLogLevel) {
  stateVerifier.throwIfRecycled();
  loadStatus = null;
  status = Status.FAILED;

  isCallingCallbacks = true;
  try {
    boolean anyListenerHandledUpdatingTarget = false;
    if (requestListeners != null) {
      for (RequestListener<R> listener : requestListeners) {
        anyListenerHandledUpdatingTarget |=
            listener.onLoadFailed(e, model, target, isFirstReadyResource());
      }
    }
    anyListenerHandledUpdatingTarget |=
        targetListener != null
            && targetListener.onLoadFailed(e, model, target, isFirstReadyResource());
    if (!anyListenerHandledUpdatingTarget) { //如果listener没有处理onLoadFailed(),那么设置error图片,如果没有error图片,会设置placeholder图片,可以进去看源码;
      setErrorPlaceholder();
    }
  } finally {
    isCallingCallbacks = false;
  }
  notifyLoadFailed(); //通知requestCoordinator加载失败了
}

再来看看SingleRequest的其他几个部分

一、状态

private enum Status {
  PENDING, //Created but not yet running.
  RUNNING, //In the process of fetching media.
  WAITING_FOR_SIZE, //Waiting for a callback given to the Target to be called to determine target dimensions.
  COMPLETE, //Finished loading media successfully.
  FAILED, //Failed to load media, may be restarted.
  CLEARED, //Cleared by the user with a placeholder set, may be restarted.
}

二、Glide自己实现了 FactoryPools.Poolable接口

SingleRequest的生成使用了缓存池的实现

private static final Pools.Pool<SingleRequest<?>> POOL = FactoryPools.threadSafe(150,
    new FactoryPools.Factory<SingleRequest<?>>() {
      @Override
      public SingleRequest<?> create() {
        return new SingleRequest<Object>();
      }
    });

创建调用Pool.acquire()从缓存池获取SingleRequest对象,调用SingleRequest的init()方法进行初始化,保存一些成员变量,比如context、glideContext、model、requestOptions、target、requestListener……。

释放的时候会调用SingleRequest.recycle()方法,将成员变量置空后,再调用Pool.release(this)将当前SingleRequest对象放入缓存池,至于何时调用SingleRequest.recycle()方法,这个由RequestTracker的clearRemoveAndRecycle()调用SingleRequest.recycle()

注意了,SimplePool本身是没有创建对象的,它只负责acquire、release对象,当第一次使用acquire时肯定返回null,这时需要调用方创建对象,Glide是实现了FactoryPools类来创建。

缓存池引用了android v4包里的SimplePool,内部是一个数组+索引来负责使用和回收,代码摘录(注意下面的SimplePool不是线程安全的,实际上用的SynchronizedPool继承自SimplePool并通过synchroinzed关键字加锁):

public static class SimplePool<T> implements Pool<T> {
    private final Object[] mPool;
    private int mPoolSize;
    public SimplePool(int maxPoolSize) {
        if (maxPoolSize <= 0) {
            throw new IllegalArgumentException("The max pool size must be > 0");
        }
        mPool = new Object[maxPoolSize];
    }

    @Override
    public T acquire() {
        if (mPoolSize > 0) {
            final int lastPooledIndex = mPoolSize - 1;
            T instance = (T) mPool[lastPooledIndex];
            mPool[lastPooledIndex] = null;
            mPoolSize--;
            return instance;
        }
        return null;
    }

    @Override
    public boolean release(@NonNull T instance) {
        if (isInPool(instance)) {
            throw new IllegalStateException("Already in the pool!");
        }
        if (mPoolSize < mPool.length) {
            mPool[mPoolSize] = instance;
            mPoolSize++;
            return true;
        }
        return false;
    }
}

同时配合 StateVerifier类来配合状态的同步。

三、请求暂停

RequestTracker的isPaused=true/调用pauseRequests()时会调用SingleRequest.clear()方法取消当前的加载,并释放资源。

public synchronized void clear() {
  assertNotCallingCallbacks();
  stateVerifier.throwIfRecycled();
  if (status == Status.CLEARED) {
    return;
  }
  cancel();
  // Resource must be released before canNotifyStatusChanged is called.
  if (resource != null) {
    releaseResource(resource);
  }
  if (canNotifyCleared()) {
    target.onLoadCleared(getPlaceholderDrawable()); //通知target onLoadCleared(),用placeholder显示;
  }

  status = Status.CLEARED;
}
private void cancel() {
  assertNotCallingCallbacks();
  stateVerifier.throwIfRecycled();
  target.removeCallback(this); //target移除当前的SingleRequest,那什么时候再添加回去呢?TODO
  if (loadStatus != null) {
    loadStatus.cancel();
    loadStatus = null;
  }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值