本篇基于Glide4.6.1
上一篇看到了Glide的基本用法 Glide使用(一)基本用法 , 使用Glide显示一张网络图片只需下面的一句话
Glide.with(this).load(url).into(imageView);
虽然用起来非常简单,不过里面可是进行了很多复杂的操作,下面就来看一下这句话的内部是个啥样子。
从上面的代码来看,使用Glide显示一张网络图片需要经过三步:with(),load(),into()三步,所以一步一步的来看。
with()
@NonNull
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
可以看到with()方法是一个静态的方法,源码中还有好几个with()方法,用于接收不同的上下文对象,所以with方法不仅可以接收activity,还能接收fragment,Context,返回一个RequestManager对象。可以看到RequestManager对象是通过getRetriever(activity).get(activity)
获取的。所以先看getRetriever()方法
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
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();
}
getRetriever()中就判断了下context是否为null,最终调用Glide的中的getRequestManagerRetriever()方法获得,那就看一下
@NonNull
public RequestManagerRetriever getRequestManagerRetriever() {
return requestManagerRetriever;
}
可以看到直接返回了requestManagerRetriever,很明显参数都是前面的get方法创建的。
@NonNull
public static Glide get(@NonNull Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context);
}
}
}
return glide;
}
可以看到get()方法是一个经典的单例的写法,glide对象只创建一次。下面就是Glide对象的创建了
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
Context applicationContext = context.getApplicationContext();
//获取自定义的模式
GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
List<com.bumptech.glide.module.GlideModule> manifestModules = Collections.emptyList();
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
manifestModules = new ManifestParser(applicationContext).parse();
}
if (annotationGeneratedModule != null
&& !annotationGeneratedModule.getExcludedModuleClasses().isEmpty()) {
Set<Class<?>> excludedModuleClasses =
annotationGeneratedModule.getExcludedModuleClasses();
Iterator<com.bumptech.glide.module.GlideModule> iterator = manifestModules.iterator();
while (iterator.hasNext()) {
com.bumptech.glide.module.GlideModule current = iterator.next();
if (!excludedModuleClasses.contains(current.getClass())) {
continue;
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "AppGlideModule excludes manifest GlideModule: " + current);
}
iterator.remove();
}
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
for (com.bumptech.glide.module.GlideModule glideModule : manifestModules) {
Log.d(TAG, "Discovered GlideModule from manifest: " + glideModule.getClass());
}
}
RequestManagerRetriever.RequestManagerFactory factory =
annotationGeneratedModule != null
? annotationGeneratedModule.getRequestManagerFactory() : null;
builder.setRequestManagerFactory(factory);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.applyOptions(applicationContext, builder);
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.applyOptions(applicationContext, builder);
}
//使用builder模式创建Glide对象
Glide glide = builder.build(applicationContext);
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.registerComponents(applicationContext, glide, glide.registry);
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
}
applicationContext.registerComponentCallbacks(glide);
Glide.glide = glide;
}
因为Glide4.0支持我们通过注解自定义模式,在编译时自动生成需要的代码,上一篇讲过了,所以方法中首先是判断用户有没有自定义模式,有的话需要处理一下。之后就是通过构建者模式创建glide了。Glide glide = builder.build(applicationContext);
@NonNull
public Glide build(@NonNull Context context) {
if (sourceExecutor == null) {
sourceExecutor = GlideExecutor.newSourceExecutor();
}
if (diskCacheExecutor == null) {
diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
}
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) {
bitmapPool = new LruBitmapPool(size);
} else {
bitmapPool = new BitmapPoolAdapter();
}
}
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);
}
可以看到初始话了很多的对象我们刚才需要的requestManagerRetriever也是在这里创建的。除了requestManagerRetriever还创建了很多对象比如:线程池(sourceExecutor,diskCacheExecutor,animationExecutor),内存大小计算器(memorySizeCalculator),默认的连接工厂(DefaultConnectivityMonitorFactory),缓存器(memoryCache),执行引擎(Engine)。
OK我们回到with()方法getRetriever(activity).get(activity)
,从上面的分析可以看到通过getRetriever(),构建了Glide对象,并放回了Glide中的requestManagerRetriever对象,然后调用其get方法。下面就看一下get方法干了神马
@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 FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, null /*parentHint*/);
}
}
@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);
}
}
@NonNull
public RequestManager get(@NonNull Activity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm, null /*parentHint*/);
}
}
@NonNull
public RequestManager get(@NonNull View view) {
if (Util.isOnBackgroundThread()) {
return get(view.getContext().getApplicationContext());
}
Preconditions.checkNotNull(view);
Preconditions.checkNotNull(view.getContext(),
"Unable to obtain a request manager for a view without a Context");
Activity activity = findActivity(view.getContext());
// The view might be somewhere else, like a service.
if (activity == null) {
return get(view.getContext().getApplicationContext());
}
if (activity instanceof FragmentActivity) {
Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
return fragment != null ? get(fragment) : get(activity);
}
// Standard Fragments.
android.app.Fragment fragment = findFragment(view, activity);
if (fragment == null) {
return get(activity);
}
return get(fragment);
}
可以看到get方法有很多的重载,根据我们传入的Context的不同来选择创建不同的RequestManager。主要分两种,
第一种 :如果是传入的Application对象就调用参数是Context的重载方法。因为Application的生命周期是跟我们的应用程序是 一样的,只要程序在它就存在,所以glide不用做特殊的处理。
第二种:如果不是Application而是activity,fragment。因为activity和fragment都有生命周期,比如我们在activity中加载一张图片,图片还没有加载完成,activity关闭了,这时候我们的图片加载也应该停止。所以图片的加载需要跟他们的生命周期绑定。那怎么能监听生命周期呢,这里使用了一个巧妙的方法,创建一个隐藏的fragment,通过这个隐藏的fragment来监听。
第三种:如果是view,先找到这个view是在activity中还是fragment中,在调用第二种方法。
我们看到每个get方法中都有一个判断
if (Util.isOnBackgroundThread()) {
return get(view.getContext().getApplicationContext());
}
如果是在后台线程中,无论我们传入的是那种context,都会强制穿换成ApplicationContext。因为我们后台运行部需要管activity和fragment的生命周期。
到这里with()方法就看完了,它主要就是创建了了Glide对象并初始化其成员变量,通过我们传入的不同的context,最终获得了RequestManager对象。
load()
上面的with()方法最后返回了一个RequestManager对象,所以load()方法也是在RequestManager中了
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
load()方法有很多重载的方法,不仅可以传入字符串,还可以传入Bitmap,Drawable,Uri,File,Integer,URL,byte,Object。因为我们平时用的组多的就是通过网络获取图片,所以这里我们就研究一下通过传入一个图片的String地址这个重载
可以看到上面的代码中并没有直接去加载我们的url,而是先调用了asDrawable()方法。这里首先配置了我们加载返回的类型,可以是bitmap,gif,Drawable,file。默认的是Drawable我们也可以自己配置。这些Glide都给我们提供了asGif(),asBitmap(),asDrawable(),asFile() 。
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
protected RequestBuilder(Glide glide, RequestManager requestManager,
Class<TranscodeType> transcodeClass, Context context) {
this.glide = glide;
this.requestManager = requestManager;
this.transcodeClass = transcodeClass;
this.defaultRequestOptions = requestManager.getDefaultRequestOptions();
this.context = context;
this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
this.requestOptions = defaultRequestOptions;
this.glideContext = glide.getGlideContext();
}
可以看到as方法返回的是一个RequestBuilder对象。创建RequestBuilder对象并且给其成员变量赋值,这里的transcodeClass 就是我们传入的需要转换的类型。然后就是调用RequestBuilder总的load()方法了。
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
这个load()方法跟前面的load()一样都有很多重载方法,最终都调用了loadGeneric方法
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
可以看到这里就是给RequestBuilder的成员变量赋值,确定请求模式model就是我们传过来的String,uri,file,bitmap,drawable.。并isModelSet 设置成true说明已经设置过model了。
到这里load()方法也就完事了。
从上面的分析可以知道,with()和load()两个方法就是为了创建各种对象和赋值各种参数。下面先看一些比较重要的参数。
Glide
Glide是一个单例的对象,通过build方法创建。上面我们看了build中的代码,初始化了很多成员变量。持有glide运行所需要的引擎对象,缓存对象等。
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptions.lock(),
defaultTransitionOptions);
}
Engine
Glide创建的时候创建。
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
GlideExecutor.newAnimationExecutor(),
isActiveResourceRetentionAllowed);
engine 翻译成引擎,创建的时候传入了几个参数,包括内存缓存对象,磁盘缓存对象,线程池。通过这些对象的名字我们也可以知道这个类是执行我们图片加载任务的主要类之一。负责启动加载图片和图片的缓存
RequestManagerRetriever
根据我们传入的不同的Context来创建出对应的RequestManager对象
Registry
添加和注册不同的解析的方式
GlideContext
Glide在加载过程中可以使用的全局的上下文对象
load()方法返回了RequestBuilder因为into()就在RequestBuilder中,下面就是调用方法了。由于into()方法非常复杂就下一篇在分析了。