概述
在分析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;
}
}
最后
以上就是直率方盒为你收集整理的Glide源码——SingleRequest的全部内容,希望文章能够帮你解决Glide源码——SingleRequest所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复