Glide源码解析系列文章基于Glide4.5.0,源码看了很多遍,慢慢理清,文章链接如下:
Glide源码解析(一)
Glide源码解析(二)
Glide源码解析(三)
Glide最基本的使用如下:
Glide.with(this)
.load(R.raw.large_giphy_logo)
.into(giphyLogoView);
1、with()返回RequestManager对象
2、load()返回RequestBuilder对象
3、into()返回Target对象
很简单,本篇主要讲解Glide.with(this),with方法如下:
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
接着接入getRetriever方法:
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
...
return Glide.get(context).getRequestManagerRetriever();
}
我们来看get方法中都做了什么:
public static Glide get(@NonNull Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context);
}
}
}
从上面可以看到在get方法中采用双重检验锁(DCL)的方式生成单例,glide变量用volatile关键字修饰。接下来看checkAndInitializeGlide()方法:
private static void checkAndInitializeGlide(@NonNull Context context) {
if (isInitializing) {
throw new IllegalStateException("You cannot call Glide.get() in registerComponents(),"
+ " use the provided Glide instance instead");
}
isInitializing = true;
initializeGlide(context);
isInitializing = false;
}
isInitializing 同样是volatile的,若是没有被初始化,则调用initializeGlide(context);
private static void initializeGlide(@NonNull Context context) {
initializeGlide(context, new GlideBuilder());
}
在initializeGlide()中,创建了GlideBuilder对象作为参数,调用
@SuppressWarnings("deprecation")
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
...
GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
List manifestModules = Collections.emptyList();
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
manifestModules = new ManifestParser(applicationContext).parse();
}
...
//移除相同的GlideModule
...
RequestManagerRetriever.RequestManagerFactory factory =
annotationGeneratedModule != null
? annotationGeneratedModule.getRequestManagerFactory() : null;
...
//设置GlideBuilder
...
;
...
//注册组件
...
//注册内存优化的系统回调
applicationContext.registerComponentCallbacks(glide);
Glide.glide = glide;
}
这个方法被标记为deprecation,表示这个方法以后可能会被弃用.在getAnnotationGeneratedGlideModules中:
private static GeneratedAppGlideModule getAnnotationGeneratedGlideModules() {
...
Class.forName("com.bumptech.glide.GeneratedAppGlideModuleImpl");
result = clazz.getDeclaredConstructor().newInstance();
...
return result;
}
我们看到GeneratedAppGlideModuleImpl这样一个类,这个类集成自一个叫GeneratedAppGlideModule的虚类,GeneratedAppGlideModule继承自AppGlideModule。在GeneratedAppGlideModuleImpl中,注入了我们自己定义的一个AppGlideModule,所以这个类其实是相当于一个代理。每个应用程序中只能有一个AppGlideModules,可以存在多个LibraryGlideModules在AppGlideModule中,有以下几个方法:
isManifestParsingEnabled()
表示是否检测AndroidManifest里面的GlideModule 该方法,默认返回true。 如果我们通过注解和继承AppGlideModule生成自己的module时,官方要求我们实现并返回false,避免AndroidManifest加载两次。
applyOptions()
在Glide被创建之前,对GlideBuilder进行设置
public Glide build(@NonNull Context context) {
//用来执行Glide的加载,解码和转换业务(请求图片的线程池),是一个依赖于优先级的线程池,线程数量取决于当前唤醒的CPU数量,而不是CPU总数,但虽多不超过4
if (sourceExecutor == null) {
sourceExecutor = GlideExecutor.newSourceExecutor();
}
//用来执行Glide的加载,解码和转换业务,依赖于优先级的线程池(硬盘缓存线程池),线程数为1
if (diskCacheExecutor == null) {
diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
}
//用来加载动画帧,线程数由可用CPU数决定,若可用CPU数不小于4,则加载的线程数为2,否则为1。
if (animationExecutor == null) {
animationExecutor = GlideExecutor.newAnimationExecutor();
}
//用来计算缓存图片的大小以及各种烦缓存pool的size,依据主要是屏幕密度和尺寸,
if (memorySizeCalculator == null) {
memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
}
//网络活动监视器,用来检测网络状态
if (connectivityMonitorFactory == null) {
connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
}
//bitmap池,用来存储bitmap对象,提升内存复用,size为所运行设备的建议bitmap池大小
if (bitmapPool == null) {
int size = memorySizeCalculator.getBitmapPoolSize();
if (size > 0)
{
//从bitmap池中拿取,没有拿到才新建位图
bitmapPool = new LruBitmapPool(size);
} else {
//永远是返回新建位图
bitmapPool = new BitmapPoolAdapter();
}
}
//byte数组缓存池
if (arrayPool == null) {
arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
}
//内存缓存,使用了LRU的方式
if (memoryCache == null) {
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
}
//硬盘缓存,使用了DiskLruCache
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
//负责开启,加载任务以及管理活跃的或者缓存的图片资源
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
GlideExecutor.newAnimationExecutor(),
isActiveResourceRetentionAllowed);
}
//用于创建新的RequestManager或从Activity或Fragment中检索现有的RequestManager,RequestManager后面再说
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptions.lock(),
defaultTransitionOptions);
}
从上面可以看到初始化的requestManagerRetriever ,接着我们返回最初的with方法,bingo,拿到之后看RequestManagerRetriever 的get方法:
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);
}
从上面的额代码我们看到,根据你Context 实际的类型,走不同的分支。若是不在主线程或者传入的是Application,那么返回的是getApplicationManager,Application对象的生命周期即应用程序的生命周期,因此这个情况下,它自动就是和应用程序的生命周期是同步的,如果应用程序关闭的话,Glide的加载也会同时终止。否则,其他情况下get方法如下:
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*/);
}
}
可以看出,如果在子线程,默认当application处理!通过上图我们会发现不论传入Activity、FragmentActivity、Fragment最终都会调用fragmentGet方法,而这个方法最终就是那就是会向当前的Activity当中添加一个隐藏的Fragment (若with中传入的是Fragment,那么get会向当前fragment中添加一个无界面的子fragment)。
为什么要这样做呢?假想一下,若你在某个Activity上正在加载一张图片,图片还没加载出来,Activity被用户关掉了,那么图片就应该取消加载,可是Glide并不知道Activity的生命周期,怎么办呢? 于是Glide就使用了添加隐藏Fragment的这种小技巧,因为Fragment的生命周期和Activity是同步的,如果Activity被销毁了,Fragment是可以监听到的,这样Glide就可以捕获这个事件并停止加载图片。
最后插播一段,Glide类实现了ComponentCallbacks2接口,这是一个细粒度的内存回收管理回调,Application、Activity、Service、ContentProvide等均实现了ComponentCallback2接口,接口中有一个方法:onTrimMemory(),响应onTrimMemory回调,app会直接受益,有利于用户体验,系统更有可能让app存活的更持久。不响应onTrimMemory回调,系统更有可能kill 进程。在Glide中,方法实现为:
public void trimMemory(int level) {
Util.assertMainThread();
memoryCache.trimMemory(level);
bitmapPool.trimMemory(level);
arrayPool.trimMemory(level);
}
可以看到裁剪工作是在主线程中进行,分别是对内存缓存,bitmap池和byte数据进行裁剪。
我感觉我把自己的瞌睡都要将来了,嗯,我是一个没有幽默感的程序员,有错误欢迎纠正~~~