关于 Glide
Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的API,高性能、可扩展的图片解码管道(decode pipeline),以及自动的资源池技术。
Glide 支持拉取,解码和展示视频快照,图片,和GIF动画。Glide的Api是如此的灵活,开发者甚至可以插入和替换成自己喜爱的任何网络栈。默认情况下,Glide使用的是一个定制化的基于HttpUrlConnection的栈,但同时也提供了与Google Volley和Square OkHttp快速集成的工具库。
Glide的性能
Glide 充分考虑了Android图片加载性能的两个关键方面:
图片解码速度
解码图片带来的资源压力
为了让用户拥有良好的App使用体验,图片不仅要快速加载,而且还不能因为过多的主线程I/O或频繁的垃圾回收导致页面的闪烁和抖动现象。
Glide使用了多个步骤来确保在Android上加载图片尽可能的快速和平滑:
自动、智能地下采样(downsampling)和缓存(caching),以最小化存储开销和解码次数;
积极的资源重用,例如字节数组和Bitmap,以最小化昂贵的垃圾回收和堆碎片影响;
深度的生命周期集成,以确保仅优先处理活跃的Fragment和Activity的请求,并有利于应用在必要时释放资源以避免在后台时被杀掉。
Glide的使用
Glide 使用简明的流式语法API,这是一个非常棒的设计,因为它允许你在大部分情况下一行代码搞定需求:
Glide.with(fragment)
.load(url)
.into(imageView);
Glide的使用example详解
1、库的引用
dependencies {
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
}
2、混淆文件
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
# for DexGuard only
-keepresourcexmlelements manifest/application/meta-data@value=GlideModule
3、简单使用
// For a simple view:
@Override public void onCreate(Bundle savedInstanceState) {
...
ImageView imageView = (ImageView) findViewById(R.id.my_image_view);
Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);
}
// For a simple image list:
@Override public View getView(int position, View recycled, ViewGroup container) {
final ImageView myImageView;
if (recycled == null) {
myImageView = (ImageView) inflater.inflate(R.layout.my_image_view, container, false);
} else {
myImageView = (ImageView) recycled;
}
String url = myUrls.get(position);
Glide
.with(myFragment)
.load(url)
.centerCrop()
.placeholder(R.drawable.loading_spinner)
.into(myImageView);
return myImageView;
}
ImageView imageView = new ImageView(this);
String url = "http://www.$$$.com/100.png";
Glide.with(getApplicationContext())//指定上下文环境
.load(url)//指定图片的url
.placeholder(R.mipmap.ic_launcher)//指定未加载成功前显示的图片
.error(R.mipmap.ic_launcher)//指定加载失败时显示的图片
.override(300,300)//指定图片的尺寸
.fitCenter()//指定图片的缩放类型 缩放居中显示 完全显示全部图像,可能不被填满
.centerCrop()//同上 填充整个view,会裁剪图片,可能不完全显示全部图像
.skipMemoryCache(true)//是否跳过内存缓存
.diskCacheStrategy(DiskCacheStrategy.NONE)//跳过磁盘缓存
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)//缓存原来全分辨率的图像
.diskCacheStrategy(DiskCacheStrategy.DATA)//缓存最终的图像
.diskCacheStrategy(DiskCacheStrategy.ALL)//缓存所有版本图像
.priority(Priority.HIGH)//指定加载优先级
.into(imageView);
Glide的加载图片原理分析
首先大概了解图片加载整体的流程:
零星瓢虫_001.png
Glide.with(getApplicationContext())
进入第一段代码,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 View view) {
return getRetriever(view.getContext()).get(view);
}
可以看到Glide的with方法提供了好几种参数的重载方法方便使用。同时都用到了 getRetriever()方法,去看看getRetriever()方法都做了什么:
@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.
//检测是否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()方法主要去获取RequestManagerRetriever类?获取之前我们看到了对context是否为空进行了检测。
继续查看RequestManagerRetriever是做什么的呢?进入RequestManagerRetriever 类中:
public class RequestManagerRetriever implements Handler.Callback {
@VisibleForTesting static final String FRAGMENT_TAG = "com.bumptech.glide.manager";
private static final String TAG = "RMRetriever";
private static final int ID_REMOVE_FRAGMENT_MANAGER = 1;
private static final int ID_REMOVE_SUPPORT_FRAGMENT_MANAGER = 2;
// Hacks based on the implementation of FragmentManagerImpl in the non-support libraries that
// allow us to iterate over and retrieve all active Fragments in a FragmentManager.
private static final String FRAGMENT_INDEX_KEY = "key";
/** The top application level RequestManager. */
private volatile RequestManager applicationManager;
/** Pending adds for RequestManagerFragments. */
@SuppressWarnings("deprecation")
@VisibleForTesting
final Map<android.app.FragmentManager, RequestManagerFragment> pendingRequestManagerFragments =
new HashMap<>();
/** Pending adds for SupportRequestManagerFragments. */
@VisibleForTesting
final Map<FragmentManager, SupportRequestManagerFragment> pendingSupportRequestManagerFragments =
new HashMap<>();
/** Main thread handler to handle cleaning up pending fragment maps. */
private final Handler handler;
private final RequestManagerFactory factory;
// Objects used to find Fragments and Activities containing views.
private final ArrayMap<View, Fragment> tempViewToSupportFragment = new ArrayMap<>();
private final ArrayMap<View, android.app.Fragment> tempViewToFragment = new ArrayMap<>();
private final Bundle tempBundle = new Bundle();
public RequestManagerRetriever(@Nullable RequestManagerFactory factory) {
this.factory = factory != null ? factory : DEFAULT_FACTORY;
handler = new Handler(Looper.getMainLooper(), this /* Callback */);
}
}
// 获取application的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;
}
// 获取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
// Only unwrap a ContextWrapper if the baseContext has a non-null application context.
// Context#createPackageContext may return a Context without an Application instance,
// in which case a ContextWrapper may be used to attach one.
&& ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
通过上述代码发现RequestManagerRetriever主要是一个工厂类用来生产RequestManager。
这里我们就获取到了RequestManagerRetriever,沿着上面的代码继续查看;getRetriever(activity).get(activity);我们以activity为参数来分析,进入RequestManagerRetriever 类查看get方法;
// 获取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
// Only unwrap a ContextWrapper if the baseContext has a non-null application context.
// Context#createPackageContext may return a Context without an Application instance,
// in which case a ContextWrapper may be used to attach one.
&& ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
可以看到会再次对context判断空,如果是Application环境,会调用getApplicationManager(context);否则调用get((Activity) context);先看一下getApplicationManager(context)方法:
@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;
}
可以看到这里通过factory创建了applicationManager类。applicationManager其实就是RequestManager类。同时通过创建 new ApplicationLifecycle()传参对此次加载图像任务生命周期进行监听。因为传进来的context是application ,那么生命周期就是整个app运行的生命周期了;
class ApplicationLifecycle implements Lifecycle {
@Override
public void addListener(@NonNull LifecycleListener listener) {
listener.onStart();
}
@Override
public void removeListener(@NonNull LifecycleListener listener) {
// Do nothing.
}
}
接下来继续查看get((Activity) context)的调用:
@SuppressWarnings("deprecation")
@NonNull
public RequestManager get(@NonNull Activity activity) {
if (Util.isOnBackgroundThread()) { // 是否在后台
return get(activity.getApplicationContext());// 调用application去获取requestManager
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
这里通过拿到FragementManager会继续去调用fragmentGet()方法:
@Deprecated
@NonNull
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);
//通过Fragment获取RequestManager;
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;
}
拿到了FragementManager之后,这里立马去创建了RequestManagerFragment,他其实就是一个Fragement:
@Deprecated
public class RequestManagerFragment extends Fragment {
private static final String TAG = "RMFragment";
private final ActivityFragmentLifecycle lifecycle;
private final RequestManagerTreeNode requestManagerTreeNode =
new FragmentRequestManagerTreeNode();
@SuppressWarnings("deprecation")
private final Set<RequestManagerFragment> childRequestManagerFragments = new HashSet<>();
@Nullable private RequestManager requestManager;
}
里面同时定义的有一个ActivityFragmentLifecycle生命周期监听:
class ActivityFragmentLifecycle implements Lifecycle {
private final Set<LifecycleListener> lifecycleListeners =
Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
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();
}
}
}
看到这里基本上可以知道,创建这个Fragment其实就是为了对这个加载图片请求进行生命周期绑定的,因为Glide不能单单通过传进来的activity就判断生命周期走到了哪里;但是如果在activity上面加载一个fragment进行检测不是就能检测到生命周期运动,同时对Glide的加载做响应改变了嘛。
最后 Glide同时把Fragment和RequestManager进行的绑定:current.setRequestManager(requestManager);
这里可以看到Glide.with()方法主要是为了了生成一个RequestManager实现Glide与相关Context生命周期的绑定工作。
接下来 Glide.with().load(url);进行url的加载,查看RequestManager类的load方法:
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
@NonNull
@CheckResult
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
@NonNull
@CheckResult
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
最终会调用到RequestBuilder类中的创建方法,进入到RequestBuilder中:
protected RequestBuilder(
@NonNull Glide glide,
RequestManager requestManager,
Class<TranscodeType> transcodeClass,
Context context) {
this.glide = glide;
this.requestManager = requestManager;
this.transcodeClass = transcodeClass;
this.context = context;
this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
this.glideContext = glide.getGlideContext();
initRequestListeners(requestManager.getDefaultRequestListeners());// 加载的监听
apply(requestManager.getDefaultRequestOptions());
}
通过RequestBuilder构建者模式初始化一些常量参数以及加载的监听;requestManager即为上一步Glide().with()方法生成的requestManager,transcodeClass则为asDrawable()传进来的Drawable.class;这边我们先主要看下requestManager.getDefaultTransitionOptions(transcodeClass)方法生成的transitionOptions是做什么的?进入到RequestManager类的getDefaultTransitionOptions方法:
@NonNull
<T> TransitionOptions<?, T> getDefaultTransitionOptions(Class<T> transcodeClass) {
return glide.getGlideContext().getDefaultTransitionOptions(transcodeClass);
}
glide.getGlideContext()获取到GildeContext类,进入GildeContext类中:
public GlideContext(
@NonNull Context context,
@NonNull ArrayPool arrayPool,
@NonNull Registry registry,
@NonNull ImageViewTargetFactory imageViewTargetFactory,
@NonNull RequestOptionsFactory defaultRequestOptionsFactory,
@NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions,
@NonNull List<RequestListener<Object>> defaultRequestListeners,
@NonNull Engine engine,
boolean isLoggingRequestOriginsEnabled,
int logLevel) {
super(context.getApplicationContext());
this.arrayPool = arrayPool;
this.registry = registry;
this.imageViewTargetFactory = imageViewTargetFactory;
this.defaultRequestOptionsFactory = defaultRequestOptionsFactory;
this.defaultRequestListeners = defaultRequestListeners;
this.defaultTransitionOptions = defaultTransitionOptions;
this.engine = engine;
this.isLoggingRequestOriginsEnabled = isLoggingRequestOriginsEnabled;
this.logLevel = logLevel;
}
static final TransitionOptions<?, ?> DEFAULT_TRANSITION_OPTIONS =
new GenericTransitionOptions<>();
private final Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions;
@NonNull
public <T> TransitionOptions<?, T> getDefaultTransitionOptions(@NonNull Class<T> transcodeClass) {
TransitionOptions<?, ?> result = defaultTransitionOptions.get(transcodeClass);
if (result == null) {
for (Entry<Class<?>, TransitionOptions<?, ?>> value : defaultTransitionOptions.entrySet()) {
if (value.getKey().isAssignableFrom(transcodeClass)) {
result = value.getValue();
}
}
}
if (result == null) {
result = DEFAULT_TRANSITION_OPTIONS;
}
return (TransitionOptions<?, T>) result;
}
可以看到getDefaultTransitionOptions方法主要想从维护GlideContext维护的defaultTransitionOptions map中获取获取TransitionOptions实列,否则则取默认的TransitionOptions实例;那么TransitionOptions是干嘛的呢?
/**
* A base class for setting a transition to use on a resource when a load completes.
*
* @param <CHILD> The implementation of this class to return to chain methods.
* @param <TranscodeType> The type of resource that will be animated.
*/
public abstract class TransitionOptions<
CHILD extends TransitionOptions<CHILD, TranscodeType>, TranscodeType>
implements Cloneable {
A base class for setting a transition to use on a resource when a load completes.
意思大概就是对资源加载转换的一个工具,个人认为类似于解码器东西;
同时RequestBuilder的构建方法会调用到apply(requestManager.getDefaultRequestOptions())方法;
@NonNull
@CheckResult
@Override
public RequestBuilder<TranscodeType> apply(@NonNull BaseRequestOptions<?> requestOptions) {
Preconditions.checkNotNull(requestOptions);
return super.apply(requestOptions);
}
@NonNull
@CheckResult
public T apply(@NonNull BaseRequestOptions<?> o) {
if (isAutoCloneEnabled) {
return clone().apply(o);
}
BaseRequestOptions<?> other = o;
if (isSet(other.fields, SIZE_MULTIPLIER)) {
sizeMultiplier = other.sizeMultiplier;
}
if (isSet(other.fields, USE_UNLIMITED_SOURCE_GENERATORS_POOL)) {
useUnlimitedSourceGeneratorsPool = other.useUnlimitedSourceGeneratorsPool;
}
if (isSet(other.fields, USE_ANIMATION_POOL)) {
useAnimationPool = other.useAnimationPool;
}
if (isSet(other.fields, DISK_CACHE_STRATEGY)) {
diskCacheStrategy = other.diskCacheStrategy;
}
if (isSet(other.fields, PRIORITY)) {
priority = other.priority;
}
if (isSet(other.fields, ERROR_PLACEHOLDER)) {
errorPlaceholder = other.errorPlaceholder;
errorId = 0;
fields &= ~ERROR_ID;
}
if (isSet(other.fields, ERROR_ID)) {
errorId = other.errorId;
errorPlaceholder = null;
fields &= ~ERROR_PLACEHOLDER;
}
if (isSet(other.fields, PLACEHOLDER)) {
placeholderDrawable = other.placeholderDrawable;
placeholderId = 0;
fields &= ~PLACEHOLDER_ID;
}
if (isSet(other.fields, PLACEHOLDER_ID)) {
placeholderId = other.placeholderId;
placeholderDrawable = null;
fields &= ~PLACEHOLDER;
}
if (isSet(other.fields, IS_CACHEABLE)) {
isCacheable = other.isCacheable;
}
if (isSet(other.fields, OVERRIDE)) {
overrideWidth = other.overrideWidth;
overrideHeight = other.overrideHeight;
}
if (isSet(other.fields, SIGNATURE)) {
signature = other.signature;
}
if (isSet(other.fields, RESOURCE_CLASS)) {
resourceClass = other.resourceClass;
}
if (isSet(other.fields, FALLBACK)) {
fallbackDrawable = other.fallbackDrawable;
fallbackId = 0;
fields &= ~FALLBACK_ID;
}
if (isSet(other.fields, FALLBACK_ID)) {
fallbackId = other.fallbackId;
fallbackDrawable = null;
fields &= ~FALLBACK;
}
if (isSet(other.fields, THEME)) {
theme = other.theme;
}
if (isSet(other.fields, TRANSFORMATION_ALLOWED)) {
isTransformationAllowed = other.isTransformationAllowed;
}
if (isSet(other.fields, TRANSFORMATION_REQUIRED)) {
isTransformationRequired = other.isTransformationRequired;
}
if (isSet(other.fields, TRANSFORMATION)) {
transformations.putAll(other.transformations);
isScaleOnlyOrNoTransform = other.isScaleOnlyOrNoTransform;
}
if (isSet(other.fields, ONLY_RETRIEVE_FROM_CACHE)) {
onlyRetrieveFromCache = other.onlyRetrieveFromCache;
}
// Applying options with dontTransform() is expected to clear our transformations.
if (!isTransformationAllowed) {
transformations.clear();
fields &= ~TRANSFORMATION;
isTransformationRequired = false;
fields &= ~TRANSFORMATION_REQUIRED;
isScaleOnlyOrNoTransform = true;
}
fields |= other.fields;
options.putAll(other.options);
return selfOrThrowIfLocked();
}
这里看到对用户设置的相关内容进行了赋值操作,例如placeholderId 、overrideWidth 、overrideHeight等。
接下来的RequestBuilder的load()方法同样传参并进行了赋值设置;
@NonNull
@Override
@CheckResult
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;
}
到这里可以看到Glide在调用到load(url)的时候主要对相关用户定义的参数进行了设置;
本篇文章先讲到这里,我们对Glide.with().load(url)进行了梳理,总结下主要做了哪些工作:
1 获取RequestManager创建RequestFragment从而对Glide的生命周期进行管理;
2 初始化相关的数据信息以及参数;
下面同时通过UML图简单查看相关使用过的类:
零星瓢虫_001.png接下来我们将继续在探究Glide的运行原理(2)
)中接着对Glide.with().load(url).into(view)的into方法进行梳理
网友评论