本文章基于glide4.11.0源码分析主流程
主流程代码为 Glide.with(activity).load(url).into(target)
.with方法
@NonNull
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
get方法
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
一般来说都是在主线程,所以看下面的supportFragmentGet
@NonNull
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
**省略若干代码
return requestManager;
}
因为只看我觉得重要的主流程,所以一些干扰代码直接省去了
getSupportRequestManagerFragment方法
@NonNull
private SupportRequestManagerFragment getSupportRequestManagerFragment(
@NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
SupportRequestManagerFragment current =
(SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
总结一下with方法做了什么
.with传入了一个上下文,glide通过这个上下文,创建了一个requestmanager和一个空的fragment,将fragment添加到activity中,将requestmanager和fragment进行绑定。这样这个requestmanager就拥有生命周期了
.load 只是进行了一些参数的赋值,获取到了一个requestbuilder
最重要的是into方法
.into方法
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
注意buildimageviewtarget返回的是DrawableImageViewTarget
可以自行点进去看
继续看into
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
Request request = buildRequest(target, targetListener, options, callbackExecutor);
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
}
private Request buildRequest(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
return buildRequestRecursive(
/*requestLock=*/ new Object(),
target,
targetListener,
/*parentCoordinator=*/ null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions,
callbackExecutor);
}
private Request buildRequestRecursive(
Object requestLock,
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
Request mainRequest =
buildThumbnailRequestRecursive(
requestLock,
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions,
callbackExecutor);
}
private Request buildThumbnailRequestRecursive(
Object requestLock,
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
Request fullRequest =
obtainRequest(
requestLock,
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
private Request obtainRequest(
Object requestLock,
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
Executor callbackExecutor) {
return SingleRequest.obtain(
context,
glideContext,
requestLock,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
最后走到了SingleRequest方法里面
在into的时候下面有一句话 previous.begin();
也就是获取到了这个request之后会执行begin方法,那么直接去看SingleRequest的begin方法
@Override
public void begin() {
synchronized (requestLock) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
target.getsize最后也会走到onSizeReady方法里面前面我们已经得到了target是DrawableImageViewTarget可以自行去看
接下来看onSizeReady位于singlerequest方法中
@Override
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
synchronized (requestLock) {
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(),
this,
callbackExecutor);
engine.load方法
public <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb,
Executor callbackExecutor) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
**缓存代码都删除了,第一次加载肯定是没有缓存的所以memoryResource==null
if (memoryResource == null) {
return waitForExistingOrStartNewJob(
glideContext,
model,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
options,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache,
cb,
callbackExecutor,
key,
startTime);
}
}
return null;
}
private <R> LoadStatus waitForExistingOrStartNewJob(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb,
Executor callbackExecutor,
EngineKey key,
long startTime) {
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
jobs.put(key, engineJob);
engineJob.addCallback(cb, callbackExecutor);
engineJob.start(decodeJob);
}
engineJob.start(decodeJob);启动engineJob
那么直接去看engineJob的run方法
enginejob是一个runnable
@Override
public void run() {
runWrapped();
}
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
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);
}
}
默认我们的runReason就是INITIALIZE
所以直接看runGenerators
private void runGenerators() {
while (!isCancelled
&& currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
}
这里可以看到getNextGenerator获取到的是SourceGenerator
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);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
上面的代码就是获取获取一个Generator并且执行,
那么在第一次加载没有缓存的情况下获取到的就是SourceGenerator
那我们看SourceGenerator的startNext方法
@Override
public boolean startNext() {
while (!started && hasNextModelLoader()) {
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
startNextLoad(loadData);
}
}
return started;
}
private void startNextLoad(final LoadData<?> toStart) {
loadData.fetcher.loadData(
helper.getPriority(),
new DataCallback<Object>() {
@Override
public void onDataReady(@Nullable Object data) {
if (isCurrentRequest(toStart)) {
onDataReadyInternal(toStart, data);
}
}
@Override
public void onLoadFailed(@NonNull Exception e) {
if (isCurrentRequest(toStart)) {
onLoadFailedInternal(toStart, e);
}
}
});
}
调用fetch的loadData方法
因为我们这里加载的是网络图片所以获取到的fetch是HttpUrlFetcher
HttpUrlFetcher的loadData方法
接下来看
@Override
public void loadData(
@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
callback.onDataReady(result);
}
private InputStream loadDataWithRedirects(
URL url, int redirects, URL lastUrl, Map<String, String> headers) throws IOException {
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);
urlConnection.setInstanceFollowRedirects(false);
urlConnection.connect();
stream = urlConnection.getInputStream();
}
这里出现了熟悉的网络代码将url变成了一个inputstream
获取到了inputstream了之后 这个流是怎么转换为图片设置到我们的target上面的呢,继续往下看
callback.onDataReady(result);
这个callback是前面loaddata的时候new出来的所以回调直接在SourceGenerator里面
private void startNextLoad(final LoadData<?> toStart) {
loadData.fetcher.loadData(
helper.getPriority(),
new DataCallback<Object>() {
@Override
public void onDataReady(@Nullable Object data) {
if (isCurrentRequest(toStart)) {
onDataReadyInternal(toStart, data);
}
}
@Override
public void onLoadFailed(@NonNull Exception e) {
if (isCurrentRequest(toStart)) {
onLoadFailedInternal(toStart, e);
}
}
});
}
@SuppressWarnings("WeakerAccess")
@Synthetic
void onDataReadyInternal(LoadData<?> loadData, Object data) {
cb.onDataFetcherReady(
loadData.sourceKey,
data,
loadData.fetcher,
loadData.fetcher.getDataSource(),
originalKey);
}
走到了cb.onDataFetcherReady,cb是在哪里设置的呢
在DecodeJob.getNextGenerator的时候设置了cb,所以我们看DecodeJob的onDataFetcherReady方法
@Override
public void onDataFetcherReady(
Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
deFromRetrievedData();
}
private void decodeFromRetrievedData() {
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
我们先看解码图片的代码,解码完成后会走notifyEncodeAndRelease
private <Data> Resource<R> decodeFromData(
DataFetcher<?> fetcher, Data data, DataSource dataSource) throws GlideException {
Resource<R> result = decodeFromFetcher(data, dataSource);
}
@SuppressWarnings("unchecked")
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);
}
注意这里的decodeHelper.getLoadPath方法,在下面解码图片获取decoder的时候,decode是在这里初始化的
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 {
return loadWithExceptionList(rewinder, options, width, height, decodeCallback, 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);
}
@NonNull
private Resource<ResourceType> decodeResource(
try {
return decodeResourceWithList(rewinder, width, height, options, exceptions);
} finally {
}
}
@NonNull
private Resource<ResourceType> decodeResourceWithList(
if (decoder.handles(data, options)) {
data = rewinder.rewindAndGet();
result = decoder.decode(data, width, height, options);
}
这里讲一下这个decoder是哪里来的在前面我标记了decodeHelper.getLoadPath这个方法
<Data> LoadPath<Data, ?, Transcode> getLoadPath(Class<Data> dataClass) {
return glideContext.getRegistry().getLoadPath(dataClass, resourceClass, transcodeClass);
}
这个方法里面初始化了decoder
@Nullable
public <Data, TResource, Transcode> LoadPath<Data, TResource, Transcode> getLoadPath(
@NonNull Class<Data> dataClass,
@NonNull Class<TResource> resourceClass,
@NonNull Class<Transcode> transcodeClass) {
List<DecodePath<Data, TResource, Transcode>> decodePaths =
getDecodePaths(dataClass, resourceClass, transcodeClass);
return result;
}
@NonNull
private <Data, TResource, Transcode> List<DecodePath<Data, TResource, Transcode>> getDecodePaths(
@NonNull Class<Data> dataClass,
@NonNull Class<TResource> resourceClass,
@NonNull Class<Transcode> transcodeClass) {
List<ResourceDecoder<Data, TResource>> decoders =
decoderRegistry.getDecoders(dataClass, registeredResourceClass);
}
public synchronized <T, R> List<ResourceDecoder<T, R>> getDecoders(
@NonNull Class<T> dataClass, @NonNull Class<R> resourceClass) {
List<ResourceDecoder<T, R>> result = new ArrayList<>();
for (String bucket : bucketPriorityList) {
List<Entry<?, ?>> entries = decoders.get(bucket);
if (entries == null) {
continue;
}
for (Entry<?, ?> entry : entries) {
if (entry.handles(dataClass, resourceClass)) {
result.add((ResourceDecoder<T, R>) entry.decoder);
}
}
}
return result;
}
这里可以看到decoder都是在bucketPriorityList中获取到的而bucketPriorityList是通过
setBucketPriorityList方法设置的
如下在registry类构建的时候设置了3个一个gif一个bitmap一个gitmapdrawable
public Registry() {
this.modelLoaderRegistry = new ModelLoaderRegistry(throwableListPool);
this.encoderRegistry = new EncoderRegistry();
this.decoderRegistry = new ResourceDecoderRegistry();
this.resourceEncoderRegistry = new ResourceEncoderRegistry();
this.dataRewinderRegistry = new DataRewinderRegistry();
this.transcoderRegistry = new TranscoderRegistry();
this.imageHeaderParserRegistry = new ImageHeaderParserRegistry();
setResourceDecoderBucketPriorityList(
Arrays.asList(BUCKET_GIF, BUCKET_BITMAP, BUCKET_BITMAP_DRAWABLE));
}
而BUCKET_BITMAP_DRAWABLE
对应的是
.append(
Registry.BUCKET_BITMAP_DRAWABLE,
ByteBuffer.class,
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, byteBufferBitmapDecoder))
.append(
Registry.BUCKET_BITMAP_DRAWABLE,
InputStream.class,
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, streamBitmapDecoder))
.append(
Registry.BUCKET_BITMAP_DRAWABLE,
ParcelFileDescriptor.class,
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, parcelFileDescriptorVideoDecoder))
streamBitmapDecoder = new InputStreamBitmapImageDecoderResourceDecoder();
所以很明显我们的是inputstream所以最后只需要看InputStreamBitmapImageDecoderResourceDecoder的decoder方法
InputStreamBitmapImageDecoderResourceDecoder的
decode方法
@Override
protected Resource<Bitmap> decode(
Source source,
int requestedResourceWidth,
int requestedResourceHeight,
OnHeaderDecodedListener listener)
throws IOException {
Bitmap result = ImageDecoder.decodeBitmap(source, listener);
return new BitmapResource(result, bitmapPool);
}
返回一个ResourceBitmap
然后回到解码的地方,解码成功后
private void decodeFromRetrievedData() {
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
解码完成后调用
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
notifyComplete(result, dataSource);
}
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
callback.onResourceReady(resource, dataSource);
}
callback是EngineJob可以回退自行查看
接下来看EngineJob的onResourceReady
@Override
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
synchronized (this) {
this.resource = resource;
this.dataSource = dataSource;
}
notifyCallbacksOfResult();
}
@Synthetic
void notifyCallbacksOfResult() {
for (final ResourceCallbackAndExecutor entry : copy) {
entry.executor.execute(new CallResourceReady(entry.cb));
}
}
CallResourceReady的run方法
@Override
public void run() {
callCallbackOnResourceReady(cb);
}
void callCallbackOnResourceReady(ResourceCallback cb) {
cb.onResourceReady(engineResource, dataSource);
}
这个cb是SingleRequest有兴趣的可以跟着回退一步一步看,很容易就能找到
@SuppressWarnings("unchecked")
@Override
public void onResourceReady(Resource<?> resource, DataSource dataSource) {
stateVerifier.throwIfRecycled();
onResourceReady((Resource<R>) resource, (R) received, dataSource);
}
}
@GuardedBy("requestLock")
private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
target.onResourceReady(result, animation);、
}
前面我们已经知道target是DrawableImageViewTarget
那么去看一下onResourceReady
在DrawableImageViewTarget的父类ImageViewTarget中
@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);
}
protected abstract void setResource(@Nullable Z resource);
回调子类的setResource方法我们来看下DrawableImageViewTarget的setResource
@Override
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
好了到这里主流程就分析完了,看了2-3天才梳理完这么简单的一句话
Glide.with(activity).load(url).into(target)
里面很多的callback都是设置的this,所以在找callback的时候要稍微注意一下,整个看完给我的感觉就是真的很复杂,是一个从外到里,在由里面回调出来的一个过程。
下一篇开始分析glide缓存的源码
网友评论