Picasso,Glide,Fresco对比
上一篇我们分析了Picasso,这一篇我们来分析Glide源码的调用流程,目前主流的图片加载框架除了Picasso和Glide,还有Facebook开源的Fresco,有时间也将开一篇来分析。下面用一张表格来对3者进行对比,如下:
示例
Glide.with( activity )
.load( imageUrl )//指定加载路径
.placeholder( R.mipmap.ic_launcher )//加载前默认图
.error( R.mipmap.ic_launcher )//加载错误时显示的图片
.override( 300, 300 )//指定图片大小
.centerCrop()//缩放,太大会裁剪并填满整个控件
.fitCenter()//缩放,会显示完整图片,但有可能不会填满整个控件
.skipMemoryCache( true )//跳过内缓存,但仍会使用硬盘缓存
.diskCacheStrategy( DiskCacheStrategy.NONE )//不进行磁盘缓存
.diskCacheStrategy( DiskCacheStrategy.RESOURCE )//只缓存转换过后的图片
.diskCacheStrategy( DiskCacheStrategy.ALL )//既缓存原始图片,也缓存转换过后的图片
.diskCacheStrategy( DiskCacheStrategy.DATA )//只缓存原始图片
.diskCacheStrategy( DiskCacheStrategy.AUTOMATIC )//根据图片资源自动选择一种缓存策略(默认选项)
.priority( Priority.HIGH )//指定优先级,但没法保证一定按优先级加载
.into( (ImageView) view );//显示目标
如示例所示,根据不同的需求场景,我们可以为Glide指定不同的配置。由于Glide源码非常庞大和复杂,因此,本篇只分析3个主要的调用流程,即:
Glide.with( getApplicationContext() )
.load( imageUrl )
.into( (ImageView) view );
源码分析
public class Glide implements ComponentCallbacks2 {
......
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
public static RequestManager with(@NonNull Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
public static RequestManager with(@NonNull View view) {
return getRetriever(view.getContext()).get(view);
}
......
//获取RequestManagerRetriever
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).");
//初始化Glide,并获取RequestManagerRetriever
return Glide.get(context).getRequestManagerRetriever();
}
}
with根据不同的上下文参数,提供了多个重载方法,因为不同的上下文环境对图片加载的生命周期,会有不同的影响。
with方法将返回一个RequestManager ,而RequestManager 的获取,需要通过RequestManagerRetriever()这个检索器来构造,并且,一个上下文环境只持有一个检索器。
假设第一次调用,在获取RequestManagerRetriever检索器前,将先初始化Glide。如源码中所示,Glide.get(context)将初始化并返回Glide对象。
public class Glide implements ComponentCallbacks2 {
//获取单例
public static Glide get(@NonNull Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
//初始化检查
checkAndInitializeGlide(context);
}
}
}
return glide;
}
//初始化检查
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;
}
//构造一个new GlideBuilder()并调用双参的重载方法
private static void initializeGlide(@NonNull Context context) {
initializeGlide(context, new GlideBuilder());
}
//初始化
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
Context applicationContext = context.getApplicationContext();
......
//构造Glide对象
Glide glide = builder.build(applicationContext);
......
//保存到静态成员中
Glide.glide = glide;
}
.......
}
Glide通过双重检查锁方式,来初始化和构造单例对象。我们看到,在initializeGlide方法中new了一个GlideBuilder,它用来构建Glide对象,并将对象保存到静态成员变量glide 中。我们看build方法如何构建。
public final class GlideBuilder {
......
Glide build(@NonNull Context context) {
// 创建资源加载请求器,是一个线程池,用于加载源数据(URL等)
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();
}
//Bitmap复用池
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());
}
// 磁盘缓存器,默认为 APP 内部私密目录
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
// 图片加载引擎,用于执行图片加载请求驱动
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
GlideExecutor.newAnimationExecutor(),
isActiveResourceRetentionAllowed);
}
// 构建一个请求监听器列表
if (defaultRequestListeners == null) {
defaultRequestListeners = Collections.emptyList();
} else {
defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
}
//构建RequestManager的检索器
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
//构建Glide
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptions.lock(),
defaultTransitionOptions,
defaultRequestListeners,
isLoggingRequestOriginsEnabled);
}
buid方法构建了许多池子,同时生成上面RequestManager的检索器,在最后构建Glide时将所有参数传入。 Glide 的构造方法代码量非常多,故省略大量代码,只显示核心逻辑。
Glide(
@NonNull Context context,
@NonNull Engine engine,
@NonNull MemoryCache memoryCache,
@NonNull BitmapPool bitmapPool,
@NonNull ArrayPool arrayPool,
@NonNull RequestManagerRetriever requestManagerRetriever,
@NonNull ConnectivityMonitorFactory connectivityMonitorFactory,
int logLevel,
@NonNull RequestOptionsFactory defaultRequestOptionsFactory,
@NonNull Map, TransitionOptions, ?>> defaultTransitionOptions,
@NonNull List> defaultRequestListeners,
boolean isLoggingRequestOriginsEnabled,
boolean isImageDecoderEnabledForBitmaps,
int hardwareBitmapFdLimit) {
// 赋值
this.engine = engine;
this.bitmapPool = bitmapPool;
this.arrayPool = arrayPool;
this.memoryCache = memoryCache;
this.requestManagerRetriever = requestManagerRetriever;
this.connectivityMonitorFactory = connectivityMonitorFactory;
this.defaultRequestOptionsFactory = defaultRequestOptionsFactory;
final Resources resources = context.getResources();
// 新建注册器
registry = new Registry();
registry.register(new DefaultImageHeaderParser());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
registry.register(new ExifInterfaceImageHeaderParser());
}
List imageHeaderParsers = registry.getImageHeaderParsers();
// 创建解码器
ByteBufferGifDecoder byteBufferGifDecoder =
new ByteBufferGifDecoder(context, imageHeaderParsers, bitmapPool, arrayPool);
ResourceDecoder parcelFileDescriptorVideoDecoder =
VideoDecoder.parcel(bitmapPool);
ResourceDecoder byteBufferBitmapDecoder;
ResourceDecoder streamBitmapDecoder;
if (isImageDecoderEnabledForBitmaps && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
streamBitmapDecoder = new InputStreamBitmapImageDecoderResourceDecoder();
byteBufferBitmapDecoder = new ByteBufferBitmapImageDecoderResourceDecoder();
} else {
Downsampler downsampler =
new Downsampler(
registry.getImageHeaderParsers(),
resources.getDisplayMetrics(),
bitmapPool,
arrayPool);
byteBufferBitmapDecoder = new ByteBufferBitmapDecoder(downsampler);
streamBitmapDecoder = new StreamBitmapDecoder(downsampler, arrayPool);
}
ResourceDrawableDecoder resourceDrawableDecoder = new ResourceDrawableDecoder(context);
// 创建数据转换器
ResourceLoader.StreamFactory resourceLoaderStreamFactory =
new ResourceLoader.StreamFactory(resources);
ResourceLoader.UriFactory resourceLoaderUriFactory = new ResourceLoader.UriFactory(resources);
ResourceLoader.FileDescriptorFactory resourceLoaderFileDescriptorFactory =
new ResourceLoader.FileDescriptorFactory(resources);
ResourceLoader.AssetFileDescriptorFactory resourceLoaderAssetFileDescriptorFactory =
new ResourceLoader.AssetFileDescriptorFactory(resources);
BitmapEncoder bitmapEncoder = new BitmapEncoder(arrayPool);
// 创建转码器
BitmapBytesTranscoder bitmapBytesTranscoder = new BitmapBytesTranscoder();
GifDrawableBytesTranscoder gifDrawableBytesTranscoder = new GifDrawableBytesTranscoder();
ContentResolver contentResolver = context.getContentResolver();
// 注册各个类型的解码器和编码器
registry
.append(ByteBuffer.class, new ByteBufferEncoder())
.append(InputStream.class, new StreamEncoder(arrayPool))
......
.register(
Drawable.class,
byte[].class,
new DrawableBytesTranscoder(
bitmapPool, bitmapBytesTranscoder, gifDrawableBytesTranscoder))
.register(GifDrawable.class, byte[].class, gifDrawableBytesTranscoder);
// 创建图片显示目标对象工厂
ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
// 创建 GlideContext 对象,注意传入的参数
glideContext =
new GlideContext(
context,
arrayPool,
registry,
imageViewTargetFactory,
defaultRequestOptionsFactory,
defaultTransitionOptions,
defaultRequestListeners,
engine,
isLoggingRequestOriginsEnabled,
logLevel);
}
构造方法主要是初始化模型转换器、解码器、转码器和编码器,并对各种类型在注册表进行注册。Glide的整个加载流程将经历:model(数据源)-->data(转换数据)-->decode(解码)-->transformed(缩放)-->transcoded(转码)-->encoded(编码保存到本地),所以在构造方法里初始化这些对象,是为Gilde后续的加载流程做准备的。
回到一开始的width方法。在GlideBuilder 中,已经创建好了RequestManagerRetriever检索器 ,RequestManagerRetriever 将通过get方法来获取RequestManager。
public class RequestManagerRetriever implements Handler.Callback {
......
private volatile RequestManager applicationManager;
public RequestManagerRetriever(@Nullable RequestManagerFactory factory) {
this.factory = factory != null ? factory : DEFAULT_FACTORY;
handler = new Handler(Looper.getMainLooper(), this /* Callback */);
}
......
//Application上下文环境
private RequestManager getApplicationManager(@NonNull Context context) {
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
Glide glide = Glide.get(context.getApplicationContext());
//新建ApplicationLifecycle()和EmptyRequestManagerTreeNode
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(),
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
}
}
}
return applicationManager;
}
//获取RequestManager
public RequestManager get(@NonNull Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
//在主线程中,并且上下文不是Application
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
//对3种上下文进行判断
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);
}
//工厂接口
public interface RequestManagerFactory {
@NonNull
RequestManager build(
@NonNull Glide glide,
@NonNull Lifecycle lifecycle,
@NonNull RequestManagerTreeNode requestManagerTreeNode,
@NonNull Context context);
}
private static final RequestManagerFactory DEFAULT_FACTORY = new RequestManagerFactory() {
@NonNull
@Override
public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle,
@NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) {
return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
}
};
}
在构造RequestManagerRetriever时,倘若没有设置RequestManagerFactory工厂,那么将使用默认的匿名内部类DEFAULT_FACTORY 来构造RequestManager。
RequestManagerRetriever的get方法主要分2种情况,其中子线程和Application上下文环境最为简单,它将使用Application为上下文,构建RequestManager,并且由源码所示,RequestManager也是一个单例,也就是说,一种上下文只有一个RequestManagerRetriever检索器,也只有一个RequestManager对象。
而其他上下文情况,最终都会以Activity为上下文,调用参数为Activity的get方法,我们继续分析,看以Activity为上下文的调用过程和以Application为上下文的情况有什么不同。
public class RequestManagerRetriever implements Handler.Callback {
//Tag缓存
static final String FRAGMENT_TAG = "com.bumptech.glide.manager";
//map缓存
final Map pendingRequestManagerFragments =
new HashMap<>();
......
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, isActivityVisible(activity));
}
}
//activity是否退出了
private static boolean isActivityVisible(Activity activity) {
return !activity.isFinishing();
}
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
//获取一个空fragment
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
//获取RequestManager
RequestManager requestManager = current.getRequestManager();
//为空则构建
if (requestManager == null) {
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
private RequestManagerFragment getRequestManagerFragment(
@NonNull final android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
//通过名为FRAGMENT_TAG的Tag获取
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
//空则从缓存中获取
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
//缓存空则新建
if (current == null) {
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
//Activity没退出
if (isParentVisible) {
//开启生命周期监听
current.getGlideLifecycle().onStart();
}
//缓存起来
pendingRequestManagerFragments.put(fm, current);
//加到当前Activity
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
//发送ID_REMOVE_FRAGMENT_MANAGER消息清除缓存
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
//消息回调移除缓存RequestManagerFragment
@Override
public boolean handleMessage(Message message) {
boolean handled = true;
Object removed = null;
Object key = null;
switch (message.what) {
case ID_REMOVE_FRAGMENT_MANAGER:
android.app.FragmentManager fm = (android.app.FragmentManager) message.obj;
key = fm;
//从缓存移除
removed = pendingRequestManagerFragments.remove(fm);
break;
case ID_REMOVE_SUPPORT_FRAGMENT_MANAGER:
FragmentManager supportFm = (FragmentManager) message.obj;
key = supportFm;
removed = pendingSupportRequestManagerFragments.remove(supportFm);
break;
default:
handled = false;
break;
}
if (handled && removed == null && Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Failed to remove expected request manager fragment, manager: " + key);
}
return handled;
}
}
RequestManagerFragment 是一个空的Fragment,Glide正是通过它来监听Activity的生命周期,换句话说,当Activity的生命周期方法被回调,也就同时回调了Fragment(RequestManagerFragment )。
如源码中所示,如果RequestManagerFragment被添加到当前的Activity中,那么通过变量名FRAGMENT_TAG就可以获取到,那为什么还需要使用pendingSupportRequestManagerFragments这个Map来进行缓存,而添加到Activity后,又立即通过消息将其从Map中移除?
因为并发。以下面的代码为例:
Glide.with(activity).load(url1).into(imageView1); //request1
Glide.with(activity).load(url2).into(imageView2); //request2
Fragment添加是通过Handler消息队列操作的,而消息队列执行在主线程之后。假设request1创建RequestManagerFragment,并提交了事务,在RequestManagerFragment添加消息未执行,也就是说RequestManagerFragment未被添加到Acitivy中前,request2执行到fm.findFragmentByTag(FRAGMENT_TAG),current 将会为null,那么,如果不使用map来缓存,RequestManagerFragment又将实例化一个,也就意味着,当前Activity将出现重复添加RequestManagerFragment的情况。
由于移除消息在提交事务消息之后,等到移除消息执行时,后面的请求已经能通过FRAGMENT_TAG获取到RequestManagerFragment了,Map没有必要再继续缓存着,因此,从缓存移除,以避免内存泄漏和减少内存压力。
下面来看RequestManagerFragment是监听Activity生命周期做了哪些操作。
public class RequestManagerFragment extends Fragment {
private final ActivityFragmentLifecycle lifecycle;
public RequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
RequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
public void onDetach() {
super.onDetach();
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();
}
}
RequestManagerFragment 构造时构建了一个ActivityFragmentLifecycle 对象,它正是负责生命周期的回调。
class ActivityFragmentLifecycle implements Lifecycle {
private final Set lifecycleListeners =
Collections.newSetFromMap(new WeakHashMap());
private boolean isStarted;
private boolean isDestroyed;
@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();
}
}
}
public interface Lifecycle {
void addListener(@NonNull LifecycleListener listener);
void removeListener(@NonNull LifecycleListener listener);
}
ActivityFragmentLifecycle 实现了Lifecycle 接口,通过addListener方法将LifecycleListener添加到集合中,当Activity生命周期被回调,将触发RequestManagerFragment对应的生命周期,也将触发ActivityFragmentLifecycle 遍历lifecycleListeners集合,回调每个LifecycleListener对应的方法。
public interface LifecycleListener {
void onStart();
void onStop();
void onDestroy();
}
LifecycleListener接口定义了3个生命周期回调,它的LifecycleListener的实现类有许多个,其中就包括RequestManager类。
with方法分析完毕,总结一下它所做的工作:
- 构造并初始化Gilde对象;
- 在构建Gilde对象的过程中,构建RequestManagerRetriever检索器;
- 检索器在上下文环境不是Application的情况下,会构建一个RequestManagerFragment 来监听页面的生命周期。
- 构建RequestManager对象。Application环境下,RequestManagerRetriever持有RequestManager,非Application环境下,RequestManagerFragment持有RequestManager。