前言:前面解析Glide源码已有两篇文章《Glide源码顺藤摸瓜之with和load主线
》和《Glide源码顺藤摸瓜之into主线》,它们已经把Glide的三条主线都摸透了。现在剩下些边角料,我们可以捋一捋。
一、Glide如何切换为子线程请求数据?
这一题好答,简直就是送分题啦。看过前面的源码解析的,或者看过源码的就知道。
在Engin.load()方法中,如果在活动缓存和内存缓存中没有获取到数据,就会调用waitForExistingOrStartNewJob()方法,在waitForExistingOrStartNewJob()方法中,将调用engineJob.start(decodeJob); 而这里就是切换线程的地方。
但是我们需要区分的是EngineJob并没有继承Runnable,它主要用来管理DecodeJob执行后,数据回调相关。而DecodeJob则继承至Runnable,它将处理从磁盘缓存中获取缓存数据和通过网络获取数据的逻辑。
EngineJob.java
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor =
decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
executor.execute(decodeJob);
}
二、Glide通过网络请求获取数据后怎么缓存磁盘的?
在《Glide源码顺藤摸瓜之into主线》一文中的 《四、获取数据后回调显示》一节中,我们说了获取数据后的回调路径。我们可以看到5. DecodeJob.notifyEncodeAndRelease()
DecodeJob.java
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
...
try {
if (deferredEncodeManager.hasResourceToEncode()) {
deferredEncodeManager.encode(diskCacheProvider, options);
}
}
}
void encode(DiskCacheProvider diskCacheProvider, Options options) {
try {
1. diskCacheProvider
.getDiskCache()
.put(key, new DataCacheWriter<>(encoder, toEncode, options));
}
}
- diskCacheProvider.getDiskCache()实际上返回的是DiskLruCacheWrapper实例。调用它的put()方法。
DiskLruCacheWrapper.java
public void put(Key key, Writer writer) {
String safeKey = safeKeyGenerator.getSafeKey(key);
try {
DiskLruCache diskCache = getDiskCache();
Value current = diskCache.get(safeKey);
if (current != null) {
return;
}
DiskLruCache.Editor editor = diskCache.edit(safeKey);
try {
File file = editor.getFile(0);
if (writer.write(file)) {
editor.commit();
}
}
...
} finally {
writeLocker.release(safeKey);
}
}
- 在DiskLruCacheWrapper.put()方法中,调用了DiskLruCache.Editor。通过commit提交并缓存到磁盘。
三、Glide获取图片数据后如何切换为主线程渲染?
3.1 这里先说下主线程的创建,这里前文也已经说过了,
- 在RequestBuilder.java中的into方法中:
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
...
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
Executor.java
private static final Executor MAIN_THREAD_EXECUTOR =
new Executor() {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(@NonNull Runnable command) {
handler.post(command);
}
};
- 中间传递过程就不说,它最终会一层一层传递到EngineJob中。engineJob.addCallback(cb, callbackExecutor); 它将被实例化为一个ResourceCallbackAndExecutor对象并add到cbs集合中。
EngineJob.java
synchronized void addCallback(final ResourceCallback cb, Executor callbackExecutor) {
...
cbs.add(cb, callbackExecutor);
...
}
void add(ResourceCallback cb, Executor executor) {
callbacksAndExecutors.add(new ResourceCallbackAndExecutor(cb, executor));
}
3.2 在《Glide源码顺藤摸瓜之into主线》一文中的 《四、获取数据后回调显示》一节中,我们说了获取数据后的回调路径。我们可以看到8. EngineJob.notifyCallbacksOfResult()(261行 entry.executor.execute(new CallResourceReady(entry.cb)))
我们可以看到代码中的1. entry.executor.execute();使用entry中的executor执行线程,而entry就是ResourceCallbackAndExecutor ,而它里面的executor正好是我们3.1中提到的 Executors.mainThreadExecutor()。
很明显它是在这里切换到了主线程。
void notifyCallbacksOfResult() {
ResourceCallbacksAndExecutors copy;
...
copy = cbs.copy();
...
for (final ResourceCallbackAndExecutor entry : copy) {
1. entry.executor.execute(new CallResourceReady(entry.cb));
}
}
四、Glide的三级缓存如何交互?
Glide中的缓存呢,有三级缓存:活动缓存、内存缓存和磁盘缓存。
4.1 先说说活动缓存和内存缓存。
- 4.1.1 当我们使用Glide加载图片,最后一步调用into()方法时,它最终会创建SingleRequest对象并调用到Engine.load()方法来。他首先通过loadFromMemory()方法去活动缓存和内存缓存中找。
Engine.java
public <R> LoadStatus load(...) {
EngineKey key =
keyFactory.buildKey(
model,
signature,
width,
height,
transformations,
resourceClass,
transcodeClass,
options);
EngineResource<?> memoryResource;
synchronized (this) {
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
if (memoryResource == null) {
return waitForExistingOrStartNewJob(
glideContext,
...
startTime);
}
}
...
}
- 4.1.2. 从缓存中获取数据,如果获取到了就将缓存资源回调给SingleRequest。它将先从活动缓存中取,取不到再去内存缓存中获取。
这里活动缓存ActiveResources:内部使用一个Map缓存这资源弱引用,Map<Key, ResourceWeakReference> activeEngineResources;
若是没有从活动缓存中获取数据,则会去内存缓存中获取,如果找到会直接从内存缓存中移除掉,并存入活动缓存中。cache.remove(key) > activeResources.activate(key, cached)
Engine.java
private EngineResource<?> loadFromMemory(
EngineKey key, boolean isMemoryCacheable, long startTime) {
EngineResource<?> active = loadFromActiveResources(key);
if (active != null) {
return active;
}
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
return cached;
}
return null;
}
private EngineResource<?> loadFromActiveResources(Key key) {
EngineResource<?> active = activeResources.get(key);
if (active != null) {
active.acquire();
}
return active;
}
private EngineResource<?> loadFromCache(Key key) {
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
cached.acquire();
activeResources.activate(key, cached);
}
return cached;
}
4.2 而说到磁盘缓存,它是在活动缓存和内存缓存中没有找到之后,执行了DecodeJob时触发。其实磁盘缓存内又分为两种:1、已经进行了采样转换过的资源;2、没有进行过处理的原始资源。
在DecodeJob中,这几种情况由相关Generator来处理:
- ResourceCacheGenerator:寻找进行了采样转换过的资源
- DataCacheGenerator:寻找没有进行过处理的原始资源
- SourceGenerator:进行网络请求获取网络资源
DecodeJob.java
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);
}
}
这在《Glide源码顺藤摸瓜之into主线》一文中有详解。
五、Glide如何监控内存?
一个应用的内存管理其实最好的方式是将自己注册到系统中,继承它的接口,但内存紧张或者变动的时候,系统会回调通知给应用程序。而Glide也是如此。
5.1 内存监听的接口
内存监听系统有标准的接口ComponentCallbacks2,而它继承至ComponentCallbacks。
- onTrimMemory()回调的是内存的使用等级;
- onLowMemory() 在整个系统内存不足的时候调用,这时进程需要减少它们的内存使用。
public interface ComponentCallbacks2 extends ComponentCallbacks {
void onTrimMemory(@TrimMemoryLevel int level);
}
public interface ComponentCallbacks {
void onLowMemory();
}
5.2 在Glide.java中,它也继承了ComponentCallbacks2
public class Glide implements ComponentCallbacks2 {
@Override
public void onTrimMemory(int level) {
trimMemory(level);
}
public void trimMemory(int level) {
for (RequestManager manager : managers) {
1. manager.onTrimMemory(level);
}
2. memoryCache.trimMemory(level);
bitmapPool.trimMemory(level);
arrayPool.trimMemory(level);
}
@Override
public void onLowMemory() {
clearMemory();
}
public void clearMemory() {
3. memoryCache.clearMemory();
bitmapPool.clearMemory();
arrayPool.clearMemory();
}
}
- 第1点:系统调用了onTrimMemory(level)传递了内存使用级别后,Glide会传递给RequestManager。并调用RequestManager的onTrimMemory()方法。它将会根据内存使用级别的不同来决定是否需要暂停资源请求。这里级别为TRIM_MEMORY_MODERATE(60)的时候暂停。
RequestManager.java
@Override
public void onTrimMemory(int level) {
if (level == TRIM_MEMORY_MODERATE && pauseAllRequestsOnTrimMemoryModerate) {
pauseAllRequestsRecursive();
}
}
public synchronized void pauseAllRequestsRecursive() {
pauseAllRequests();
for (RequestManager requestManager : treeNode.getDescendants()) {
requestManager.pauseAllRequests();
}
}
public synchronized void pauseAllRequests() {
requestTracker.pauseAllRequests();
}
RequestTracker.java
public void pauseAllRequests() {
isPaused = true;
for (Request request : Util.getSnapshot(requests)) {
if (request.isRunning() || request.isComplete()) {
request.clear();
pendingRequests.add(request);
}
}
}
- 第2点:同时onTrimMemory也会将level传递给memoryCache、bitmapPool和arrayPool等池子。也会根据level做相应的内存优化处理。
- 第3点:onLowMemory则会直接调用clearMemory(),那么memoryCache、bitmapPool和arrayPool缓存池将会被清理。
六、Glide如何监控网络实现重启图片加载?
我们在使用Glide的时候发现它在没有网络的时候会暂停下载,等待有网络的时候呢,又会自动开始资源请求。我们稍稍思考下,它肯定监听了网络,根据监听到的网络情况来控制请求的停启。
6.1 看到GlideBuilder.java中创建Glide实例的时候,它会初始化很多工厂,其他的我们先不看仅仅看到connectivityMonitorFactory ,它确实初始化了一个网格监听器的工厂类,并保存在Glide实例中。
GlideBuilder.java
Glide build(@NonNull Context context) {
...
if (connectivityMonitorFactory == null) {
connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
}
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
return new Glide(
...
connectivityMonitorFactory,
...);
}
6.2 而在初始化RequestManager的时候,调用了ConnectivityMonitorFactory(实际为DefaultConnectivityMonitorFactory)的build方法,构建出了一个网络监听器connectivityMonitor(DefaultConnetivityMonitor),同时RequestManager中的lifecycle将网络监听器加入了listener中,因为connectivityMonitor本身也继承了LifecycleListener。所以它也是能监听生命周期回调的。
RequestManager.java
public RequestManager(...) {
this(...,glide.getConnectivityMonitorFactory(),context);
}
RequestManager(...) {
connectivityMonitor =
factory.build(
context.getApplicationContext(),
new RequestManagerConnectivityListener(requestTracker));
lifecycle.addListener(connectivityMonitor);
...
}
6.3 看到DefaultConnectivityMonitor类,他监听了生命周期onStart/onStop方法,并在方法中register/unregister了广播。当收到网络连接断开的广播后回调listener。
DefaultConnectivityMonitor.java
final class DefaultConnectivityMonitor implements ConnectivityMonitor {
private final BroadcastReceiver connectivityReceiver =
new BroadcastReceiver() {
@Override
public void onReceive(@NonNull Context context, Intent intent) {
listener.onConnectivityChanged(isConnected);
}
}
};
@Override
public void onStart() {
register();
}
@Override
public void onStop() {
unregister();
}
}
6.4 在RequestManager中收到网络连接的回调后,开始继续执行资源请求。
RequestManager.java
private class RequestManagerConnectivityListener
implements ConnectivityMonitor.ConnectivityListener {
@Override
public void onConnectivityChanged(boolean isConnected) {
if (isConnected) {
synchronized (RequestManager.this) {
requestTracker.restartRequests();
}
}
}
}
七、Glide如何根据Activity生命周期开始和暂停请求?
7.1 前面跟踪with主线的时候,在with()方法中。内部实现了一个无UI的Fragment,它将绑定到Activity上。这样就和Activity生命周期进行了关联。
Glide.java
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
RequestManagerRetriever.java
public RequestManager get(@NonNull FragmentActivity activity) {
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
private RequestManager supportFragmentGet(...) {
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
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;
}
7.2 无UI的Fragment有两种:SupportRequestManagerFragment和RequestManagerFragment,它们逻辑没啥区别,只不过前一种是为了适配androidX而已。
它们的构造方法中都构建了一个ActivityFragmentLifecycle对象。
public RequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
RequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
public SupportRequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
7.3 ActivityFragmentLifecycle将在Fragment生命周期方法(主要为onStart、onStop和onDestroy)调起时,通知它的观察者。
RequestManagerFragment.java和SupportRequestManagerFragment.java
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.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();
}
}
7.4 上面说到的ActivityFragmentLifecycle将被传到RequestManager中,而本身RequestManager就是实现了LifecycleListener接口,所以它也是一个ActivityFragmentLifecycle的观察者。
RequestManagerRetriever.java
private RequestManager fragmentGet(...) {
...
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;
}
current.getGlideLifecycle(); current就是RequestManagerFragment或者SupportRequestManagerFragment,getGlideLifecycle()返回的就是ActivityFragmentLifecycle。
7.5 RequestManger会将自己注册到ActivityFragmentLifecycle中,成为它的观察者。
RequestManager.java
RequestManager(Glide glide, Lifecycle lifecycle, ...) {
if (Util.isOnBackgroundThread()) {
...
} else {
lifecycle.addListener(this);
}
...
}
7.6 RequestManager在接受到生命周期回调时,会自动启停资源请求。
RequestManager.java
@Override
public synchronized void onStart() {
resumeRequests();
targetTracker.onStart();
}
public synchronized void resumeRequests() {
requestTracker.resumeRequests();
}
@Override
public synchronized void onStop() {
pauseRequests();
targetTracker.onStop();
}
public synchronized void pauseRequests() {
requestTracker.pauseRequests();
}
7.7 具体的启停操作由RequestTracker来控制
RequestTracker.java
public void resumeRequests() {
for (Request request : Util.getSnapshot(requests)) {
if (!request.isComplete() && !request.isRunning()) {
request.begin();
}
}
pendingRequests.clear();
}
public void pauseRequests() {
for (Request request : Util.getSnapshot(requests)) {
if (request.isRunning()) {
request.pause();
pendingRequests.add(request);
}
}
}
八、结语
Glide框架源码终于爬完了,文章写的要吐了。也好,Glide算是了解透了。