Glide源码阅读一
来源:互联网 发布:明星淘宝店铺名称 编辑:程序博客网 时间:2024/05/24 01:31
从如下代码开始阅读Glide源码:
private static final Headers headers = new LazyHeaders.Builder().addHeader("Referer", AppCfg.FATE_IT_HTTP).build();if (TextUtils.isEmpty(sPic)) return;try { GlideUrl glideUrl = new GlideUrl(sPic, headers); Glide.with(context) .load(glideUrl) .dontAnimate() .placeholder(defResImg) .error(errResImg) .transform(transformation) .diskCacheStrategy(DiskCacheStrategy.ALL) .into(view);} catch (Exception e) { e.printStackTrace();}
第一步
首先分析with(context)
public static RequestManager with(Context context) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(context);}
下面的的get方法
public RequestManager get(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) { return get(((ContextWrapper) context).getBaseContext()); } } return getApplicationManager(context);}
上面分情况
这是 getApplicationManager(context);
private RequestManager getApplicationManager(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. applicationManager = new RequestManager(context.getApplicationContext(), new ApplicationLifecycle(), new EmptyRequestManagerTreeNode()); } } } return applicationManager;}
这是 get(Activity activity)
@TargetApi(Build.VERSION_CODES.HONEYCOMB)public RequestManager get(Activity activity) { if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { return get(activity.getApplicationContext()); } else { assertNotDestroyed(activity); android.app.FragmentManager fm = activity.getFragmentManager(); return fragmentGet(activity, fm); }}@TargetApi(Build.VERSION_CODES.HONEYCOMB)RequestManager fragmentGet(Context context, android.app.FragmentManager fm) { RequestManagerFragment current = getRequestManagerFragment(fm); RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode()); current.setRequestManager(requestManager); } return requestManager;}
以上分析的两种里面均会返回 RequestManager 对象,此时要看改对象构造函数
public RequestManager(Context context, Lifecycle lifecycle, RequestManagerTreeNode treeNode) { this(context, lifecycle, treeNode, new RequestTracker(), new ConnectivityMonitorFactory());}RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode, RequestTracker requestTracker, ConnectivityMonitorFactory factory) { this.context = context.getApplicationContext(); this.lifecycle = lifecycle; this.treeNode = treeNode; this.requestTracker = requestTracker; this.glide = Glide.get(context); this.optionsApplier = new OptionsApplier(); ConnectivityMonitor connectivityMonitor = factory.build(context, new RequestManagerConnectivityListener(requestTracker)); // If we're the application level request manager, we may be created on a background thread. In that case we // cannot risk synchronously pausing or resuming requests, so we hack around the issue by delaying adding // ourselves as a lifecycle listener by posting to the main thread. This should be entirely safe. if (Util.isOnBackgroundThread()) { new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { lifecycle.addListener(RequestManager.this); } }); } else { lifecycle.addListener(this); } lifecycle.addListener(connectivityMonitor);}
第二个构造器里 this.glide = Glide.get(context); 开始调用 Glide 的单利模式了,进去看看
/** * Get the singleton. * * @return the singleton */public static Glide get(Context context) { if (glide == null) { synchronized (Glide.class) { if (glide == null) { Context applicationContext = context.getApplicationContext(); List<GlideModule> modules = new ManifestParser(applicationContext).parse(); GlideBuilder builder = new GlideBuilder(applicationContext); for (GlideModule module : modules) { module.applyOptions(applicationContext, builder); } glide = builder.createGlide(); for (GlideModule module : modules) { module.registerComponents(applicationContext, glide); } } } } return glide;}
单利生成 glide 对象 glide = builder.createGlide(); 用到 GlideBuilder 对象的 createGlide()。进去看看
Glide createGlide() { if (sourceService == null) { final int cores = Math.max(1, Runtime.getRuntime().availableProcessors()); sourceService = new FifoPriorityThreadPoolExecutor(cores); } if (diskCacheService == null) { diskCacheService = new FifoPriorityThreadPoolExecutor(1); } MemorySizeCalculator calculator = new MemorySizeCalculator(context); if (bitmapPool == null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { int size = calculator.getBitmapPoolSize(); bitmapPool = new LruBitmapPool(size); } else { bitmapPool = new BitmapPoolAdapter(); } } if (memoryCache == null) { memoryCache = new LruResourceCache(calculator.getMemoryCacheSize()); } if (diskCacheFactory == null) { diskCacheFactory = new InternalCacheDiskCacheFactory(context); } if (engine == null) { engine = new Engine(memoryCache, diskCacheFactory, diskCacheService, sourceService); } if (decodeFormat == null) { decodeFormat = DecodeFormat.DEFAULT; } return new Glide(engine, memoryCache, bitmapPool, context, decodeFormat);}
createGlide() 里面创建 glide 对象的时候,初始化了很多对象,到此算是 Glide 的初始化吧
第二步
看网络请求 和 缓存策略
直接看into(view) 在 DrawableRequestBuilder 类里
public Target<GlideDrawable> into(ImageView view) { return super.into(view);}
super.into(view) 到 GenericRequestBuilder 类里
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));}
进入这个 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;}
requestTracker.runRequest(request); 到 RequestTracker 类里
/** * Starts tracking the given request. */public void runRequest(Request request) { requests.add(request); if (!isPaused) { request.begin(); } else { pendingRequests.add(request); }}
GenericRequest 类中实现 request.begin();
/** * {@inheritDoc} */@Overridepublic 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)); }}/** * A callback method that should never be invoked directly. */@Overridepublic 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)); }}
开始加载了 engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
priority, isMemoryCacheable, diskCacheStrategy, this);
进入 Engin 看看,重点来了
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);}
EngineRunnable里面传入了 engineJob, decodeJob
engineJob.start(runnable); // diskCacheService.submit(engineRunnable); // ExecutorService 涉及线程池
EngineRunnable线程开始干活了
@Overridepublic 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); }}private Resource<?> decode() throws Exception { if (isDecodingFromCache()) { return decodeFromCache(); } else { return decodeFromSource(); }}
直接看网络加载吧
private Resource<?> decodeFromSource() throws Exception { return decodeJob.decodeFromSource();}
DecodeJob 入场了
public Resource<Z> decodeFromSource() throws Exception { Resource<T> decoded = decodeSource(); return transformEncodeAndTranscode(decoded);}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;}
DataFetcher 类来了,(数据提取类)
final A data = fetcher.loadData(priority); 数据提取有七种实现,我们来看 HttpUrlFetcher 吧
@Overridepublic InputStream loadData(Priority priority) throws Exception { return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders());}private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers) throws IOException { if (redirects >= MAXIMUM_REDIRECTS) { throw new IOException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!"); } else { // Comparing the URLs using .equals performs additional network I/O and is generally broken. // See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html. try { if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) { throw new IOException("In re-direct loop"); } } catch (URISyntaxException e) { // Do nothing, this is best effort. } } urlConnection = connectionFactory.build(url); for (Map.Entry<String, String> headerEntry : headers.entrySet()) { urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue()); } urlConnection.setConnectTimeout(2500); urlConnection.setReadTimeout(2500); urlConnection.setUseCaches(false); urlConnection.setDoInput(true); // Connect explicitly to avoid errors in decoders if connection fails. urlConnection.connect(); if (isCancelled) { return null; } final int statusCode = urlConnection.getResponseCode(); if (statusCode / 100 == 2) { return getStreamForSuccessfulRequest(urlConnection); } else if (statusCode / 100 == 3) { String redirectUrlString = urlConnection.getHeaderField("Location"); if (TextUtils.isEmpty(redirectUrlString)) { throw new IOException("Received empty or null redirect url"); } URL redirectUrl = new URL(url, redirectUrlString); return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers); } else { if (statusCode == -1) { throw new IOException("Unable to retrieve response code from HttpUrlConnection."); } throw new IOException("Request failed " + statusCode + ": " + urlConnection.getResponseMessage()); }}
是不是很熟悉,好了请求到的 InputStream 我们还是要返回的。回到 DecodeJob,看 decoded = decodeFromSourceData(data);
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;}
这里
decoded = cacheAndDecodeSourceData(data);是否缓存并 decode 解码
decoded = loadProvider.getSourceDecoder().decode(data, width, height); decode 选个合适的 ResourceDecoder 吧
以上都会返回 Resource ,逐级返回到 EngineRunnable 里面,开始给控件赋值了
给控件赋值
在 EngineRunnable 类里
@Overridepublic 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); }}
来看 onLoadComplete(resource);
private void onLoadComplete(Resource resource) { manager.onResourceReady(resource);}
点击去看看, 来到了 EngineJob 类里
@Overridepublic void onResourceReady(final Resource<?> resource) { this.resource = resource; MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();}
看看 MAIN_THREAD_HANDLER 主线程的 handler
private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());
MainThreadCallback 里面
private static class MainThreadCallback implements Handler.Callback { @Override public boolean handleMessage(Message message) { if (MSG_COMPLETE == message.what || MSG_EXCEPTION == message.what) { EngineJob job = (EngineJob) message.obj; if (MSG_COMPLETE == message.what) { job.handleResultOnMainThread(); } else { job.handleExceptionOnMainThread(); } return true; } return false; }}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();}
在 EngineJob 里 cb.onResourceReady(engineResource); cb 是 ResourceCallback,它的实现类 EngineJob 和 GenericRequest;
GenericRequest 实现 onResourceReady 方法
@SuppressWarnings("unchecked")@Overridepublic void onResourceReady(Resource<?> resource) { if (resource == null) { onException(new Exception("Expected to receive a Resource<R> with an object of " + transcodeClass + " inside, but instead got null.")); return; } Object received = resource.get(); if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) { releaseResource(resource); onException(new Exception("Expected to receive an object of " + transcodeClass + " but instead got " + (received != null ? received.getClass() : "") + "{" + received + "}" + " inside Resource{" + resource + "}." + (received != null ? "" : " " + "To indicate failure return a null Resource object, " + "rather than a Resource object containing null data.") )); return; } if (!canSetResource()) { releaseResource(resource); // We can't set the status to complete before asking canSetResource(). status = Status.COMPLETE; return; } onResourceReady(resource, (R) received); // 这里}private void onResourceReady(Resource<?> resource, R result) { // We must call isFirstReadyResource before setting status. boolean isFirstResource = isFirstReadyResource(); status = Status.COMPLETE; this.resource = resource; if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache, isFirstResource)) { GlideAnimation<R> animation = animationFactory.build(loadedFromMemoryCache, isFirstResource); target.onResourceReady(result, animation); // 这里 选一种 target 实现吧 如: ImageViewTarget } notifyLoadSuccess(); if (Log.isLoggable(TAG, Log.VERBOSE)) { logV("Resource ready in " + LogTime.getElapsedMillis(startTime) + " size: " + (resource.getSize() * TO_MEGABYTE) + " fromCache: " + loadedFromMemoryCache); }}
如果选择的是 ImageViewTarget 实现,来看看吧
@Overridepublic void onResourceReady(Z resource, GlideAnimation<? super Z> glideAnimation) { if (glideAnimation == null || !glideAnimation.animate(resource, this)) { setResource(resource); // 执行的是下面的抽象方法 }}protected abstract void setResource(Z resource);
实现类 BitmapImageViewTarget、DrawableImageViewTarget、GlideDrawableImageViewTarget 选一个吧,如: BitmapImageViewTarget
@Overrideprotected void setResource(Bitmap resource) { view.setImageBitmap(resource);}
至此,Glide 加载图片及赋值算是完成了
注:还有好多东西需要研究,生命周期管理、缓存策略、资源加载策略
- Glide源码阅读一
- 源码阅读--Glide
- Glide源码分析 一
- Glide的源码分析<一>
- live555源码阅读一
- nginx源码阅读(一)
- TCMalloc源码阅读(一)
- TCMalloc源码阅读(一)
- 源码阅读(一)
- Sring源码阅读一
- OSCache源码阅读(一)
- Log4j源码阅读一
- 源码阅读(一)
- pg源码阅读一
- STL源码阅读(一)
- FreeRTOS源码阅读(一)
- flask源码阅读一
- 阅读XRecyclerView源码一
- 软件测试经验
- WebStorm ES6 语法支持设置
- android 7.0 致2017
- List转换成Map工具类
- 常见开源数据库连接池的使用
- Glide源码阅读一
- C#-Socket编程-UDP
- Android开发的细节处理
- 面向对象之父Alan Kay:预测未来,创造未来
- MySQL中varchar最大长度是多少?
- 数据表现形式及其运算
- 心态和心情
- vs2015 C#连接mysql
- 工作总结