内容简介:先来说下世面上常用的三种图片加载框架Picasso,Glide,FrescoPicasso与Glide相比:Fresco
先来说下世面上常用的三种图片加载框架Picasso,Glide,Fresco
Picasso与Glide相比:
- 相似——api上的调用差不多,都支持内存缓存,glide是picasso的升级,性能有一定的提升
- 差异
- 缓存不同,picasso2级缓存,没有磁盘缓存,Glide三级缓存,内存-磁盘-网络的优先级加载黑乎乎。
- Picasso默认加载的图片格式是ARGB-8888,Glide默认是RGB-565,内存开销节省小一半
- Picasso是加载全尺寸图片到内存中,下次在任何imageView中加载图片时,先取全尺寸图片,重新调整大小,再存缓存。而Glide是按ImageView的大小缓存的,为每种大小缓存一次。 Glide这种方式是空间换时间 ,大小几乎是picasso的2倍
- 生命周期问题,Glide的with方法图片加载会和Activity与Fragment的生命周期一致
- Glide可以加载GIF
- Picasso包特别小,100k左右,方法法为850,glide大概500k,2700个方法。
Fresco
- 优点:
- 图片存储在安卓系统匿名共享内存区,而不是虚拟机的堆内存,图片的中间缓冲数据也存放在本地堆内存,所以应用有更多的内存空间使用。不容易OOM,减少GC回收
- 渐近式加载,支持图片从模糊到清晰,用户体验极好
- 图片可以以任意为中心点显示在ImageView
- JPEG图片改变大小也是在native进行,不在虚拟机堆内存,同样减少OOM
- 对GIF支持友好
- 缺点
- 包太大,2-3M
- 用法复杂
- 底层都是C/C++,源码阅读有挑战性
小结
Glide能做Picasso能做的所有事情,更快,能处理大型图片流,一般Glide是首选;Fresco当使用图片非常多的应用时,它的优势非常明显
Glide的基本使用
implementation ("com.github.bumptech.glide:glide:4.9.0") {
exclude group: "com.android.support"
}
annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
复制代码
Glide.with(this)
.load("http://pic37.nipic.com/20140113/8800276_184927469000_2.png")
.into(imageView);
<uses-permission android:name="android.permission.INTERNET" />
复制代码
需要注意的是,我们在Android9.0以上使用,用的http请求的话,需要在AndroidMainfest中
<application
...
android:usesCleartextTraffic="true">
复制代码
原因是android9.0以后,默认禁止http请求的。
Glide源码
Glide.with(实例化Glide并获取RequestManager)
先看Glide.with()方法
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
@NonNull
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
public static RequestManager with(@NonNull Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
@SuppressWarnings("deprecation")
@Deprecated
@NonNull
public static RequestManager with(@NonNull android.app.Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
@NonNull
public static RequestManager with(@NonNull View view) {
return getRetriever(view.getContext()).get(view);
}
复制代码
可以看到,with方法有多个重载方法,而且都是先调用了 getRetriever 这个方法,那么我们先看这个方法的源码
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
...
return Glide.get(context).getRequestManagerRetriever();
}
复制代码
从源码看,直接是调用Glide的get()方法,然后再调用 getRequestManagerRetriever
先看get方法
@NonNull
public static Glide get(@NonNull Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context);
}
}
}
return glide;
}
复制代码
一看原来 Glide是单例,只有第一次会实例化 ,通过Builder模式实例化Glide对象,初始化后调用getRequestManagerRetriever方法来得到RequestManagerRetriever对象。
生命周期管理
那么问题又回到了getRetriever(xxx).get(xxx);这里,当getRetriever得到了RequestManagerRetriever对象,我们继续看后面的get方法
//get方法也和with一样,有多个对应的重载
@NonNull
public RequestManager get(@NonNull Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
//直接返回ApplicationManager
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper) {
return get(((ContextWrapper) context).getBaseContext());
}
}
//传入的context为ApplicationContext
return getApplicationManager(context);
}
//get(Activity/fragement)逻辑都差不多的,这里只拿getFragmentActivity来讲
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
//后台时,就调用get(context)
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
//前台可见,创建一个FragmentManager
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
@NonNull
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
//获取RequestManager
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
//如果得到requestManager为空,创建requestManager,并把Lifecycle传了进去
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
//缓存这个requestManager
current.setRequestManager(requestManager);
}
return requestManager;
}
//创建并添加一个SupportRequestManagerFragment
@NonNull
private SupportRequestManagerFragment getSupportRequestManagerFragment(
@NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
SupportRequestManagerFragment current =
(SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
current = new SupportRequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingSupportRequestManagerFragments.put(fm, current);
//在这里,使用fragmentManager添加了一个隐藏的无界面Fragment
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
复制代码
可以看到,get方法的重载方法很多,但是核心都是一样的的,就是返回两种requestManager,1. ApplicationManager,它的生命周期与应用同步,应用退出,Glide也退出;2. 附加在Fragment之上的requestManager,通过这个fragment,绑定了对应的生命周期,这样就可以在Activity销毁时往上加载了,RxPermission也是这么设计的。
public class SupportRequestManagerFragment extends Fragment {
private static final String TAG = "SupportRMFragment";
private final ActivityFragmentLifecycle lifecycle;
...
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
registerFragmentWithRoot(getActivity());
} catch (IllegalStateException e) {
// OnAttach can be called after the activity is destroyed, see #497.
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Unable to register fragment with root", e);
}
}
}
@Override
public void onDetach() {
super.onDetach();
parentFragmentHint = null;
unregisterFragmentWithRoot();
}
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
unregisterFragmentWithRoot();
}
...
}
复制代码
可以看到,SupportRequestManagerFragment就是这么设计的,注入了一个生命周期监听器ActivityFragmentLifecycle,并在Fragment的各个生命周期中,调用了对应的方法。
class ActivityFragmentLifecycle implements Lifecycle {
...
@Override
public void addListener(@NonNull LifecycleListener listener) {
lifecycleListeners.add(listener);
if (isDestroyed) {
listener.onDestroy();
} else if (isStarted) {
listener.onStart();
} else {
listener.onStop();
}
}
@Override
public void removeListener(@NonNull LifecycleListener listener) {
lifecycleListeners.remove(listener);
}
void onStart() {
isStarted = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStart();
}
}
void onStop() {
isStarted = false;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStop();
}
}
void onDestroy() {
isDestroyed = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onDestroy();
}
}
}
复制代码
可以看到,在ActivityFragmentLifecycle会紧接着调用lifecycleListener监听器,而这个监听器其实就是RequestManager。
最后,可以看到,生命周期已与requestManager进行了绑定。
RequestBuilder
load
接下来我们看load方法的源码
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
复制代码
先来看前面的asDrawable
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
复制代码
其实就相当于new RequestBuilder,那再看load
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
@NonNull
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
复制代码
可以看到load方法非常简单,其实是创建了RequestBuilder,并把传递进来的参数url赋值给RequestBuilder中。
into方法实现资源加载并设置到target中
再看into方法
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
// Clone in this method so that if we use this RequestBuilder to load into a View and then
// into a different target, we don't retain the transformation applied based on the previous
// View's scale type.
//这些都与ImageView的scaleType相关,是转换逻辑,与我们关心的代码流程无关,可以不用关心
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
//真正执行的代码在这
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
复制代码
分析源码可以知道,它的内部调用了into的重载方法
我们先看里面的参数方法glideContext.buildImageViewTarget(view, transcodeClass),
@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
@NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
复制代码
可以看到,返回了ViewTarger,还记得上面我们看到的asDrawable么,说明是DrawableImageViewTarget,接下来再看外层的into方法
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
//创建request
Request request = buildRequest(target, targetListener, options, callbackExecutor);
//获取targert之前的请求任务(如果有的话)
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
//新构建的request上一个相等,并且设置了缓存以及没有执行完成
//释放新的request
request.recycle();
// If the request is completed, beginning again will ensure the result is re-delivered,
// triggering RequestListeners and Targets. If the request is failed, beginning again will
// restart the request, giving it another chance to complete. If the request is already
// running, we can let it continue running without interruption.
if (!Preconditions.checkNotNull(previous).isRunning()) {
//当旧的request没有在运行。执行它的begin
// Use the previous request rather than the new one to allow for optimizations like skipping
// setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
// that are done in the individual Request.
previous.begin();
}
return target;
}
// 清除先Target之前的所有任务并释放资源
requestManager.clear(target);
//把新的request设置给target
target.setRequest(request);
//在这里执行request,下载图片任务
requestManager.track(target, request);
return target;
}
private boolean isSkipMemoryCacheWithCompletePreviousRequest(
BaseRequestOptions<?> options, Request previous) {
//是否设置缓存以及上一次是否执行完成
return !options.isMemoryCacheable() && previous.isComplete();
}
复制代码
这里主要做了两件事:
- 通过buildRequest构建了一个request
- 获取target的上一个request对象,与新的request对比,并检测是否采用了缓存及target的上次请求是否完成
- 两个对象相等,并且options采用了缓存或target上一次没有请求完,则将新的request回收,并判断target的request是否还在运行,没有的话begin,并返回
- 两个对象不相等,或者option没有使用缓存和target请求完成了,清除target的之间设置,并将新的request对象设置给target,通过track方法启动request请求。
再来看requestManager的track方法
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
public void track(@NonNull Target<?> target) {
targets.add(target);
}
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
//当处于前台可见时,调用request的begin
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
//先不执行request,只把它加入到一个准备队列
pendingRequests.add(request);
}
}
复制代码
可的看到,track方法是先将target添加到targetTracker类的targets集合中,然后运行request的begin方法。
到这里,其实图片加载网络资源的流程已经完成了大半了。接下来接着看如何加载资源并显示到target上的。
Request实现加载资源及显示
我们直接点request.begin方法去跟踪源码,会发现Request只是一个接口,所以我们要找到它的实现类。
那么我们再看上面的创建request方法
private Request buildRequest(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
return buildRequestRecursive(
target,
targetListener,
/*parentCoordinator=*/ null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions,
callbackExecutor);
}
//参数是真鸡儿长
private Request buildRequestRecursive(
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(
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions,
callbackExecutor);
if (errorRequestCoordinator == null) {
return mainRequest;
}
...
//如果有设置错误时的处理逻辑
return errorRequestCoordinator;
}
复制代码
可以看到,真正的核心代码在buildThumbnailRequestRecursive方法
//这个方法结构其实很简单,但是参数太多,所以把参数省略再看
private Request buildThumbnailRequestRecursive(
...) {
//默认的thumbnailBuilder就是空的,除非手动调用RequestBuilder类的thumbnail方法
//否则这个if代码块永远执行不到
if (thumbnailBuilder != null) {
// Recursive case: contains a potentially recursive thumbnail request builder.
if (isThumbnailBuilt) {
throw new IllegalStateException("You cannot use a request as both the main request and a "
+ "thumbnail, consider using clone() on the request(s) passed to thumbnail()");
}
TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions =
thumbnailBuilder.transitionOptions;
// Apply our transition by default to thumbnail requests but avoid overriding custom options
// that may have been applied on the thumbnail request explicitly.
if (thumbnailBuilder.isDefaultTransitionOptionsSet) {
thumbTransitionOptions = transitionOptions;
}
//缩略图权限
Priority thumbPriority = thumbnailBuilder.isPrioritySet()
? thumbnailBuilder.getPriority() : getThumbnailPriority(priority);
//缩略图宽高
int thumbOverrideWidth = thumbnailBuilder.getOverrideWidth();
int thumbOverrideHeight = thumbnailBuilder.getOverrideHeight();
//宽高检验
if (Util.isValidDimensions(overrideWidth, overrideHeight)
&& !thumbnailBuilder.isValidOverride()) {
thumbOverrideWidth = requestOptions.getOverrideWidth();
thumbOverrideHeight = requestOptions.getOverrideHeight();
}
//缩略图请求协议器,同时协调原图与缩略图的request
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
//原图请求
Request fullRequest =
obtainRequest(...);
isThumbnailBuilt = true;
// Recursively generate thumbnail requests.
//调用buildRequestRecursive,还是会调到buildThumbnailRequestRecursive,这是个递归方法
//递归生成缩略图请求
Request thumbRequest =
thumbnailBuilder.buildRequestRecursive(...);
isThumbnailBuilt = false;
//把这两个request包装到ThumbnailRequestCoordinator中
coordinator.setRequests(fullRequest, thumbRequest);
return coordinator;
} else if (thumbSizeMultiplier != null) {
//根据指定的缩放系数加载缩略图
// Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
Request fullRequest =
obtainRequest(...);
BaseRequestOptions<?> thumbnailOptions =
requestOptions.clone().sizeMultiplier(thumbSizeMultiplier);
Request thumbnailRequest =
obtainRequest(...);
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else {
//只加载原图
// Base case: no thumbnail.
return obtainRequest(...);
}
}
复制代码
可以看到,在buildThumbnailRequestRecursive主要做了有无缩略图的判断,然后再进行加载,最后调用了obtainRequest方法
private Request obtainRequest(
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,
model,//对应load(url),比如一个图片地址
transcodeClass,
requestOptions,
overrideWidth,//宽
overrideHeight,//高
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),//全局加载引擎
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
复制代码
这个方法通过 SingleReques 类的方法obtain去创建一个Request对象,所以,它就是我们要找的requst,那么看它的begin方法
开启资源加载任务
@Override
public synchronized void begin() {
assertNotCallingCallbacks();
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 we're restarted after we're complete (usually via something like a notifyDataSetChanged
// that starts an identical request into the same Target or View), we can simply use the
// resource and size we retrieved the last time around and skip obtaining a new size, starting a
// new load etc. This does mean that users who want to restart a load because they expect that
// the view size has changed will need to explicitly clear the View or Target before starting
// the new load.
if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
// Restarts for requests that are neither complete nor running can be treated as new requests
// and can run again from the beginning.
status = Status.WAITING_FOR_SIZE;
//如果Target的宽高已经获取并合法,就开始下一步
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
//手动获取宽高
target.getSize(this);
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
//设置占位图
target.onLoadStarted(getPlaceholderDrawable());
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
复制代码
可以看到,begin方法经过一系列的判断,当status是RUNNING或者WAITING_FOR_SIZE状态,并且需要设置占位图时,会调用onLoadStarted设置占位图,当状态是COMPLETE时,会执行onResourceReady方法并返回。
@Override
public synchronized void onResourceReady(Resource<?> resource, DataSource dataSource) {
stateVerifier.throwIfRecycled();
loadStatus = null;
...
//判断是否需要设置资源,如果不需要就直接释放并设置状态为COMPLETE
if (!canSetResource()) {
releaseResource(resource);
// We can't put the status to complete before asking canSetResource().
status = Status.COMPLETE;
return;
}
//执行方法
onResourceReady((Resource<R>) resource, (R) received, dataSource);
}
复制代码
上面省略了一大段加载失败的代码,直接来看onResourceReady的重载方法。
private synchronized void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
// We must call isFirstReadyResource before setting status.
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
...
try {
boolean anyListenerHandledUpdatingTarget = false;
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);
//设置资源及动画相关的信息
if (!anyListenerHandledUpdatingTarget) {
Transition<? super R> animation =
animationFactory.build(dataSource, isFirstResource);
//这个target有多个,比如DrawableImageViewTarget
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
//最后通知加载成功
notifyLoadSuccess();
}
复制代码
可以看到,当状态为COMPLETE时,就是把当前result设置到当前的target上,并通知加载成功(做一些加载成功后的清理工作)。
上面是COMPLETE时的状态,那么不是这个状态时呢?会执行到onSizeReady方法
@Override
public synchronized void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
...
status = Status.RUNNING;
//计算缩略图的尺寸
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
if (IS_VERBOSE_LOGGABLE) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
//加载流程
loadStatus =
engine.load(
glideContext,
model,//对应rul,图片地址
requestOptions.getSignature(),
this.width,
this.height,
requestOptions.getResourceClass(),//默认是Object.class
transcodeClass,//默认是Drawable.class
priority,
requestOptions.getDiskCacheStrategy(),//缓存策略,默认是AUTOMATIC
requestOptions.getTransformations(),
requestOptions.isTransformationRequired(),
requestOptions.isScaleOnlyOrNoTransform(),
requestOptions.getOptions(),
requestOptions.isMemoryCacheable(),
requestOptions.getUseUnlimitedSourceGeneratorsPool(),
requestOptions.getUseAnimationPool(),
requestOptions.getOnlyRetrieveFromCache(),
this,
callbackExecutor);
}
复制代码
可以看到,调用了Engine的load方法,关于加载图片的加载机制,我们下一篇再讲,今天先就讲到这。
总结
这一篇主要分析Glide.with().load().into()的简单流程
- Glide类作为入口类,调用静态方法with(),实例化了Glide这个单例,取得RequestManager对象并返回
- RequestManager去管理Request请求,根据Activity或Fragment生命周期,管理request请求,包括:onStop,onStart,onDestory,pauseRequest,resumeRequests等,并可以设置加载资源要返回的资源类型,Bitmap,Drawable,Gif。通过调用load()、asBitmap()、asFile()等方法均返回一个RquestBuilder对象,将资源的请求处理移交给了RequestBuilder,实现将功能分离,模块化处理。
- RquestBuilder处理资源加载请求,调用apply()方法传入RequestOptions对象进行一些选项设置;调用transition()方法实现资源加载显示时过度动画;最后调用into()方法,去构建Rquest对象或使用Target设置过的Request对象,调用Rquest的对象方法begin()开启加载请求。
- 开启请求后的工作就移交到Request类中,加载完成后,Request调用onResourceReady()方法去判断加载结果,若加载成功,调用Target类的onReadySuccess()方法设置资源,调用RequestCoordinator中方法onRequestSuccess()执行加载成功后的资源清理工作。若加载失败,Request直接调用notifyLoadFailed()方法,将清理资源工作移交给RequestCoordinator类处理。
参考
- Glide最全解析系列文章 - 郭神基于3.x版本的。
- Android图片加载框架Glide源码解析(二)
- 深入理解Glide
- Glide使用简介及流程分析
下面是我的公众号,欢迎大家关注我
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 以太坊源码分析(36)ethdb源码分析
- [源码分析] kubelet源码分析(一)之 NewKubeletCommand
- libmodbus源码分析(3)从机(服务端)功能源码分析
- [源码分析] nfs-client-provisioner源码分析
- [源码分析] kubelet源码分析(三)之 Pod的创建
- Spring事务源码分析专题(一)JdbcTemplate使用及源码分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Effective JavaScript
David Herman / Addison-Wesley Professional / 2012-12-6 / USD 39.99
"It's uncommon to have a programming language wonk who can speak in such comfortable and friendly language as David does. His walk through the syntax and semantics of JavaScript is both charming and h......一起来看看 《Effective JavaScript》 这本书的介绍吧!