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一下就知道了。

原创粉丝点击