前言:
从事android开发已经四五年了,对第三方库的源码还没有进行多深入的研读,属实有点说不过去。
接下来会对常用的第三方库进行研读,希望有更深入的了解,并希望从源码中能学到东西,同时在读源码的过程中,对知识薄弱的地方进行加强。
文章只是现阶段对源码的解读,自己的一个记录,如果发现有错误的,评论,一起探讨,共同进步。话不多说,现在就开始吧,希望可以一直坚持下去。
首先列下接下来看源码自己的一些流程 1.提出对第三方库不理解的点,感兴趣的点,提出问题,带着问题去看源码 2.在源码中寻找能解决提出问题的答案,然后记录下来 3.根据自己的理解,绘制第三方库的流程图 4.总结,源码中学到的东西进行总结 5.可以再选择一个功能模块进行细看
glide 源码解析 3.7版本
glide作为安卓比较比较受欢迎的图片加载框架,相信你一定对他有一定的了解,今天就从源码开始,对他进行一个解析,加深对他的认识。
问题:
1.如何判断生命周期进行回收 2.如何缓存,使用缓存 3.如何请求网络图片
一、Glide生命周期的监听
先从glide的最简单的使用开始 Glide.with(context).load(url).into(view); 没看源码之前,可能面试上就会问传入的context有什么要求,如果乱用context会导致什么问题 相信一部分人已经知道,content的传入是会影响glide的回收的,如何使用不当,可能会导致内存泄露。那针对第一个问题,glide如何判断生命周期进行回收的,我们就可以从content入手,看glide是如何监控页面生命周期,进行资源回收的
public static RequestManager with(Context context) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(context);
}
public static RequestManager with(Activity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
public static RequestManager with(FragmentActivity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
public static RequestManager with(Fragment fragment) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(fragment);
}
通过上面源码,我们知道Glide.with()方法,有多个重载方法,可以传入Context,Activity,FragmentActivity,Fragment等,而他们返回的RequestManager 都是通过RequestManagerRetriever来实现
以传入Fragment为例,会先拿到传入的FragmentManger,这里是通过getChildFragmentManager获取的,如果是activity则是getSupportFragmentManager
public RequestManager get(Fragment fragment) {
if (fragment.getActivity() == null) {
throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
}
if (Util.isOnBackgroundThread()) {
return get(fragment.getActivity().getApplicationContext());
} else {
FragmentManager fm = fragment.getChildFragmentManager();
return supportFragmentGet(fragment.getActivity(), fm);
}
}
再看下supportFragmentGet的方法
RequestManager supportFragmentGet(Context context, FragmentManager fm) {
SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}
还需要跳到getSupportRequestManagerFragment
SupportRequestManagerFragment getSupportRequestManagerFragment(final FragmentManager fm) {
SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag(
FRAGMENT_TAG);
if (current == null) {
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
current = new SupportRequestManagerFragment();
pendingSupportRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
这里我们可以知道,他是先通过前面获取的fragmentmanager 通过tag,看是否存在 SupportRequestManagerFragment,如果不存在就会new一个,然后通过fragmentManager开启事务添加一个fragment,并设置tag,下次就可以通过tag寻找。接下来我们看看SupportRequestManagerFragment是个什么东西
public class SupportRequestManagerFragment extends Fragment {
private RequestManager requestManager;
private final ActivityFragmentLifecycle lifecycle;
private final RequestManagerTreeNode requestManagerTreeNode =
new SupportFragmentRequestManagerTreeNode();
private final HashSet<SupportRequestManagerFragment> childRequestManagerFragments =
new HashSet<SupportRequestManagerFragment>();
private SupportRequestManagerFragment rootRequestManagerFragment;
public SupportRequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
// For testing only.
@SuppressLint("ValidFragment")
public SupportRequestManagerFragment(ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
...
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
1. public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
}
其实SupportRequestManagerFragment是一个空界面的fragment,至于为什么glide要加一个空的fragment,实际上就是fragment对生命周期进行监控,而又不需要界面展示。
二、Glide的图片加载流程
加载流程就得看load方法了
public DrawableTypeRequest<String> load(String string) {
return (DrawableTypeRequest<String>) fromString().load(string);
}
private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader =
Glide.buildFileDescriptorModelLoader(modelClass, context);
if (modelClass != null && streamModelLoader == null && fileDescriptorModelLoader == null) {
throw new IllegalArgumentException("Unknown type " + modelClass + ". You must provide a Model of a type for"
+ " which there is a registered ModelLoader, if you are using a custom model, you must first call"
+ " Glide#register with a ModelLoaderFactory for your custom model class");
}
return optionsApplier.apply(
new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
glide, requestTracker, lifecycle, optionsApplier));
}
根据不同的加载类型,构建DrawableTypeRequest,然后调用load()方法 DrawableTypeRequest继承至DrawableRequestBuilder,DrawableRequestBuilder继承至GenericRequestBuilder,最终调用GenericRequestBuilder中的load方法
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) {
this.model = model;
isModelSet = true;
return this;
}
这里是返回了自身,我们知道在load()方法后,会调用into方法,在控件上显示图片。
public Target<TranscodeType> into(ImageView view) {
Util.assertMainThread();
if (view == null) {
throw new IllegalArgumentException("You must pass in a non null View");
}
if (!isTransformationSet && view.getScaleType() != null) {
switch (view.getScaleType()) {
case CENTER_CROP:
applyCenterCrop();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
applyFitCenter();
break;
//$CASES-OMITTED$
default:
// Do nothing.
}
}
return into(glide.buildImageViewTarget(view, transcodeClass));
public <Y extends Target<TranscodeType>> Y into(Y target) {
Util.assertMainThread();
if (target == null) {
throw new IllegalArgumentException("You must pass in a non null Target");
}
if (!isModelSet) {
throw new IllegalArgumentException("You must first set a model (try #load())");
}
Request previous = target.getRequest();
if (previous != null) {
previous.clear();
requestTracker.removeRequest(previous);
previous.recycle();
}
Request request = buildRequest(target);
target.setRequest(request);
lifecycle.addListener(target);
requestTracker.runRequest(request);
return target;
}
这里会构建一个target对象,再通过target构建一个Request请求,最后通过requestTracker 运行这个请求,接下来看请求如何执行
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
@Override
public void begin() {
startTime = LogTime.getLogTime();
if (model == null) {
onException(null);
return;
}
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
onSizeReady这里就是请求执行的地方,并设置好图片的占位图,再继续看下去
@Override
public void onSizeReady(int width, int height) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
width = Math.round(sizeMultiplier * width);
height = Math.round(sizeMultiplier * height);
ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
if (dataFetcher == null) {
onException(new Exception("Failed to load model: \'" + model + "\'"));
return;
}
ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
loadedFromMemoryCache = true;
loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
priority, isMemoryCacheable, diskCacheStrategy, this);
loadedFromMemoryCache = resource != null;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
这里是做请求的最后一步,生成编码,解码的transcoder,和请求图片相关的DataFetcher类,然后传给Engie做最后的资源获取逻辑
public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
Util.assertMainThread();
long startTime = LogTime.getLogTime();
final String id = fetcher.getId();
EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
transcoder, loadProvider.getSourceEncoder());
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
EngineJob current = jobs.get(key);
if (current != null) {
current.addCallback(cb);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
transcoder, diskCacheProvider, diskCacheStrategy, priority);
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(runnable);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
static class EngineJobFactory {
private final ExecutorService diskCacheService;
private final ExecutorService sourceService;
private final EngineJobListener listener;
public EngineJobFactory(ExecutorService diskCacheService, ExecutorService sourceService,
EngineJobListener listener) {
this.diskCacheService = diskCacheService;
this.sourceService = sourceService;
this.listener = listener;
}
public EngineJob build(Key key, boolean isMemoryCacheable) {
return new EngineJob(key, diskCacheService, sourceService, isMemoryCacheable, listener);
}
}
这个方法是Glide加载图片核心逻辑。Glide 加载首先会从内存中加载,通过 loadFromCache(),loadFromActiveResources(),如果存在就直接返回 cb.onResourceReady(cached); 否则会构建一个EngineJob对象,通过 EngineJobFactory进行构建。包含了两个线程池diskCacheService,sourceService。然后调用了EngineJob方法,执行runnable对象
public void start(EngineRunnable engineRunnable) {
this.engineRunnable = engineRunnable;
future = diskCacheService.submit(engineRunnable);
}
这里会调用磁盘缓存的任务,看下他runnable 执行
@Override
public void run() {
if (isCancelled) {
return;
}
Exception exception = null;
Resource<?> resource = null;
try {
resource = decode();
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception decoding", e);
}
exception = e;
}
if (isCancelled) {
if (resource != null) {
resource.recycle();
}
return;
}
if (resource == null) {
onLoadFailed(exception);
} else {
onLoadComplete(resource);
}
}
会执行到decode方法
private Resource<?> decode() throws Exception {
if (isDecodingFromCache()) {
return decodeFromCache();
} else {
return decodeFromSource();
}
}
会isDecodingFromCache 一开始传入的为true,先加载缓存,在run方法中,执行完decode 会有一段代码
if (resource == null) {
onLoadFailed(exception);
} else {
onLoadComplete(resource);
}
当从磁盘缓存中没有获取到资源,就会执行onLoadFailed 方法
private void onLoadFailed(Exception e) {
if (isDecodingFromCache()) {
stage = Stage.SOURCE;
manager.submitForSource(this);
} else {
manager.onException(e);
}
}
这里会进行Stage的状态设置,再次执行run任务,此时isDecodingFromCache就为false,执行decodeFromSource,请求网络图片,代码如下
private Resource<T> decodeSource() throws Exception {
Resource<T> decoded = null;
try {
long startTime = LogTime.getLogTime();
final A data = fetcher.loadData(priority);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Fetched data", startTime);
}
if (isCancelled) {
return null;
}
decoded = decodeFromSourceData(data);
} finally {
fetcher.cleanup();
}
return decoded;
}
请求成功后会执行decodeFromSourceData
private Resource<T> decodeFromSourceData(A data) throws IOException {
final Resource<T> decoded;
if (diskCacheStrategy.cacheSource()) {
decoded = cacheAndDecodeSourceData(data);
} else {
long startTime = LogTime.getLogTime();
decoded = loadProvider.getSourceDecoder().decode(data, width, height);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded from source", startTime);
}
}
return decoded;
}
private Resource<T> cacheAndDecodeSourceData(A data) throws IOException {
long startTime = LogTime.getLogTime();
SourceWriter<A> writer = new SourceWriter<A>(loadProvider.getSourceEncoder(), data);
diskCacheProvider.getDiskCache().put(resultKey.getOriginalKey(), writer);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Wrote source to cache", startTime);
}
startTime = LogTime.getLogTime();
Resource<T> result = loadFromCache(resultKey.getOriginalKey());
if (Log.isLoggable(TAG, Log.VERBOSE) && result != null) {
logWithTimeAndKey("Decoded source from cache", startTime);
}
return result;
}
将请求到的数据保存到磁盘,返回资源. 拿到资源后,会调用onLoadComplete()方法
private void onLoadComplete(Resource resource) {
manager.onResourceReady(resource);
}
@Override
public void onResourceReady(final Resource<?> resource) {
this.resource = resource;
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
通过hanlder发送消息,回到主线程
private void handleResultOnMainThread() {
if (isCancelled) {
resource.recycle();
return;
} else if (cbs.isEmpty()) {
throw new IllegalStateException("Received a resource without any callbacks to notify");
}
engineResource = engineResourceFactory.build(resource, isCacheable);
hasResource = true;
// Hold on to resource for duration of request so we don't recycle it in the middle of notifying if it
// synchronously released by one of the callbacks.
engineResource.acquire();
listener.onEngineJobComplete(key, engineResource);
for (ResourceCallback cb : cbs) {
if (!isInIgnoredCallbacks(cb)) {
engineResource.acquire();
cb.onResourceReady(engineResource);
}
}
// Our request is complete, so we can release the resource.
engineResource.release();
}
资源的内存缓存,并回调展示,这里会进行请求期间的数据进行保存,然后同步回调完成后进行释放,保存到内存缓存中
@SuppressWarnings("unchecked")
@Override
public void onEngineJobComplete(Key key, EngineResource<?> resource) {
Util.assertMainThread();
// A null resource indicates that the load failed, usually due to an exception.
if (resource != null) {
resource.setResourceListener(key, this);
if (resource.isCacheable()) {
activeResources.put(key, new ResourceWeakReference(key, resource, getReferenceQueue()));
}
}
// TODO: should this check that the engine job is still current?
jobs.remove(key);
}
@Override
public void onResourceReleased(Key cacheKey, EngineResource resource) {
Util.assertMainThread();
activeResources.remove(cacheKey);
if (resource.isCacheable()) {
cache.put(cacheKey, resource);
} else {
resourceRecycler.recycle(resource);
}
}
三、总结
通过上面两部分的源码分析,可以知道Glide通过添加一个空白的fragment来做生命周期的监听,然后执行资源的回收。 Glide的缓存分为两层,内存缓存,磁盘缓存。有的博主说是有三次,那是算上了网络的一层。 在设置网络图片时,先从内存缓存读取,不存在就会到磁盘读取,还是没有就会就会进行网络获取图片数据。获取到数据之后会将图片保存到磁盘,然后加载图片到界面,再将图片保存到内存中。而图片的请求则是通过DataFetcher,可以是HttpUrlConnection,可以是okhttp,可以是volley来进行请求