Glide加载过程分析
来源:互联网 发布:wine for mac 编辑:程序博客网 时间:2024/06/04 18:18
注:以下分析基于glide 4.0.0-RC1
版本,主要分析基于网络图片的加载 GitHub地址
Glide 基本用法
RequestManager requestManager = Glide.with(MainActivity.this);RequestBuilder requestBuilder=requestManager.load("https://github.com/bumptech/glide/raw/master/static/glide_logo.png"); requestBuilder.into(mIvTest);
Glide 的初始化
在第一次调用Glide.with()时,Glide会进行初始化,调用链大家去看下代码就知道,这里不一一列举,核心代码如下:
// Glide.java private static void initGlide(Context context) { Context applicationContext = context.getApplicationContext(); //省略............. //factory这里为空 GlideBuilder builder = new GlideBuilder .setRequestManagerFactory(factory) glide = builder.build(applicationContext); }
接下看GlideBuilder的 build方法
// GlideBuilder.java public Glide build(Context context) { //生成一个请求图片的线程池, //默认:corePoolSize=maximumPoolSize,keepAliveTimeInMs=0 ,corePoolSize为 CPU 数,但最大为4,最小为1 if (sourceExecutor == null) { sourceExecutor = GlideExecutor.newSourceExecutor(); } //生成一个硬盘缓存图片的线程池,默认:corePoolSize=maximumPoolSize=1,keepAliveTimeInMs=0 if (diskCacheExecutor == null) { diskCacheExecutor = GlideExecutor.newDiskCacheExecutor(); } //用来计算缓存图片的大小以及各种缓存pool 的 szie,依据主要是设备屏幕密度、尺寸 if (memorySizeCalculator == null) { memorySizeCalculator = new MemorySizeCalculator.Builder(context).build(); }//网络权限相关 if (connectivityMonitorFactory == null) { connectivityMonitorFactory = new DefaultConnectivityMonitorFactory(); }//bitmap Pool,大于取自于memorySizeCalculator//LruBitmapPool的主要作用有://1. 基于 LRU 算法提供内存缓存//2. 当发生TRIM_MEMORY时,根据TRIM_MEMORY的等级进行缓存的清理(LRU);// 内存缓存的策略主要由LruPoolStrategy的实现类来决定 if (bitmapPool == null) { int size = memorySizeCalculator.getBitmapPoolSize(); bitmapPool = new LruBitmapPool(size); }//对象数组缓存池,默认4 M if (arrayPool == null) { arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes()); }// Resource 图片的缓存 if (memoryCache == null) { memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize()); }//说明:默认状态下,bitmapPool+arrayPool+memoryCache 的峰值大概会占到应用最大可用内存的30%~40%,//硬盘缓存策略 if (diskCacheFactory == null) { diskCacheFactory = new InternalCacheDiskCacheFactory(context); }//图片加载引擎 if (engine == null) { engine = new Engine(memoryCache, diskCacheFactory, diskCacheExecutor, sourceExecutor, GlideExecutor.newUnlimitedSourceExecutor()); } RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever( requestManagerFactory);//返回 Glide 对象 return new Glide( context, engine, memoryCache, bitmapPool, arrayPool, requestManagerRetriever, connectivityMonitorFactory, logLevel, defaultRequestOptions.lock()); }
创建 RequestManager 对象
RequestManager主要负责管理Image Request,并将Request与activity、 fragment的生命周期绑定起来。核心代码如下:
//RequestManagerRetriever.java private RequestManager supportFragmentGet(Context context, FragmentManager fm, Fragment parentHint) { //获取一个SupportRequestManagerFragment //SupportRequestManagerFragment是一个没有布局的Fragment,依附于 Activity或Fragment //SupportRequestManagerFragment主要用于跟踪生命周期 //对于同一个 Activity或Fragment对象,只会有一个SupportRequestManagerFragment SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint); RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { Glide glide = Glide.get(context); //构建一个RequestManager,其中current.getGlideLifecycle()就是SupportRequestManagerFragment生命周期的回调 requestManager = factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode()); current.setRequestManager(requestManager); } return requestManager; }
创建 RequestBuilder 对象
RequestBuilder是一个泛型类,它主要用于处于与图片加载相关的设置,其中的泛型类型代表着最终要被设置到 ImageView或者加载的资源类型(eg:Drawable、Bitmap、GifDrawable),默认是Drawable。核心代码如下:
//RequestManager.java//注意 load()方法接收的是一个Object,意味着不一定要传入 String,可以传入例如 File、Resource IDpublic RequestBuilder<Drawable> load(@Nullable Object model) { return asDrawable().load(model); }
//RequestManager.java public RequestBuilder<Drawable> asDrawable() { //as(Drawable.class)指定加载的资源类型为 Drawable //transition(new DrawableTransitionOptions()) 主要设置了一个图片加载成功后的动画效果 return as(Drawable.class).transition(new DrawableTransitionOptions()); }
至此,我们已经得到了一个RequestBuilder对象,接下来就是重头戏into()方法了。
public Target<TranscodeType> into(ImageView view) { //into()方法必须在主线程调用 Util.assertMainThread(); Preconditions.checkNotNull(view); //requestOptions 是 RequestOptions对象,主要用来包装图片加载的各种策略,例如:缓存、裁剪、动画 if (!requestOptions.isTransformationSet() && requestOptions.isTransformationAllowed() && view.getScaleType() != null) { if (requestOptions.isLocked()) { requestOptions = requestOptions.clone(); } //ImageView 默认的 ScaleType为FIT_CENTER switch (view.getScaleType()) { case CENTER_CROP: requestOptions.optionalCenterCrop(); break; case CENTER_INSIDE: requestOptions.optionalCenterInside(); break; case FIT_CENTER: case FIT_START: case FIT_END: requestOptions.optionalFitCenter(); break; case FIT_XY: requestOptions.optionalCenterInside(); break; case CENTER: case MATRIX: default: // Do nothing. } } //重点,context对象是GlideContext,是对 Context的一个包装 return into(context.buildImageViewTarget(view, transcodeClass)); }
最后的 into()方法接收一个Target对象的子类,Target是对要图片资源要展示的目的地(最常见的当然是 ImageView了)的一个包装。我们先来看看GlideContext.buildImageViewTarget()方法,buildImageViewTarget最终调用的是ImageViewTargetFactory的buildTarget()方法,代码如下:
public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) { //其实就是按照加载的资源类型返回相对应的 Target if (Bitmap.class.equals(clazz)) { return (Target<Z>) new BitmapImageViewTarget(view); } else if (Drawable.class.isAssignableFrom(clazz)) { return (Target<Z>) new DrawableImageViewTarget(view); } else { throw new IllegalArgumentException( "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)"); } }
自此,ImageView 转换成了Target , 接着看下RequestBuilder.into(Target target)
public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) { Util.assertMainThread(); Preconditions.checkNotNull(target); if (!isModelSet) { throw new IllegalArgumentException("You must call #load() before calling #into()"); }//如果同一个target 之前有图片资源的相关请求,则 clear它。 Request previous = target.getRequest(); if (previous != null) { requestManager.clear(target); }//将RequestOptions状态设置为锁定,防止中途被修改 requestOptions.lock();//创建一个图片请求,具体稍后再看 Request request = buildRequest(target);//将request设置到 target 中 target.setRequest(request);//将request加入到 RequestManager 中,由RequestManager管理相应的 request//request在这发起 requestManager.track(target, request); return target; }
图片请求Request的创建
图片请求的创建由 RequestBuilder 的buildRequest(Target target)发起,核心代码如下:
//RequestBuilder.java private Request buildRequest(Target<TranscodeType> target) { //这里可以通过requestOptions来指定宽高 return buildRequestRecursive(target, null, transitionOptions, requestOptions.getPriority(), requestOptions.getOverrideWidth(), requestOptions.getOverrideHeight()); } ``` ```java private Request buildRequestRecursive(Target<TranscodeType> target, @Nullable ThumbnailRequestCoordinator parentCoordinator, TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, int overrideWidth, int overrideHeight) { //如果有缩略图,处理缩略图的请求,这部分不是我们分析的重点 if (thumbnailBuilder != null) { //********************** return coordinator; } //处理缩放,也不是我们的重点 else if (thumbSizeMultiplier != null) { //********************** return coordinator; } else { // 这是最常见的情况 return obtainRequest(target, requestOptions, parentCoordinator, transitionOptions, priority, overrideWidth, overrideHeight); } } ``` ```java //RequestBuilder.java private Request obtainRequest(Target<TranscodeType> target, RequestOptions requestOptions, RequestCoordinator requestCoordinator,TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority,int overrideWidth, int overrideHeight) { requestOptions.lock(); //调用 SingleRequest 的一个静态方法通过相应的参数获取一个Request return SingleRequest.obtain( context,//GlideContext,对上下文(Context)的一个包装,里面包含了重要的Engine对象 model,//图片来源 model ,比如 url,File ,srcId transcodeClass, requestOptions, overrideWidth, overrideHeight, priority, target,//对数据目的地的一个包装(主要是 ImageView) requestListener, requestCoordinator,//请求协调器,主要是为了有缩略图的请求 context.getEngine(),//Engine对象 transitionOptions.getTransitionFactory()); }
得到Request之后干啥呢?我们回到 大名鼎鼎的into()方法中看看
// RequestBuilder.java public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) { //into()方法必须在 ui线程调用 Util.assertMainThread(); //**************** requestOptions.lock(); //得到请求 Request request = buildRequest(target); //将请求设置到target 中 target.setRequest(request); //最终会调用 RequestTracker 的runRequest()来执行请求 requestManager.track(target, request); return target; }
//RequestTracker.java public void runRequest(Request request) { requests.add(request); //如果请求没有暂停,则开始请求。isPaused默认是 false if (!isPaused) { //Request是一个接口,这里的Request实例是SingleRequest request.begin(); } //否则加入到一个队列中 else { pendingRequests.add(request); } }
于是重点又回到了SingleRequest 中的 begin() 方法
//DecodeJob.java @Override public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) { this.currentSourceKey = sourceKey; this.currentData = data; this.currentFetcher = fetcher; this.currentDataSource = dataSource; this.currentAttemptingKey = attemptedKey; if (Thread.currentThread() != currentThread) { runReason = RunReason.DECODE_DATA; callback.reschedule(this); } else { TraceCompat.beginSection("DecodeJob.decodeFromRetrievedData"); try { //资源的解码工作 decodeFromRetrievedData(); } finally { TraceCompat.endSection(); } } }
解码完成后会做些缓存的工作,接着通过DecodeJob的callback对象(EngineJob),最后是通过MSG_COMPLETE的Message将在 UI 线程设置相应的资源到 target 上去。流程就不一一列举了,大家可以自己 debug一下就知道了。
- Glide加载过程分析
- Glide 使用OkHttp加载图片源码分析
- 类加载过程分析
- Fragment加载过程分析。
- Fragment加载过程分析
- Bootloader加载过程分析
- jvm加载过程分析
- 深入Glide图片加载库的Demo源码分析
- Android图片加载框架分析之Glide、Picasso和Fresco
- Glide源码分析2 -- request创建与发送过程
- Glide在加载网络图片过程中怎么知道加载状态
- 分析ELF的加载过程
- 概括分析elf加载过程
- 分析ELF的加载过程
- ZendFramework资源加载过程分析
- jvm类加载过程分析
- jvm类加载过程分析
- Java类加载过程分析
- Python闭包
- LeetCode-Two Sum
- 史上最权威宏基因组软件评估—人工重组宏基因组基准数据集
- 前端之微信小程序
- Improving Deep Neural Networks Gradient Checking 参考答案
- Glide加载过程分析
- 9-10 DAIRY
- 在实验室台式上更新python库
- 第3章 SQL Server表
- python笔记--集合
- Linux下安装mysql
- mysql 事物与锁
- 51Nod
- Gradle学习系列之一——Gradle快速入门