先放上glide地址:
https://github.com/bumptech/glide
glide发展到今日已经到了4.9.0,具体的用法在之前也有讲过了,具体请看:
这篇文章主要从源码方面解读Glide。
1:AppGlideModule和GlideModule
我们都知道想要使用glideApp需要先创建一个文件继承AppglideModule并实现GlideModule注解。如:
@GlideModule
public final class GlobalGlideConfig extends AppGlideModule {
}
那AppGlideModule和GlideModule注解具体实现了什么呢?
我们先看下AppGlideModule的代码:
public abstract class AppGlideModule extends LibraryGlideModule implements AppliesOptions {
/**
* Returns {@code true} if Glide should check the AndroidManifest for {@link GlideModule}s.
*
* <p>Implementations should return {@code false} after they and their dependencies have migrated
* to Glide's annotation processor.
*
* <p>Returns {@code true} by default.
*/
public boolean isManifestParsingEnabled() {
return true;
}
@Override
public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
// Default empty impl.
}
}
public abstract class LibraryGlideModule implements RegistersComponents {
@Override
public void registerComponents(@NonNull Context context, @NonNull Glide glide,
@NonNull Registry registry) {
// Default empty impl.
}
}
isManifestParsingEnabled默认返回true;用途是否检测manifest里面的GlideModule。
上面的源码中也告诉我们当继承AppGlideModule时,最好实现这个方法,并默认返回false。这样避免AndroidManifest加载两次。
applyOptions()主要用来对GlideBuilder进行设置。
registerComponents()注册在应用程序中初始化Glide时要使用的一组组件.
//在编译时,为AppGlideModules和LibraryGlideModules提供注入。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface GlideModule {
/**
* Returns the name of the class that will be used as a replacement for
* {@code com.bumptech.glide.Glide} in Applications that depend on Glide's generated code.
*/
String glideName() default "GlideApp";
}
我们可以看到注解GlideModule中默认了GlideName为GlideApp.调用的时候就是GlideApp.with(this);
2:with()
查看源码我们可以知道GlideApp的多个with方法其实实现的还是Glide.with(),并返回GlideRequests。
/**
* @see Glide#with(Context)
*/
@NonNull
public static GlideRequests with(@NonNull Context context) {
return (GlideRequests) Glide.with(context);
}
/**
* @see Glide#with(Activity)
*/
@NonNull
public static GlideRequests with(@NonNull Activity activity) {
return (GlideRequests) Glide.with(activity);
}
/**
* @see Glide#with(FragmentActivity)
*/
@NonNull
public static GlideRequests with(@NonNull FragmentActivity activity) {
return (GlideRequests) Glide.with(activity);
}
/**
* @see Glide#with(Fragment)
*/
@NonNull
public static GlideRequests with(@NonNull Fragment fragment) {
return (GlideRequests) Glide.with(fragment);
}
/**
* @see Glide#with(Fragment)
*/
@Deprecated
@NonNull
public static GlideRequests with(@NonNull android.app.Fragment fragment) {
return (GlideRequests) Glide.with(fragment);
}
/**
* @see Glide#with(View)
*/
@NonNull
public static GlideRequests with(@NonNull View view) {
return (GlideRequests) Glide.with(view);
}
我们以Glide.with(Activity)为例:
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
// Context could be null for other reasons (ie the user passes in null), but in practice it will
// only occur due to errors with the Fragment lifecycle.
Preconditions.checkNotNull(
context,
"You cannot start a load on a not yet attached View or a Fragment where getActivity() "
+ "returns null (which usually occurs when getActivity() is called before the Fragment "
+ "is attached or after the Fragment is destroyed).");
return Glide.get(context).getRequestManagerRetriever();
}
/**
* Begin a load with Glide that will be tied to the given {@link android.app.Activity}'s lifecycle
* and that uses the given {@link Activity}'s default options.
*
* @param activity The activity to use.
* @return A RequestManager for the given activity that can be used to start a load.
*/
@NonNull
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
可以看到with()方法就是调用getRequestManagerRetriever().get()来获取一个RequestManagerRetriever对象。
传入参数activity是为了绑定activity,当Activity 销毁的时候Glide会停止图片的加载。
至于RequestManagerRetriever中具体通过单例模式返回RequestManager 对象,
@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)) {
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());
}
}
return getApplicationManager(context);
}
@NonNull
public RequestManager get(@NonNull Fragment fragment) {
Preconditions.checkNotNull(fragment.getActivity(),
"You cannot start a load on a fragment before it is attached or after it is destroyed");
if (Util.isOnBackgroundThread()) {
return get(fragment.getActivity().getApplicationContext());
} else {
FragmentManager fm = fragment.getChildFragmentManager();
return supportFragmentGet(fragment.getActivity(), fm, fragment, fragment.isVisible());
}
}
@SuppressWarnings("deprecation")
@NonNull
public RequestManager get(@NonNull Activity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
//判断当前activity是否被销毁
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
从get(Context context)中我们可以看到根据context instance application来判断,当传入对象是application时调用getApplicationManager()返回RequestManager;
@NonNull
private RequestManager getApplicationManager(@NonNull Context context) {
// Either an application context or we're on a background thread.
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
// Normally pause/resume is taken care of by the fragment we add to the fragment or
// activity. However, in this case since the manager attached to the application will not
// receive lifecycle events, we must force the manager to start resumed using
// ApplicationLifecycle.
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context.getApplicationContext());
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(),
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
}
}
}
return applicationManager;
}
当传入不是application时又分为两种:
第一种supportFragmentGet
@NonNull
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
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 =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
第二种fragmentGet
@SuppressWarnings({"deprecation", "DeprecatedIsStillUsed"})
@Deprecated
@NonNull
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = getRequestManagerFragment(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 =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
两种方法基本一致,都是创建一个没有界面的的fragment并add到当前activity中,以此来实现对activity生命周期的监听。
@SuppressWarnings("deprecation")
@NonNull
private RequestManagerFragment getRequestManagerFragment(
@NonNull final android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
3:GlideBuilder
用于设置Glide要使用的默认结构类的构建器类.
具体的set方法等可查看api:
https://bumptech.github.io/glide/javadocs/410/com/bumptech/glide/GlideBuilder.html
@NonNull
Glide build(@NonNull Context context) {
//创建图片线程池
if (sourceExecutor == null) {
sourceExecutor = GlideExecutor.newSourceExecutor();
}
// 创建硬盘缓存线程池diskCacheExecutor
if (diskCacheExecutor == null) {
diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
}
// 创建动画线程池animationExecutor
if (animationExecutor == null) {
animationExecutor = GlideExecutor.newAnimationExecutor();
}
if (memorySizeCalculator == null) {
memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
}
if (connectivityMonitorFactory == null) {
connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
}
if (bitmapPool == null) {
int size = memorySizeCalculator.getBitmapPoolSize();
if (size > 0) {
// 创建图片线程池LruBitmapPool,缓存所有被释放的bitmap
bitmapPool = new LruBitmapPool(size);
} else {
bitmapPool = new BitmapPoolAdapter();
}
}
// 创建对象数组缓存池LruArrayPool,默认4M
if (arrayPool == null) {
arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
}
//内存缓存
if (memoryCache == null) {
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
}
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
// 创建任务和资源管理引擎(线程池,内存缓存和硬盘缓存对象)
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
GlideExecutor.newAnimationExecutor(),
isActiveResourceRetentionAllowed);
}
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptions.lock(),
defaultTransitionOptions);
}
4:load(url)
我们可以看到load是GlideRequest的方法,
@Override
@NonNull
@CheckResult
public GlideRequest<Drawable> load(@Nullable String string) {
return (GlideRequest<Drawable>) super.load(string);
}
如上是加载的super.load();我们看到GlideRequest是继承自GlideManager,所以继续查看GlideManager的load方法。
@NonNull
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
/**
* Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(Bitmap)}.
*
* @return A new request builder for loading a {@link Drawable} using the given model.
*/
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
return asDrawable().load(bitmap);
}
/**
* Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(Drawable)}.
*
* @return A new request builder for loading a {@link Drawable} using the given model.
*/
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
return asDrawable().load(drawable);
}
/**
* Equivalent to calling {@link #asDrawable()} and then {@link RequestBuilder#load(String)}.
*
* @return A new request builder for loading a {@link Drawable} using the given model.
*/
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
继续点进去可以看到
/**
* Returns a request builder to load the given {@link java.lang.String}.
*
* <p> Note - this method caches data using only the given String as the cache key. If the data is
* a Uri outside of your control, or you otherwise expect the data represented by the given String
* to change without the String identifier changing, Consider using
* {@link com.bumptech.glide.request.RequestOptions#signature(com.bumptech.glide.load.Key)} to
* mixin a signature you create that identifies the data currently at the given String that will
* invalidate the cache if that data changes. Alternatively, using
* {@link com.bumptech.glide.load.engine.DiskCacheStrategy#NONE} and/or
* {@link com.bumptech.glide.request.RequestOptions#skipMemoryCache(boolean)} may be
* appropriate.
* </p>
*
* @see #load(Object)
*
* @param string A file path, or a uri or url handled by
* {@link com.bumptech.glide.load.model.UriLoader}.
*/
@NonNull
@Override
@CheckResult
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
//设置model
@NonNull
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
5:into
如上所示:into 主要有三种传参方式:
5.1Imageview
/**
* Sets the {@link ImageView} the resource will be loaded into, cancels any existing loads into
* the view, and frees any resources Glide may have previously loaded into the view so they may be
* reused.
*
* @see RequestManager#clear(Target)
*
* @param view The view to cancel previous loads for and load the new resource into.
* @return The
* {@link com.bumptech.glide.request.target.Target} used to wrap the given {@link ImageView}.
*/
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
//判断是否是在主线程
Util.assertMainThread();
//判空
Preconditions.checkNotNull(view);
//ScaleType配置
RequestOptions requestOptions = this.requestOptions;
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.
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);
}
glideContext是在Glide构造方法中创建的
into(ImageView)实际返回的还是into(target)的三个参数的方法。另外 glideContext.buildImageViewTarget(view, transcodeClass)获取到target对象传入参数。
/**
* Set the target the resource will be loaded into.
*
* @param target The target to load the resource into.
* @return The given target.
* @see RequestManager#clear(Target)
*/
@NonNull
public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) {
return into(target, /*targetListener=*/ null);
}
@NonNull
@Synthetic <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener) {
return into(target, targetListener, getMutableOptions());
}
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
@NonNull RequestOptions options) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
options = options.autoClone();
Request request = buildRequest(target, targetListener, options);
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
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()) {
// 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;
}
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
首先Util.assertMainThread()判断是否在主线程,Preconditions.checkNotNull(target)判断是否为空。
在上一步我们可以看到isModelSet是在loadGeneric方法中设置为true的,所以ismodelset也就是判断是否调用了load方法。
target.getRequest() 获取当前Request对象。
request.isEquivalentTo(previous)&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)判断两个请求是否相同,并且当前绑定的request 即previous是否调用skipMemoryCache。
begin() -->启动异步加载
track()方法:
void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}