概述
Glide 是这几年关注度比较高的图片加载框架。它涉及到生命周期管理、网络加载、图片解析、缓存与显示等内容。这篇文章就从源码出发,从生命周期管理、数据加载等方面来分析分析Glide的一些原理。然后讲一讲一些基本用法。
Glide源码:Glide
一、生命周期管理
还是老规矩,从最简单的使用作为切入:
Glide.with(this)
.load(url)
.into(glideImage);
这是最简单的使用方式,而且又是一个链式结构。我们知道,图片加载过程中若页面退出,按理说是需要在Activity或者 Fragment的生命周期方法里调用停止图片加载相应方法的。但 Glide却不需要这样做,那么它是怎么管理加载的生命周期的呢?我们点进上面 Glide.with()这个方法,看它如何管理生命周期。
//Glide.java
@NonNull
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
// RequestManagerRetriever.java
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
frameWaiter.registerSelf(activity);
FragmentManager fm = activity.getSupportFragmentManager();
// 注释 1 supportFragmentGet() 方法
return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
Glide.with() 方法有好几个重载方法,
参数可以传 Activity 、Fragment 、Context,这里不建议传 Context作为参数,因为最终可能会使得加载的生命周期与 Application同步。这点就不做分析了,可看 Context参数的重载方法。这里我们以 Activity 作为参数的方法展开讲讲。
看上面注释 1处的地方,获取了 FragmentManager 对象作为参数,在方法返回处调用了 supportFragmentGet()方法,我们点进这个方法看一下:
// RequestManagerRetriever.java
@NonNull
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
// 注释 2,创建一个 Fragment 通过 FragmentManager 绑定 Activity
SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
// 注释 3,创建 RequestManager 对象(Lifecycle 对象作为参数)
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
......
current.setRequestManager(requestManager);
}
return requestManager;
}
我们可以看到,上面贴出来的这些方法的返回值都是 RequestManager 。上面代码注释 2和注释 3标注了两个重要的地方,注释 2处在getSupportRequestManagerFragment()方法里,创建了一个Fragment,并用 FragmentManager 与Activity绑定。这样 新创建的Fragment就可以感知 Activity的生命周期,进而对图片加载的生命周期进行管理。我们可以点进 getSupportRequestManagerFragment() 方法看一下:
// RequestManagerRetriever.java
private SupportRequestManagerFragment getSupportRequestManagerFragment(
@NonNull final FragmentManager fm, @Nullable Fragment parentHint) {
SupportRequestManagerFragment current =
(SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
current = new SupportRequestManagerFragment();
current.setParentFragmentHint(parentHint);
pendingSupportRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
看到这里我们需要看一下这个新建的 SupportRequestManagerFragment 的一些源码,看看它生命周期管理的工具 Lifecycle:
// RequestManagerFragment .java
public class RequestManagerFragment extends Fragment {
private static final String TAG = "RMFragment";
private final ActivityFragmentLifecycle lifecycle;
......
RequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
......
ActivityFragmentLifecycle getGlideLifecycle() {
return lifecycle;
}
......
@Override
public void onStart() {
super.onStart();
// 注释 4,在 Fragment 生命周期回调方法里,调用生命周期管理器 lifecycle管理加载生命周期
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
// 注释 5,在 Fragment 生命周期回调方法里,调用生命周期管理器 lifecycle管理加载生命周期
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
// 注释 6,在 Fragment 生命周期回调方法里,调用生命周期管理器 lifecycle管理加载生命周期
lifecycle.onDestroy();
unregisterFragmentWithRoot();
}
}
上面我们看到,注释 4、注释 5、注释 6处,在 Fragment的生命周期分别调用了 生命周期管理对象 lifecycle的相关方法,以管理加载生命周期。最后我们再看一下 ActivityFragmentLifecycle的 onStart() 、onStop()和 onDestroy()方法的实现吧:
// ActivityFragmentLifecycle.java
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的生命周期发生变化,生命周期管理器 Lifecycle就会遍历各个观察者,并调用个观察者的生命周期方法。
好了,我们再回过头来看一下,RequestManager 是怎么把自己注册成Fragment生命周期的观察者的。再看回上面注释 3处:
// RequestManagerRetriever.java
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
这里创建了 RequestManager对象,并且从上面的参数看,Fragment用于生命周期管理的 Lifecycle也作为参数传给了 RequestManager。我们先看看 上面build()方法做了啥:
// RequestManagerRetriever.java
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) {
//注释 7 创建 RequestManager对象
return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
}
};
看上面的注释 7处,RequestManager对象终于被创建出来了。我们来看一下 RequestManager类里用于生命周期管理的一些方法和参数:
// RequestManager.java
// 注释 8, RequestManager实现了用于生命周期管理的接口 LifecycleListener,
//并实现了 onStart()、 onStop() 、onDestroy()方法。
public class RequestManager
implements ComponentCallbacks2, LifecycleListener, ModelTypes<RequestBuilder<Drawable>> {
......
final Lifecycle lifecycle;
......
private final Runnable addSelfToLifecycle =
new Runnable() {
@Override
public void run() {
// 注释 10,将当前对象注册为观察者
lifecycle.addListener(RequestManager.this);
}
};
......
RequestManager(
Glide glide,
// 注释 9,构造器里传进 Fragment生命周期管理对象 Lifecycle
Lifecycle lifecycle,
RequestManagerTreeNode treeNode,
RequestTracker requestTracker,
ConnectivityMonitorFactory factory,
Context context) {
this.glide = glide;
this.lifecycle = lifecycle;
}
......
@Override
public synchronized void onStart() {
// 注释 11,执行加载生命周期
resumeRequests();
targetTracker.onStart();
}
@Override
public synchronized void onStop() {
// 注释 12,执行加载生命周期
pauseRequests();
targetTracker.onStop();
}
@Override
public synchronized void onDestroy() {
// 注释 13,执行加载生命周期
targetTracker.onDestroy();
for (Target<?> target : targetTracker.getAll()) {
clear(target);
}
targetTracker.clear();
requestTracker.clearRequests();
lifecycle.removeListener(this);
lifecycle.removeListener(connectivityMonitor);
Util.removeCallbacksOnUiThread(addSelfToLifecycle);
glide.unregisterRequestManager(this);
}
可以看到上面注释 8处, RequestManager实现了生命周期的接口 LifecycleListener,并实现了 onStart()、 onStop() 、onDestroy()方法。注释 10的地方用 Fragment传过来的 lifecycle将当前 RequestManager对象注册成 Fragment生命周期的观察者。上面分析过,Fragment的生命周期发生改变时,lifecycle对象就会遍历所有观察者,然后调用观察者相应的生命周期的方法,也就是上面注释 11、注释 12、注释 13处的 onStart()、 onStop() 、onDestroy()方法。从而达到框架图片加载生命周期与 Fragment(或者说 Activity)同步的目的。这样我们使用 Glide时就不用手动管理生命周期啦~
二、数据逐级加载
*内存缓存
下面我们来看数据加载。因为 RequestManager.load()方法只是将路径保存,所以我们往下看 RequestBuilder.into() 方法。
// RequestBuilder.java
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
......
// 打包 request
Request request = buildRequest(target, targetListener, options, callbackExecutor);
......
requestManager.clear(target);
target.setRequest(request);
// target 和 request 往下执行
requestManager.track(target, request);
return target;
}
// RequestBuilder.java
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
// 执行请求
requestTracker.runRequest(request);
}
// RequestTracker.java
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
// 开始执行 request
request.begin();
} else {
......
}
}
// SingleRequest.java
public void begin() {
synchronized (requestLock) {
......
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
// 尺寸已经准备好,进行下一步加载
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
......
}
}
// SingleRequest.java
public void onSizeReady(int width, int height) {
synchronized (requestLock) {
......
loadStatus =
// 启动 Engine.java 的 load方法
engine.load(
......
......
);
......
}
}
// Engine.java
public <R> Engine.LoadStatus load(
......
) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
// 生成 key值 ,从缓存中取
EngineKey key =
keyFactory.buildKey(
......
);
EngineResource<?> memoryResource;
synchronized (this) {
// 注释 14, 从内存缓存中取数据
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
// 注释 15,上一步内存获取的数据为空,尝试从下一级缓存中获取
if (memoryResource == null) {
return waitForExistingOrStartNewJob(
......
);
}
}
cb.onResourceReady(
memoryResource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
return null;
}
上面一路追踪到了 Engine.load() 方法。数据加载时逐级从缓存中加载的,包括内存缓存、磁盘缓存、网络加载等等在内。上面注释 14是先从内存缓存中尝试获取数据,如果没有,则到上面注释 15 处往下级缓存中寻找。现在我们先看一下注释 14处内存缓存的取法:
// Engine.java
private EngineResource<?> loadFromMemory(
EngineKey key, boolean isMemoryCacheable, long startTime) {
// 注释16, 从弱引用缓存中获取资源
EngineResource<?> active = loadFromActiveResources(key);
if (active != null) {
return active;
}
// 注释 17, LRU 缓存
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return cached;
}
return null;
}
从上面注释 16、注释 17中可以看到,内存缓存又分为两级,一级是从弱引用使用过的资源中加载,没有的话第二级再从LRU内存缓存中获取。下面我们来看看 LRU内存缓存:
// Engine.java
private EngineResource<?> loadFromMemory(
EngineKey key, boolean isMemoryCacheable, long startTime) {
// 弱引用缓存
EngineResource<?> active = loadFromActiveResources(key);
if (active != null) {
return active;
}
// LRU 缓存
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return cached;
}
return null;
}
// Engine.java
private EngineResource<?> loadFromCache(Key key) {
// 内存缓存
EngineResource<?> cached = getEngineResourceFromCache(key);
.......
return cached;
}
// Engine.java
private EngineResource<?> getEngineResourceFromCache(Key key) {
// 注释 18, cached 的实现类是 LruResourceCache
Resource<?> cached = cache.remove(key);
.......
return result;
}
上面一路追踪到了注释 18 的地方,cached 的实现类是 LruResourceCache。现在我们看看这个 LRU缓存实现类 LruResourceCache以及它的父类 LruCache:
// LruResourceCache.java
public class LruResourceCache extends LruCache<Key, Resource<?>> implements MemoryCache {
private ResourceRemovedListener listener;
public LruResourceCache(long size) {
// 看父类 LruCache
super(size);
}}
// LruCache.java
public class LruCache<T, Y> {
// 注释 19, Lru 内存缓存,使用 LinkedHashMap保存对象
private final Map<T, com.bumptech.glide.util.LruCache.Entry<Y>> cache = new LinkedHashMap<>(100, 0.75f, true);
// 缓存数量
protected synchronized int getCount() {
return cache.size();
}
// 根据 key 取缓存数据
public synchronized Y get(@NonNull T key) {
com.bumptech.glide.util.LruCache.Entry<Y> entry = cache.get(key);
return entry != null ? entry.value : null;
}
// 保存数据
public synchronized Y put(@NonNull T key, @Nullable Y item) {
final int itemSize = getSize(item);
LruCache.Entry<Y> old = cache.put(key, item == null ? null : new com.bumptech.glide.util.LruCache.Entry<>(item, itemSize));
return old != null ? old.value : null;
}
// 注释20, 移除最近最少使用的数据 (LRU)
protected synchronized void trimToSize(long size) {
Map.Entry<T, com.bumptech.glide.util.LruCache.Entry<Y>> last;
Iterator<Map.Entry<T, com.bumptech.glide.util.LruCache.Entry<Y>>> cacheIterator;
while (currentSize > size) {
cacheIterator = cache.entrySet().iterator();
last = cacheIterator.next();
final com.bumptech.glide.util.LruCache.Entry<Y> toRemove = last.getValue();
currentSize -= toRemove.size;
final T key = last.getKey();
cacheIterator.remove();
onItemEvicted(key, toRemove.value);
}
}
}
看到上面应该就一目了然了,注释 19 处用一个 LinkedHashMap对象来保存内存缓存数据,这里有 get和 put方法分别用于读写数据。注释 20处,当数据量过大超过设置长度时,会移除最近最少使用的数据 (LRU)。
*磁盘缓存及网络加载
上面分析完了内存缓存,下面我们继续分析磁盘加载及网络加载。回到上面注释 15 的地方:
// Engine.java
public <R> Engine.LoadStatus load(
......
) {
.......
EngineResource<?> memoryResource;
synchronized (this) {
// 注释 14, 从内存缓存中取数据
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
// 注释 15,上一步内存获取的数据为空,尝试从下一级缓存中获取
if (memoryResource == null) {
return waitForExistingOrStartNewJob(
......
);
}
}
cb.onResourceReady(
memoryResource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
return null;
}
下面继续往下看 waitForExistingOrStartNewJob() 这个方法:
// Engine.java
private <R> Engine.LoadStatus waitForExistingOrStartNewJob(
......
......
) {
DecodeJob<R> decodeJob =
decodeJobFactory.build(
......
......
);
......
// 看start方法
engineJob.start(decodeJob);
return new Engine.LoadStatus(cb, engineJob);
}
// EngineJob.java
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
//注释 21, GlideExecutor是一个线程池,那么 DecodeJob必然是一个 Runnable ,我们可以点进去看一下
GlideExecutor executor =
decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
// 注释 22, 执行 Runnable
executor.execute(decodeJob);
}
看上面注释21 GlideExecutor 是一个线程池,注释 22执行了线程池 execute()方法。那么,DecodeJob对象必然是一个 Runnable对象,我们可以点进去看一看:
// DecodeJob.java
class DecodeJob<R>
implements DataFetcherGenerator.FetcherReadyCallback,
Runnable,
Comparable<com.bumptech.glide.load.engine.DecodeJob<?>>,
FactoryPools.Poolable {
public void run() {
runWrapped();
}
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
stage = getNextStage(com.bumptech.glide.load.engine.DecodeJob.Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
// 磁盘缓存
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
}
上面的 Runnable对象的run方法执行了相关的任务逻辑,这里面有多种缓存形式。我们看一下这个 DataCacheGenerator磁盘缓存及网络加载的相关的逻辑:
// DataCacheGenerator.java
public boolean startNext() {
while (modelLoaders == null || !hasNextModelLoader()) {
sourceIdIndex++;
if (sourceIdIndex >= cacheKeys.size()) {
return false;
}
Key sourceId = cacheKeys.get(sourceIdIndex);
Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
cacheFile = helper.getDiskCache().get(originalKey);
if (cacheFile != null) {
this.sourceKey = sourceId;
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
}
}
boolean started = false;
while (!started && hasNextModelLoader()) {
// 注释 23, 逐级缓存获取
// 循环从 modelLoaders中获取对应的加载数据的 ModelLoader
// ModelLoader 用于加载数据,它有多个子类,分别用于本地资源加载和网络加载等等
ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
// 注释24, 获取对应的 LoadData,如果获取不到,则 started == false,进入下一次循环
loadData =
modelLoader.buildLoadData(
cacheFile, helper.getWidth(), helper.getHeight(), helper.getOptions());
if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
started = true;
//注释 25, 调用对用的 Fetcher 来获取数据
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
上面这个 startNext()方法实现了主要逻辑。注释 23处使用了while 循环逐级获取数据。当加载数据的 LoadData 对象为空时,started 为 false,走进下一次循环。ModelLoader 用于加载数据,它有多个子类,分别用于本地资源加载和网络加载等。一旦从磁盘缓存中加载不到数据,就会切换到网络加载的线程池进行网络加载。下面我们来看看最后网络加载的 ModelLoader实现类 HttpGlideUrlLoader以及其对应的 HttpUrlFetcher实现的加载逻辑。
根据上面注释 24和 注释 25的顺序,我们先看获取 LoadData 对象的 HttpGlideUrlLoader.buildLoadData() 方法,再看一下注释 25处 HttpUrlFetcher调用的 loadData()方法。
// HttpGlideUrlLoader .java
public class HttpGlideUrlLoader implements ModelLoader<GlideUrl, InputStream> {
public static final Option<Integer> TIMEOUT =
Option.memory("com.bumptech.glide.load.model.stream.HttpGlideUrlLoader.Timeout", 2500);
@Nullable private final ModelCache<GlideUrl, GlideUrl> modelCache;
public HttpGlideUrlLoader() {
this(null);
}
public HttpGlideUrlLoader(@Nullable ModelCache<GlideUrl, GlideUrl> modelCache) {
this.modelCache = modelCache;
}
@Override
public LoadData<InputStream> buildLoadData(
@NonNull GlideUrl model, int width, int height, @NonNull Options options) {
// GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time
// spent parsing urls.
GlideUrl url = model;
if (modelCache != null) {
url = modelCache.get(model, 0, 0);
if (url == null) {
modelCache.put(model, 0, 0, model);
url = model;
}
}
int timeout = options.get(TIMEOUT);
// 注释 26, 返回 LoadData对象,Fetcher是 HttpUrlFetcher
return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
}
}
上面注释 26 是返回 LoadData对象的地方,网络加载的 Fetcher实现类是 HttpUrlFetcher。下面我们就看看 HttpUrlFetcher的loadData()方法是如何从网络上加载数据的吧:
public class HttpUrlFetcher implements DataFetcher<InputStream> {
private static final String TAG = "HttpUrlFetcher";
private static final int MAXIMUM_REDIRECTS = 5;
private HttpURLConnection urlConnection;
private InputStream stream;
private volatile boolean isCancelled;
@Override
public void loadData(
@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
// 注释 27,获取输入流 InputStream 然后回调结果
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
callback.onDataReady(result);
} catch (IOException e) {
} finally {
}
}
}
private InputStream loadDataWithRedirects(
URL url, int redirects, URL lastUrl, Map<String, String> headers) throws HttpException {
......
// 获取 HttpURLConnection
urlConnection = buildAndConfigureConnection(url, headers);
try {
// 连接
urlConnection.connect();
stream = urlConnection.getInputStream();
} catch (IOException e) {
throw new HttpException(
"Failed to connect or obtain data", getHttpStatusCodeOrInvalid(urlConnection), e);
}
......
final int statusCode = getHttpStatusCodeOrInvalid(urlConnection);
if (isHttpOk(statusCode)) {
// 返回 InputStream
return getStreamForSuccessfulRequest(urlConnection);
} else if (isHttpRedirect(statusCode)) {
}
}
// 获取 HttpURLConnection
private HttpURLConnection buildAndConfigureConnection(URL url, Map<String, String> headers)
throws HttpException {
HttpURLConnection urlConnection;
try {
urlConnection = connectionFactory.build(url);
} catch (IOException e) {
throw new HttpException("URL.openConnection threw", /*statusCode=*/ 0, e);
}
for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
}
urlConnection.setConnectTimeout(timeout);
urlConnection.setReadTimeout(timeout);
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
urlConnection.setInstanceFollowRedirects(false);
return urlConnection;
}
}
上面这个类贴出了主要方法,看注释27.这个类应该就比较简单了,创建一个 HttpURLConnection 连接,然后获取输入流再回调。
三、Glide的一些常见用法
- 设置加载尺寸
Glide.with(this)
.load(url)
// 设置宽高
.override(800, 800)
.into(glideImage);
- 设置加载过程中及加载错误时现实的图片
Glide.with(this)
.load(url)
// 加载中显示的图片
.placeholder(R.mipmap.ic_launcher)
// 加载错误后显示的图片
.error(R.mipmap.ic_launcher)
.into(glideImage);
- 显示缩略图
Glide.with(this)
.load(url)
// 显示缩略图
.thumbnail(0.1f)
.into(glideImage);
- 静态图和动态图
Glide.with(this)
// 静态图
.asBitmap()
.load(url)
.into(glideImage);
Glide.with(this)
// 动态图
.asGif()
.load(url)
.into(glideImage);
- 图片显示样式
Glide.with(this)
.load(url)
// 裁剪图片将imageView填满
.centerCrop()
.into(glideImage);
Glide.with(this)
.load(url)
// 将图像全显示出来
.fitCenter()
.into(glideImage);
- 处理一下图片再显示
Glide.with(this)
.load(url)
.into(new CustomTarget<Drawable>() {
@Override
public void onResourceReady(@NonNull @org.jetbrains.annotations.NotNull Drawable resource, @Nullable @org.jetbrains.annotations.Nullable Transition<? super Drawable> transition) {
// 处理一下 resource 再显示
glideImage.setImageDrawable(resource);
}
@Override
public void onLoadCleared(@Nullable @org.jetbrains.annotations.Nullable Drawable placeholder) {
}
});
- 磁盘缓存设置
Glide.with(this)
.load(url)
// 设置磁盘缓存策略
// DiskCacheStrategy.NONE:不缓存任何图片,即禁用磁盘缓存
// DiskCacheStrategy.ALL :缓存原始图片 & 转换后的图片(默认)
// DiskCacheStrategy.SOURCE:只缓存原始图片(原来的全分辨率的图像,即不缓存转换后的图片)
// DiskCacheStrategy.RESULT:只缓存转换后的图片(即最终的图像:降低分辨率后 / 或者转换后 ,不缓存原始图片
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(glideImage);
- 设置是否跳过内存缓存
Glide.with(this)
.load(url)
// 设置是否跳过内存缓存
.skipMemoryCache(true)
.into(glideImage);
- 清理缓存
Glide.get(this).clearDiskCache();//清理磁盘缓存 需要在子线程中执行
Glide.get(this).clearMemory();//清理内存缓存 可以在UI主线程中进行
- 设置下载优先级
Glide.with(this)
.load(url)
// 设置下载优先级
.priority(Priority.NORMAL)
.into(glideImage);
- 变换
Glide.with(this)
.load(url)
// 变换
.transform(new MultiTransformation<>())
.into(glideImage);
网友评论