架构大合集,轻松应对工作需求(中)

Posted 初一十五啊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了架构大合集,轻松应对工作需求(中)相关的知识,希望对你有一定的参考价值。

前言

本文讲述

  • 数据结构和算法,23种设计模式,
  • OKhttp,Retrofit,
  • Glide,
  • Dagger2,
  • MVP,MVC,MVVM,MVI,
  • Jetpack Room,

可能字数限制会分为2-3篇讲述😂

今天星期一,星期一,星期一😑

关注公众号:初一十五a
解锁 《Android十大板块文档》,让学习更贴近未来实战。已形成PDF版

内容如下

1.2022最新Android11位大厂面试专题,128道附答案
2.音视频大合集,从初中高到面试应有尽有
3.Android车载应用大合集,从零开始一起学
4.性能优化大合集,告别优化烦恼
5.Framework大合集,从里到外分析的明明白白
6.Flutter大合集,进阶Flutter高级工程师
7.compose大合集,拥抱新技术
8.Jetpack大合集,全家桶一次吃个够
9.架构大合集,轻松应对工作需求
10.Android基础篇大合集,根基稳固高楼平地起

整理不易,关注一下吧。开始进入正题,ღ( ´・ᴗ・` ) 🤔

三丶图片加载

1.Glide

1.1.基本使用流程

Glide最基本的使用流程就是下面这行代码,其它所有扩展的额外功能都是以其建造者链式调用的基础上增加的。

GlideApp.with(context).load(url).into(iv);

其中的GlideApp是注解处理器自动生成的,要使用GlideApp,必须先配置应用的AppGlideModule模块,里面可以为空配置,也可以根据实际情况添加指定配置。

@GlideModule
public class MyAppGlideModule extends AppGlideModule 

    @Override
    public void applyOptions(Context context, GlideBuilder builder) 
        // 实际使用中根据情况可以添加如下配置
        <!--builder.setDefaultRequestOptions(new RequestOptions().format(DecodeFormat.PREFER_RGB_565));-->
        <!--int memoryCacheSizeBytes = 1024 * 1024 * 20;-->
        <!--builder.setMemoryCache(new LruResourceCache(memoryCacheSizeBytes));-->
        <!--int bitmapPoolSizeBytes = 1024 * 1024 * 30;-->
        <!--builder.setBitmapPool(new LruBitmapPool(bitmapPoolSizeBytes));-->
        <!--int diskCacheSizeBytes = 1024 * 1024 * 100;-->
        <!--builder.setDiskCache(new InternalCacheDiskCacheFactory(context, diskCacheSizeBytes));-->
    


接下来,本文将针对Glide的最新源码版本V4.8.0对Glide加载网络图片的流程进行详细地分析与讲解,力争做到让读者朋友们知其然也知其所以然。

1.2.GlideApp.with(context)源码详解

首先,用这份Glide框架图让我们对Glide的总体框架有一个初步的了解。

从GlideApp.with这行代码开始,内部主线执行流程如下。

GlideApp#with

return (GlideRequests) Glide.with(context);

Glide#with

return getRetriever(context).get(context);

return Glide.get(context).getRequestManagerRetriever();

// 外部使用了双重检锁的同步方式确保同一时刻只执一次Glide的初始化
checkAndInitializeGlide(context);

initializeGlide(context);

// 最终执行到Glide的另一个重载方法
initializeGlide(context, new GlideBuilder());

@SuppressWarnings("deprecation")
  private static void initializeGlide(@NonNull Context   context, @NonNull GlideBuilder builder) 
    Context applicationContext =     context.getApplicationContext();
    // 1、获取前面应用中带注解的GlideModule
    GeneratedAppGlideModule annotationGeneratedModule =     getAnnotationGeneratedGlideModules();
    // 2、如果GlideModule为空或者可配置manifest里面的标志为true,则获取manifest里面
    // 配置的GlideModule模块(manifestModules)。
    List<com.bumptech.glide.module.GlideModule>     manifestModules = Collections.emptyList();
    if (annotationGeneratedModule == null ||     annotationGeneratedModule.isManifestParsingEnabled(    )) 
      manifestModules = new   ManifestParser(applicationContext).parse();
    

    ...

    RequestManagerRetriever.RequestManagerFactory     factory =
        annotationGeneratedModule != null
            ? annotationGeneratedModule.getRequestManag    erFactory() : null;
    builder.setRequestManagerFactory(factory);
    for (com.bumptech.glide.module.GlideModule module :     manifestModules) 
      module.applyOptions(applicationContext, builder);
    
    if (annotationGeneratedModule != null) 
      annotationGeneratedModule.applyOptions(applicatio  nContext, builder);
    
    // 3、初始化各种配置信息
    Glide glide = builder.build(applicationContext);
    // 4、把manifestModules以及annotationGeneratedModule里面的配置信息放到builder
    // 里面(applyOptions)替换glide默认组件(registerComponents)
    for (com.bumptech.glide.module.GlideModule module :     manifestModules) 
      module.registerComponents(applicationContext,   glide, glide.registry);
    
    if (annotationGeneratedModule != null) 
      annotationGeneratedModule.registerComponents(appl  icationContext, glide, glide.registry);
    
    applicationContext.registerComponentCallbacks(glide    );
    Glide.glide = glide;


GlideBuilder#build

@NonNull
  Glide build(@NonNull Context context) 
    // 创建请求图片线程池sourceExecutor
    if (sourceExecutor == null) 
      sourceExecutor =   GlideExecutor.newSourceExecutor();
    

    // 创建硬盘缓存线程池diskCacheExecutor
    if (diskCacheExecutor == null) 
      diskCacheExecutor =   GlideExecutor.newDiskCacheExecutor();
    

    // 创建动画线程池animationExecutor
    if (animationExecutor == null) 
      animationExecutor =   GlideExecutor.newAnimationExecutor();
    

    if (memorySizeCalculator == null) 
      memorySizeCalculator = new   MemorySizeCalculator.Builder(context).build();
    

    if (connectivityMonitorFactory == null) 
      connectivityMonitorFactory = new   DefaultConnectivityMonitorFactory();
    

    if (bitmapPool == null) 
      // 依据设备的屏幕密度和尺寸设置各种pool的size
      int size =   memorySizeCalculator.getBitmapPoolSize();
      if (size > 0) 
        // 创建图片线程池LruBitmapPool,缓存所有被释放的bitmap
        // 缓存策略在API大于19时,为SizeConfigStrategy,小于为AttributeStrategy。
        // 其中SizeConfigStrategy是以bitmap的size和config为key,value为bitmap的HashMap
        bitmapPool = new LruBitmapPool(size);
       else 
        bitmapPool = new BitmapPoolAdapter();
      
    

    // 创建对象数组缓存池LruArrayPool,默认4M
    if (arrayPool == null) 
      arrayPool = new   LruArrayPool(memorySizeCalculator.getArrayPoolSiz  eInBytes());
    

    // 创建LruResourceCache,内存缓存
    if (memoryCache == null) 
      memoryCache = new   LruResourceCache(memorySizeCalculator.getMemoryCa  cheSize());
    

    if (diskCacheFactory == null) 
      diskCacheFactory = new   InternalCacheDiskCacheFactory(context);
    

    // 创建任务和资源管理引擎(线程池,内存缓存和硬盘缓存对象)
    if (engine == null) 
      engine =
          new Engine(
              memoryCache,
              diskCacheFactory,
              diskCacheExecutor,
              sourceExecutor,
              GlideExecutor.newUnlimitedSourceExecutor(  ),
              GlideExecutor.newAnimationExecutor(),
              isActiveResourceRetentionAllowed);
    
    
    RequestManagerRetriever requestManagerRetriever =
    new RequestManagerRetriever(requestManagerFactory);

    return new Glide(
        context,
        engine,
        memoryCache,
        bitmapPool,
        arrayPool,
        requestManagerRetriever,
        connectivityMonitorFactory,
        logLevel,
        defaultRequestOptions.lock(),
        defaultTransitionOptions);


Glide#Glide构造方法

Glide(...) 
    ...
    // 注册管理任务执行对象的类(Registry)
    // Registry是一个工厂,而其中所有注册的对象都是一个工厂员工,当任务分发时,
    // 根据当前任务的性质,分发给相应员工进行处理
    registry = new Registry();
    
    ...
    
    // 这里大概有60余次的append或register员工组件(解析器、编解码器、工厂类、转码类等等组件)
    registry
    .append(ByteBuffer.class, new ByteBufferEncoder())
    .append(InputStream.class, new StreamEncoder(arrayPool))
    
    // 根据给定子类产出对应类型的target(BitmapImageViewTarget / DrawableImageViewTarget)
    ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
    
    glideContext =
        new GlideContext(
            context,
            arrayPool,
            registry,
            imageViewTargetFactory,
            defaultRequestOptions,
            defaultTransitionOptions,
            engine,
            logLevel);


RequestManagerRetriever#get

@NonNull
public RequestManager get(@NonNull Context context) 
  if (context == null) 
    throw new IllegalArgumentException("You cannot start a load on a null Context");
   else if (Util.isOnMainThread() && !(context instanceof Application)) 
    // 如果当前线程是主线程且context不是Application走相应的get重载方法
    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());
    
  

  // 否则直接将请求与ApplicationLifecycle关联
  return getApplicationManager(context);


这里总结一下,对于当前传入的context是application或当前线程是子线程时,请求的生命周期和ApplicationLifecycle关联,否则,context是FragmentActivity或Fragment时,在当前组件添加一个SupportFragment(SupportRequestManagerFragment),context是Activity时,在当前组件添加一个Fragment(RequestManagerFragment)。

GlideApp#with小结

  1. 初始化各式各样的配置信息(包括缓存,请求线程池,大小,图片格式等等)以及glide对象。

  2. 将glide请求和application/SupportFragment/Fragment的生命周期绑定在一块。

with方法的执行流程

1.3.load(url)源码详解

GlideRequest(RequestManager)#load

return (GlideRequest<Drawable>) super.load(string);

return asDrawable().load(string);

// 1、asDrawable部分
return (GlideRequest<Drawable>) super.asDrawable();

return as(Drawable.class);

// 最终返回了一个GlideRequest(RequestManager的子类)
return new GlideRequest<>(glide, this, resourceClass, context);

// 2、load部分
return (GlideRequest<TranscodeType>) super.load(string);

return loadGeneric(string);

@NonNull
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) 
    // model则为设置的url
    this.model = model;
    // 记录url已设置
    isModelSet = true;
    return this;


可以看到,load这部分的源码很简单,就是给GlideRequest(RequestManager)设置了要请求的mode(url),并记录了url已设置的状态。

load方法的执行流程

1.4.into(iv)源码详解

真正复杂的地方要开始了。

RequestBuilder.into

 @NonNull
public ViewTarget<ImageView, TranscodeType>   into(@NonNull ImageView view) 
  Util.assertMainThread();
  Preconditions.checkNotNull(view);

  RequestOptions requestOptions =     this.requestOptions;
  if (!requestOptions.isTransformationSet()
      && requestOptions.isTransformationAllowed()
      && view.getScaleType() != null) 
    // Clone in this method so that if we use this   RequestBuilder to load into a View and then
    // into a different target, we don't retain the   transformation applied based on the previous
    // View's scale type.
    switch (view.getScaleType()) 
      // 这个RequestOptions里保存了要设置的scaleType,Glide自身封装了CenterCrop、CenterInside、
      // FitCenter、CenterInside四种规格。
      case CENTER_CROP:
        requestOptions =   requestOptions.clone().optionalCenterCrop();
        break;
      case CENTER_INSIDE:
        requestOptions =   requestOptions.clone().optionalCenterInside()  ;
        break;
      case FIT_CENTER:
      case FIT_START:
      case FIT_END:
        requestOptions =   requestOptions.clone().optionalFitCenter();
        break;
      case FIT_XY:
        requestOptions =   requestOptions.clone().optionalCenterInside()  ;
        break;
      case CENTER:
      case MATRIX:
      default:
        // Do nothing.
    
  

  // 注意,这个transcodeClass是指的drawable或bitmap
  return into(
      glideContext.buildImageViewTarget(view,     transcodeClass),
      /*targetListener=*/ null,
      requestOptions);


GlideContext#buildImageViewTarget

return imageViewTargetFactory.buildTarget(imageView, transcodeClass);

ImageViewTargetFactory#buildTarget

@NonNull
@SuppressWarnings("unchecked")
public <Z> ViewTarget<ImageView, Z>   buildTarget(@NonNull ImageView view,
    @NonNull Class<Z> clazz) 
  // 返回展示Bimtap/Drawable资源的目标对象
  if (Bitmap.class.equals(clazz)) 
    return (ViewTarget<ImageView, Z>) new   BitmapImageViewTarget(view);
   else if (Drawable.class.isAssignableFrom(clazz))     
    return (ViewTarget<ImageView, Z>) new   DrawableImageViewTarget(view);
   else 
    throw new IllegalArgumentException(
        "Unhandled class: " + clazz + ", try   .as*(Class).transcode(ResourceTranscoder)");
  


可以看到,Glide内部只维护了两种target,一种是BitmapImageViewTarget,另一种则是DrawableImageViewTarget,接下来继续深入。

RequestBuilder#into

private <Y extends Target<TranscodeType>> Y into(
      @NonNull Y target,
      @Nullable RequestListener<TranscodeType>   targetListener,
      @NonNull RequestOptions options) 
    Util.assertMainThread();
    Preconditions.checkNotNull(target);
    if (!isModelSet) 
      throw new IllegalArgumentException("You must call   #load() before calling #into()");
    

    options = options.autoClone();
    // 分析1.建立请求
    Request request = buildRequest(target,     targetListener, options);

    Request previous = target.getRequest();
    if (request.isEquivalentTo(previous)
        && !isSkipMemoryCacheWithCompletePreviousReques    t(options, previous)) 
      request.recycle();
      // If the request is completed, beginning again   will ensure the result is re-delivered,
      // triggering RequestListeners and Targets. If   the request is failed, beginning again will
      // restart the request, giving it another chance   to complete. If the request is already
      // running, we can let it continue running   without interruption.
      if (!Preconditions.checkNotNull(previous).isRunni  ng()) 
        // Use the previous request rather than the new     one to allow for optimizations like skipping
        // setting placeholders, tracking and     un-tracking Targets, and obtaining View     dimensions
        // that are done in the individual Request.
        previous.begin();
      
      return target;
    
    
    requestManager.clear(target);
    target.setRequest(request);
    // 分析2.真正追踪请求的地方
    requestManager.track(target, request);

    return target;


// 分析1
private Request buildRequest(
      Target<TranscodeType> target,
      @Nullable RequestListener<TranscodeType>   targetListener,
      RequestOptions requestOptions) 
    return buildRequestRecursive(
        target,
        targetListener,
        /*parentCoordinator=*/ null,
        transitionOptions,
        requestOptions.getPriority(),
        requestOptions.getOverrideWidth(),
        requestOptions.getOverrideHeight(),
        requestOptions);


// 分析1
private Request buildRequestRecursive(
      Target<TranscodeType> target,
      @Nullable RequestListener<TranscodeType>   targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType>   transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      RequestOptions requestOptions) 

    // Build the ErrorRequestCoordinator first if     necessary so we can update parentCoordinator.
    ErrorRequestCoordinator errorRequestCoordinator =     null;
    if (errorBuilder != null) 
      // 创建errorRequestCoordinator(异常处理对象)
      errorRequestCoordinator = new   ErrorRequestCoordinator(parentCoordinator);
      parentCoordinator = errorRequestCoordinator;
    

    // 递归建立缩略图请求
    Request mainRequest =
        buildThumbnailRequestRecursive(
            target,
            targetListener,
            parentCoordinator,
            transitionOptions,
            priority,
            overrideWidth,
            overrideHeight,
            requestOptions);

    if (errorRequestCoordinator == null) 
      return mainRequest;
    

    ...
    
    Request errorRequest =     errorBuilder.buildRequestRecursive(
        target,
        targetListener,
        errorRequestCoordinator,
        errorBuilder.transitionOptions,
        errorBuilder.requestOptions.getPriority(),
        errorOverrideWidth,
        errorOverrideHeight,
        errorBuilder.requestOptions);
    errorRequestCoordinator.setRequests(mainRequest,     errorRequest);
    return errorRequestCoordinator;


// 分析1
private Request buildThumbnailRequestRecursive(
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      @Nullable RequestCoordinator parentCoordinator,
      TransitionOptions<?, ? super TranscodeType> transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight,
      RequestOptions requestOptions) 
    if (thumbnailBuilder != null) 
      // Recursive case: contains a potentially recursive thumbnail request builder.
      
      ...

      ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
      // 获取一个正常请求对象
      Request fullRequest =
          obtainRequest(
              target,
              targetListener,
              requestOptions,
              coordinator,
              transitionOptions,
              priority,
              overrideWidth,
              overrideHeight);
      isThumbnailBuilt = true;
      // Recursively generate thumbnail requests.
      // 使用递归的方式建立一个缩略图请求对象
      Request thumbRequest =
          thumbnailBuilder.buildRequestRecursive(
              target,
              targetListener,
              coordinator,
              thumbTransitionOptions,
              thumbPriority,
              thumbOverrideWidth,
              thumbOverrideHeight,
              thumbnailBuilder.requestOptions);
      isThumbnailBuilt = false;
      // coordinator(ThumbnailRequestCoordinator)是作为两者的协调者,
      // 能够同时加载缩略图和正常的图的请求
      coordinator.setRequests(fullRequest, thumbRequest);
      return coordinator;
     else if (thumbSizeMultiplier != null) 
      // Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
      // 当设置了缩略的比例thumbSizeMultiplier(0 ~  1)时,
      // 不需要递归建立缩略图请求
      ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
      Request fullRequest =
          obtainRequest(
              target,
              targetListener,
              requestOptions,
              coordinator,
              transitionOptions,
              priority,
              overrideWidth,
              overrideHeight);
      RequestOptions thumbnailOptions = requestOptions.clone()
          .sizeMultiplier(thumbSizeMultiplier);

      Request thumbnailRequest =
          obtainRequest(
              target,
              targetListener,
              thumbnailOptions,
              coordinator,
              transitionOptions,
              getThumbnailPriority(priority),
              overrideWidth,
              overrideHeight);

      coordinator.setRequests(fullRequest, thumbnailRequest);
      return coordinator;
     else 
      // Base case: no thumbnail.
      // 没有缩略图请求时,直接获取一个正常图请求
      return obtainRequest(
          target,
          targetListener,
          requestOptions,
          parentCoordinator,
          transitionOptions,
          priority,
          overrideWidth,
          overrideHeight);
    


private Request obtainRequest(
      Target<TranscodeType> target,
      RequestListener<TranscodeType> targetListener,
      RequestOptions requestOptions,
      RequestCoordinator requestCoordinator,
      TransitionOptions<?, ? super TranscodeType>   transitionOptions,
      Priority priority,
      int overrideWidth,
      int overrideHeight) 
    // 最终实际返回的是一个SingleRequest对象(将制定的资源加载进对应的Target
    return SingleRequest.obtain(
        context,
        glideContext,
        model,
        transcodeClass,
        requestOptions,
        overrideWidth,
        overrideHeight,
        priority,
        target,
        targetListener,
        requestListeners,
        requestCoordinator,
        glideContext.getEngine(),
        transitionOptions.getTransitionFactory());

从上源码分析可知,我们在分析1处的buildRequest()方法里建立了请求,且最多可同时进行缩略图和正常图的请求,最后,调用了requestManager.track(target, request)方法,接着看看track里面做了什么。

RequestManager#track

// 分析2
void track(@NonNull Target<?> target, @NonNull Request request) 
    // 加入一个target目标集合(Set)
    targetTracker.track(target);
    
    requestTracker.runRequest(request);


RequestTracker#runRequest

/**
* Starts tracking the given request.
*/
// 分析2
public void runRequest(@NonNull Request request) 
    requests.add(request);
    if (!isPaused) 
      // 如果不是暂停状态则开始请求
      request.begin();
     else 
      request.clear();
      if (Log.isLoggable(TAG, Log.VERBOSE)) 
        Log.v(TAG, "Paused, delaying request");
      
      // 否则清空请求,加入延迟请求队列(为了对这些请求维持一个强引用,使用了ArrayList实现)
      pendingRequests.add(request);
    


SingleRequest#begin

// 分析2
@Override
public void begin() 
  
  ...
  
  if (model == null) 
  
    ...
    // model(url)为空,回调加载失败
    onLoadFailed(new GlideException("Received null   model"), logLevel);
    return;
  

  if (status == Status.RUNNING) 
    throw new IllegalArgumentException("Cannot   restart a running request");
  

 
  if (status == Status.COMPLETE) 
    onResourceReady(resource,   DataSource.MEMORY_CACHE);
    return;
  

  status = Status.WAITING_FOR_SIZE;
  if (Util.isValidDimensions(overrideWidth, overrideHeight)) 
    // 当使用override() API为图片指定了一个固定的宽高时直接执行onSizeReady,
    // 最终的核心处理位于onSizeReady
    onSizeReady(overrideWidth, overrideHeight);
   else 
    // 根据imageView的宽高算出图片的宽高,最终也会走到onSizeReady
    target.getSize(this);
  

  if ((status == Status.RUNNING || status ==     Status.WAITING_FOR_SIZE)
      && canNotifyStatusChanged()) 
    // 预先加载设置的缩略图
    target.onLoadStarted(getPlaceholderDrawable());
  
  if (IS_VERBOSE_LOGGABLE) 
    logV("finished run method in " +   LogTime.getElapsedMillis(startTime));
  


从requestManager.track(target, request)开始,最终会执行到SingleRequest#begin()方法的onSizeReady,可以猜到(因为后面只做了预加载缩略图的处理),真正的请求就是从这里开始的,咱们进去一探究竟~

SingleRequest#onSizeReady

// 分析2
@Override
public void onSizeReady(int width, int height) 
  stateVerifier.throwIfRecycled();
  
  ...
  
  status = Status.RUNNING;

  float sizeMultiplier =     requestOptions.getSizeMultiplier();
  this.width = maybeApplySizeMultiplier(width,     sizeMultiplier);
  this.height = maybeApplySizeMultiplier(height,     sizeMultiplier);

  ...
  
  // 根据给定的配置进行加载,engine是一个负责加载、管理活跃和缓存资源的引擎类
  loadStatus = engine.load(
      glideContext,
      model,
      requestOptions.getSignature(),
      this.width,
      this.height,
      requestOptions.getResourceClass(),
      transcodeClass,
      priority,
      requestOptions.getDiskCacheStrategy(),
      requestOptions.getTransformations(),
      requestOptions.isTransformationRequired(),
      requestOptions.isScaleOnlyOrNoTransform(),
      requestOptions.getOptions(),
      requestOptions.isMemoryCacheable(),
      requestOptions.getUseUnlimitedSourceGeneratorsP    ool(),
      requestOptions.getUseAnimationPool(),
      requestOptions.getOnlyRetrieveFromCache(),
      this);

  ...


终于看到Engine类了,感觉距离成功不远了,继续~

Engine#load

public <R> LoadStatus load(
    GlideContext glideContext,
    Object model,
    Key signature,
    int width,
    int height,
    Class<?> resourceClass,
    Class<R> transcodeClass,
    Priority priority,
    DiskCacheStrategy diskCacheStrategy,
    Map<Class<?>, Transformation<?>> transformations,
    boolean isTransformationRequired,
    boolean isScaleOnlyOrNoTransform,
    Options options,
    boolean isMemoryCacheable,
    boolean useUnlimitedSourceExecutorPool,
    boolean useAnimationPool,
    boolean onlyRetrieveFromCache,
    ResourceCallback cb) 
  
  ...

  // 先从弱引用中查找,如果有的话回调onResourceReady并直接返回
  EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
  if (active != null) 
    cb.onResourceReady(active,   DataSource.MEMORY_CACHE);
    if (VERBOSE_IS_LOGGABLE) 
      logWithTimeAndKey("Loaded resource from active     resources", startTime, key);
    
    return null;
  

  // 没有再从内存中查找,有的话会取出并放到ActiveResources(内部维护的弱引用缓存map)里面
  EngineResource<?> cached = loadFromCache(key,     isMemoryCacheable);
  if (cached != null) 
    cb.onResourceReady(cached,   DataSource.MEMORY_CACHE);
    if (VERBOSE_IS_LOGGABLE) 
      logWithTimeAndKey("Loaded resource from cache",     startTime, key);
    
    return null;
  

  EngineJob<?> current = jobs.get(key,     onlyRetrieveFromCache);
  if (current != null) 
    current.addCallback(cb);
    if (VERBOSE_IS_LOGGABLE) 
      logWithTimeAndKey("Added to existing load",     startTime, key);
    
    return new LoadStatus(cb, current);
  

  // 如果内存中没有,则创建engineJob(decodejob的回调类,管理下载过程以及状态)
  EngineJob<R> engineJob =
      engineJobFactory.build(
          key,
          isMemoryCacheable,
          useUnlimitedSourceExecutorPool,
          useAnimationPool,
          onlyRetrieveFromCache);

  // 创建解析工作对象
  DecodeJob<R> decodeJob =
      decodeJobFactory.build(
          glideContext,
          model,
          key,
          signature,
          width,
          height,
          resourceClass,
          transcodeClass,
          priority,
          diskCacheStrategy,
          transformations,
          isTransformationRequired,
          isScaleOnlyOrNoTransform,
          onlyRetrieveFromCache,
          options,
          engineJob);

  // 放在Jobs内部维护的HashMap中
  jobs.put(key, engineJob);

  // 关注点8 后面分析会用到
  // 注册ResourceCallback接口
  engineJob.addCallback(cb);
  // 内部开启线程去请求
  engineJob.start(decodeJob);

  if (VERBOSE_IS_LOGGABLE) 
    logWithTimeAndKey("Started new load", startTime,   key);
  
  return new LoadStatus(cb, engineJob);


public void start(DecodeJob<R> decodeJob) 
    this.decodeJob = decodeJob;
    // willDecodeFromCache方法内部根据不同的阶段stage,如果是RESOURCE_CACHE/DATA_CACHE则返回true,使用diskCacheExecutor,否则调用getActiveSourceExecutor,内部会根据相应的条件返回sourceUnlimitedExecutor/animationExecutor/sourceExecutor
    GlideExecutor executor =   
    decodeJob.willDecodeFromCache()
        ? diskCacheExecutor
        : getActiveSourceExecutor();
    executor.execute(decodeJob);


可以看到,最终Engine(引擎)类内部会执行到自身的start方法,它会根据不同的配置采用不同的线程池使用diskCacheExecutor/sourceUnlimitedExecutor/animationExecutor/sourceExecutor来执行最终的解码任务decodeJob。

DecodeJob#run

runWrapped();

private void runWrapped() 
    switch (runReason) 
      case INITIALIZE:
        stage = getNextStage(Stage.INITIALIZE);
        // 关注点1
        currentGenerator = getNextGenerator();
        // 关注点2 内部会调用相应Generator的startNext()
        runGenerators();
        break;
      case SWITCH_TO_SOURCE_SERVICE:
        runGenerators();
        break;
      case DECODE_DATA:
        // 关注点3 将获取的数据解码成对应的资源
        decodeFromRetrievedData();
        break;
      default:
        throw new IllegalStateException("Unrecognized     run reason: " + runReason);
    


// 关注点1,完整情况下,会异步依次生成这里的ResourceCacheGenerator、DataCacheGenerator和SourceGenerator对象,并在之后执行其中的startNext()
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);
      case FINISHED:
        return null;
      default:
        throw new IllegalStateException("Unrecognized     stage: " + stage);
    


SourceGenerator#startNext

// 关注点2
@Override
public boolean startNext() 
  // dataToCache数据不为空的话缓存到硬盘(第一执行该方法是不会调用的)
  if (dataToCache != null) 
    Object data = dataToCache;
    dataToCache = null;
    cacheData(data);
  

  if (sourceCacheGenerator != null &&     sourceCacheGenerator.startNext()) 
    return true;
  
  sourceCacheGenerator = null;

  loadData = null;
  boolean started = false;
  while (!started && hasNextModelLoader()) 
    // 关注点4 getLoadData()方法内部会在modelLoaders里面找到ModelLoder对象
    // (每个Generator对应一个ModelLoader),
    // 并使用modelLoader.buildLoadData方法返回一个loadData列表
    loadData =   helper.getLoadData().get(loadDataListIndex++);
    if (loadData != null
        && (helper.getDiskCacheStrategy().isDataCache  able(loadData.fetcher.getDataSource())
        || helper.hasLoadPath(loadData.fetcher.getDat  aClass()))) 
      started = true;
      // 关注点6 通过loadData对象的fetcher对象(有关注点3的分析可知其实现类为HttpUrlFetcher)的
      // loadData方法来获取图片数据
      loadData.fetcher.loadData(helper.getPriority(),     this);
    
  
  return started;


DecodeHelper#getLoadData

List<LoadData<?>> getLoadData() 
    if (!isLoadDataSet) 
      isLoadDataSet = true;
      loadData.clear();
      List<ModelLoader<Object, ?>> modelLoaders =   glideContext.getRegistry().getModelLoaders(model)  ;
      //noinspection ForLoopReplaceableByForEach to   improve perf
      for (int i = 0, size = modelLoaders.size(); i <   size; i++) 
        ModelLoader<Object, ?> modelLoader =     modelLoaders.get(i);
        // 注意:这里最终是通过HttpGlideUrlLoader的buildLoadData获取到实际的loadData对象
        LoadData<?> current =
            modelLoader.buildLoadData(model, width,     height, options);
        if (current != null) 
          loadData.add(current);
        
      
    
    return loadData;


HttpGlideUrlLoader#buildLoadData

@Override
public LoadData<InputStream> buildLoadData(@NonNull   GlideUrl model, int width, int height,
    @NonNull Options options) 
  // GlideUrls memoize parsed URLs so caching them     saves a few object instantiations and time
  // spent parsing urls.
  GlideUrl url = model;
  if (modelCache != null) 
    url = modelCache.get(model, 0, 0);
    if (url == null) 
      // 关注点5
      modelCache.put(model, 0, 0, model);
      url = model;
    
  
  int timeout = options.get(TIMEOUT);
  // 注意,这里创建了一个DataFetcher的实现类HttpUrlFetcher
  return new LoadData<>(url, new HttpUrlFetcher(url,     timeout));


// 关注点5
public void put(A model, int width, int height, B value) 
    ModelKey<A> key = ModelKey.get(model, width,     height);
    // 最终是通过LruCache来缓存对应的值,key是一个ModelKey对象(由model、width、height三个属性组成)
    cache.put(key, value);


从这里的分析,我们明白了HttpUrlFetcher实际上就是最终的请求执行者,而且,我们知道了Glide会使用LruCache来对解析后的url来进行缓存,以便后续可以省去解析url的时间。

HttpUrlFetcher#loadData

@Override
public void loadData(@NonNull Priority priority,
    @NonNull DataCallback<? super InputStream>   callback) 
  long startTime = LogTime.getLogTime();
  try 
    // 关注点6
    // loadDataWithRedirects内部是通过HttpURLConnection网络请求数据
    InputStream result =   loadDataWithRedirects(glideUrl.toURL(), 0, null,   glideUrl.getHeaders());
    // 请求成功回调onDataReady()
    callback.onDataReady(result);
   catch (IOException e) 
    if (Log.isLoggable(TAG, Log.DEBUG)) 
      Log.d(TAG, "Failed to load data for url", e);
    
    callback.onLoadFailed(e);
   finally 
    if (Log.isLoggable(TAG, Log.VERBOSE)) 
      Log.v(TAG, "Finished http url fetcher fetch in     " + LogTime.getElapsedMillis(startTime));
    
  


private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl,
  Map<String, String> headers) throws IOException 
    
    ...

    urlConnection.connect();
    // Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352.
    stream = urlConnection.getInputStream();
    if (isCancelled) 
      return null;
    
    final int statusCode = urlConnection.getResponseCode();
    // 只要是2xx形式的状态码则判断为成功
    if (isHttpOk(statusCode)) 
      // 从urlConnection中获取资源流
      return getStreamForSuccessfulRequest(urlConnection);
     else if (isHttpRedirect(statusCode)) 
    
      ...
      
      // 重定向请求
      return loadDataWithRedirects(redirectUrl, redirects + 1, url,   headers);
     else if (statusCode == INVALID_STATUS_CODE) 
      throw new HttpException(statusCode);
     else 
      throw new HttpException(urlConnection.getResponseMessage(),   statusCode);
    


private InputStream getStreamForSuccessfulRequest(HttpURLConnection urlConnection)
  throws IOException 
    if (TextUtils.isEmpty(urlConnection.getContentEncoding())) 
      int contentLength = urlConnection.getContentLength();
      stream = ContentLengthInputStream.obtain(urlConnection.getInputStr  eam(), contentLength);
     else 
      if (Log.isLoggable(TAG, Log.DEBUG)) 
        Log.d(TAG, "Got non empty content encoding: " +     urlConnection.getContentEncoding());
      
      stream = urlConnection.getInputStream();
    
    return stream;


在HttpUrlFetcher#loadData方法的loadDataWithRedirects里面,Glide通过原生的HttpURLConnection进行请求后,并调用getStreamForSuccessfulRequest()方法获取到了最终的图片流。

DecodeJob#run

在我们通过HtttpUrlFetcher的loadData()方法请求得到对应的流之后,我们还必须对流进行处理得到最终我们想要的资源。这里我们回到第10步DecodeJob#run方法的关注点3处,这行代码将会对流进行解码。

decodeFromRetrievedData();

接下来,继续看看他内部的处理。

private void decodeFromRetrievedData() 
    if (Log.isLoggable(TAG, Log.VERBOSE)) 
      logWithTimeAndKey("Retrieved data", startFetchTime,
          "data: " + currentData
              + ", cache key: " + currentSourceKey
              + ", fetcher: " + currentFetcher);
    
    Resource<R> resource = null;
    try 
      //  核心代码 
      // 从数据中解码得到资源
      resource = decodeFromData(currentFetcher, currentData,   currentDataSource);
     catch (GlideException e) 
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    
    if (resource != null) 
      // 关注点8 
      // 编码和发布最终得到的Resource<Bitmap>对象
      notifyEncodeAndRelease(resource, currentDataSource);
     else 
      runGenerators();
    


 private <Data> Resource<R> decodeFromData(DataFetcher<?> fetcher, Data data,
  DataSource dataSource) throws GlideException 
    try 
      if (data == null) 
        return null;
      
      long startTime = LogTime.getLogTime();
      // 核心代码
      // 进一步包装了解码方法
      Resource<R> result = decodeFromFetcher(data, dataSource);
      if (Log.isLoggable(TAG, Log.VERBOSE)) 
        logWithTimeAndKey("Decoded result " + result, startTime);
      
      return result;
     finally 
      fetcher.cleanup();
    


@SuppressWarnings("unchecked")
private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
  throws GlideException 
    LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
    // 核心代码
    // 将解码任务分发给LoadPath
    return runLoadPath(data, dataSource, path);


private <Data, ResourceType> Resource<R> runLoadPath(Data data, DataSource dataSource,
  LoadPath<Data, ResourceType, R> path) throws GlideException 
    Options options = getOptionsWithHardwareConfig(dataSource);
    // 将数据进一步包装
    DataRewinder<Data> rewinder =     glideContext.getRegistry().getRewinder(data);
    try 
      // ResourceType in DecodeCallback below is required for   compilation to work with gradle.
      // 核心代码
      // 将解码任务分发给LoadPath
      return path.load(
          rewinder, options, width, height, new   DecodeCallback<ResourceType>(dataSource));
     finally 
      rewinder.cleanup();
    


LoadPath#load

public Resource<Transcode> load(DataRewinder<Data> rewinder, @NonNull Options options, int width,
  int height, DecodePath.DecodeCallback<ResourceType> decodeCallback) throws GlideException 
List<Throwable> throwables = Preconditions.checkNotNull(listPool.acquire());
try 
  // 核心代码
  return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
 finally 
  listPool.release(throwables);


private Resource<Transcode> loadWithExceptionList(DataRewinder<Data> rewinder,
      @NonNull Options options,
      int width, int height, DecodePath.DecodeCallback<ResourceType>   decodeCallback,
      List<Throwable> exceptions) throws GlideException 
    Resource<Transcode> result = null;
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0, size = decodePaths.size(); i < size; i++) 
      DecodePath<Data, ResourceType, Transcode> path =   decodePaths.get(i);
      try 
        // 核心代码
        // 将解码任务又进一步分发给DecodePath的decode方法去解码
        result = path.decode(rewinder, width, height, options,     decodeCallback);
       catch (GlideException e) 
        exceptions.add(e);
      
      if (result != null) 
        break;
      
    

    if (result == null) 
      throw new GlideException(failureMessage, new   ArrayList<>(exceptions));
    

    return result;


DecodePath#decode

public Resource<Transcode> decode(DataRewinder<DataType> rewinder,     int width, int height,
      @NonNull Options options, DecodeCallback<ResourceType> callback)   throws GlideException 
    // 核心代码
    // 继续调用DecodePath的decodeResource方法去解析出数据
    Resource<ResourceType> decoded = decodeResource(rewinder, width,     height, options);
    Resource<ResourceType> transformed =     callback.onResourceDecoded(decoded);
    return transcoder.transcode(transformed, options);


@NonNull
private Resource<ResourceType> decodeResource(DataRewinder<DataType>   rewinder, int width,
    int height, @NonNull Options options) throws GlideException 
  List<Throwable> exceptions =     Preconditions.checkNotNull(listPool.acquire());
  try 
    // 核心代码
    return decodeResourceWithList(rewinder, width, height, options,   exceptions);
   finally 
    listPool.release(exceptions);
  


@NonNull
private Resource<ResourceType>   decodeResourceWithList(DataRewinder<DataType> rewinder, int width,
    int height, @NonNull Options options, List<Throwable> exceptions)   throws GlideException 
  Resource<ResourceType> result = null;
  //noinspection ForLoopReplaceableByForEach to improve perf
  for (int i = 0, size = decoders.size(); i < size; i++) 
    ResourceDecoder<DataType, ResourceType> decoder = decoders.get(i);
    try 
      DataType data = rewinder.rewindAndGet();
      if (decoder.handles(data, options)) 
        // 获取包装的数据
        data = rewinder.rewindAndGet();
        // 核心代码 
        // 根据DataType和ResourceType的类型分发给不同的解码器Decoder
        result = decoder.decode(data, width, height, options);
      
     catch (IOException | RuntimeException | OutOfMemoryError e) 
      if (Log.isLoggable(TAG, Log.VERBOSE)) 
        Log.v(TAG, "Failed to decode data for " + decoder, e);
      
      exceptions.add(e);
    

    if (result != null) 
      break;
    
  

  if (result == null) 
    throw new GlideException(failureMessage, new   ArrayList<>(exceptions));
  
  return result;


可以看到,经过一连串的嵌套调用,最终执行到了decoder.decode()这行代码,decode是一个ResourceDecoder<DataType, ResourceType>接口(资源解码器),根据不同的DataType和ResourceType它会有不同的实现类,这里的实现类是ByteBufferBitmapDecoder,接下来让我们来看看这个解码器内部的解码流程。

ByteBufferBitmapDecoder#decode

/**
 * Decodes @link android.graphics.Bitmap Bitmaps from @link    java.nio.ByteBuffer ByteBuffers.
 */
public class ByteBufferBitmapDecoder implements     ResourceDecoder<ByteBuffer, Bitmap> 
  
  ...

  @Override
  public Resource<Bitmap> decode(@NonNull ByteBuffer source, int width,   int height,
      @NonNull Options options)
      throws IOException 
    InputStream is = ByteBufferUtil.toStream(source);
    // 核心代码
    return downsampler.decode(is, width, height, options);
  


可以看到,最终是使用了一个downsampler,它是一个压缩器,主要是对流进行解码,压缩,圆角等处理。

DownSampler#decode

public Resource<Bitmap> decode(InputStream is, int outWidth, int outHeight,
  Options options) throws IOException 
    return decode(is, outWidth, outHeight, options, EMPTY_CALLBACKS);


 @SuppressWarnings("resource", "deprecation")
public Resource<Bitmap> decode(InputStream is, int requestedWidth, int requestedHeight,
      Options options, DecodeCallbacks callbacks) throws IOException 
    Preconditions.checkArgument(is.markSupported(), "You must provide an     InputStream that supports"
        + " mark()");

    ...

    try 
      // 核心代码
      Bitmap result = decodeFromWrappedStreams(is, bitmapFactoryOptions,
          downsampleStrategy, decodeFormat, isHardwareConfigAllowed,   requestedWidth,
          requestedHeight, fixBitmapToRequestedDimensions, callbacks);
      // 关注点7   
      // 解码得到Bitmap对象后,包装成BitmapResource对象返回,
      // 通过内部的get方法得到Resource<Bitmap>对象
      return BitmapResource.obtain(result, bitmapPool);
     finally 
      releaseOptions(bitmapFactoryOptions);
      byteArrayPool.put(bytesForOptions);
    


private Bitmap decodeFromWrappedStreams(InputStream is,
      BitmapFactory.Options options, DownsampleStrategy downsampleStrategy,
      DecodeFormat decodeFormat, boolean isHardwareConfigAllowed, int requestedWidth,
      int requestedHeight, boolean fixBitmapToRequestedDimensions,
      DecodeCallbacks callbacks) throws IOException 
    
    // 省去计算压缩比例等一系列非核心逻辑
    ...
    
    // 核心代码
    Bitmap downsampled = decodeStream(is, options, callbacks, bitmapPool);
    callbacks.onDecodeComplete(bitmapPool, downsampled);

    ...

    // Bimtap旋转处理
    ...
    
    return rotated;


private static Bitmap decodeStream(InputStream is,     BitmapFactory.Options options,
      DecodeCallbacks callbacks, BitmapPool bitmapPool) throws   IOException 
    
    ...
    
    TransformationUtils.getBitmapDrawableLock().lock();
    try 
      // 核心代码
      result = BitmapFactory.decodeStream(is, null, options);
     catch (IllegalArgumentException e) 
      ...
     finally 
      TransformationUtils.getBitmapDrawableLock().unlock();
    

    if (options.inJustDecodeBounds) 
      is.reset();
    
    return result;


从以上源码流程我们知道,最后是在DownSampler的decodeStream()方法中使用了BitmapFactory.decodeStream()来得到Bitmap对象。然后,我们来分析下图片时如何显示的,我们回到步骤19的DownSampler#decode方法,看到关注点7,这里是将Bitmap包装成BitmapResource对象返回,通过内部的get方法可以得到Resource对象,再回到步骤15的DecodeJob#run方法,这是使用了notifyEncodeAndRelease()方法对Resource对象进行了发布。

DecodeJob#notifyEncodeAndRelease

private void notifyEncodeAndRelease(Resource<R> resource, DataSource     dataSource) 
 
    ...

    notifyComplete(result, dataSource);

    ...
    


private void notifyComplete(Resource<R> resource, DataSource     dataSource) 
    setNotifiedOrThrow();
    callback.onResourceReady(resource, dataSource);


从以上EngineJob的源码可知,它实现了DecodeJob.CallBack这个接口。

class EngineJob<R> implements DecodeJob.Callback<R>,
    Poolable 
    ...


EngineJob#onResourceReady

@Override
public void onResourceReady(Resource<R> resource, DataSource   dataSource) 
  this.resource = resource;
  this.dataSource = dataSource;
  MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();


private static class MainThreadCallback implements Handler.Callback

    ...

    @Override
    public boolean handleMessage(Message message) 
      EngineJob<?> job = (EngineJob<?>) message.obj;
      switch (message.what) 
        case MSG_COMPLETE:
          // 核心代码
          job.handleResultOnMainThread();
          break;
        ...
      
      return true;
    


从以上源码可知,通过主线程Handler对象进行切换线程,然后在主线程调用了handleResultOnMainThread这个方法。

@Synthetic
void handleResultOnMainThread() 
  ...

  //noinspection ForLoopReplaceableByForEach to improve perf
  for (int i = 0, size = cbs.size(); i < size; i++) 
    ResourceCallback cb = cbs.get(i);
    if (!isInIgnoredCallbacks(cb)) 
      engineResource.acquire();
      cb.onResourceReady(engineResource, dataSource);
    
  
 
  ...


这里又通过一个循环调用了所有ResourceCallback的方法,让我们回到步骤9处Engine#load方法的关注点8这行代码,这里对ResourceCallback进行了注册,在步骤8出SingleRequest#onSizeReady方法里的engine.load中,我们看到最后一个参数,传入的是this,可以明白,engineJob.addCallback(cb)这里的cb的实现类就是SingleRequest。接下来,让我们看看SingleRequest的onResourceReady方法。

SingleRequest#onResourceReady

/**
 * A callback method that should never be invoked directly.
 */
@SuppressWarnings("unchecked")
@Override
public void onResourceReady(Resource<?> resource, DataSource   dataSource) 
  ...
  
  // 从Resource<Bitmap>中得到Bitmap对象
  Object received = resource.get();
  
  ...
  
  onResourceReady((Resource<R>) resource, (R) received, dataSource);


private void onResourceReady(Resource<R> resource, R resultDataSource dataSource) 

    ...

    try 
      ...

      if (!anyListenerHandledUpdatingTarget) 
        Transition<? super R> animation =
            animationFactory.build(dataSource, isFirstResource);
        // 核心代码
        target.onResourceReady(result, animation);
      
     finally 
      isCallingCallbacks = false;
    

    notifyLoadSuccess();


在SingleRequest#onResourceReady方法中又调用了target.onResourceReady(result, animation)方法,这里的target其实就是我们在into方法中建立的那个BitmapImageViewTarget,看到BitmapImageViewTarget类,我们并没有发现onResourceReady方法,但是我们从它的子类ImageViewTarget中发现了onResourceReady方法,从这里继续往下看。

ImageViewTarget#onResourceReady

public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z>
implements Transition.ViewAdapter 

    ...

    @Override
    public void onResourceReady(@NonNull Z resource, @Nullable       Transition<? super Z> transition) 
      if (transition == null || !transition.transition(resource, this))   
        // 核心代码
        setResourceInternal(resource);
       else 
        maybeUpdateAnimatable(resource);
      
    
 
    ...
    
    private void setResourceInternal(@Nullable Z resource) 
        // Order matters here. Set the resource first to make sure that the         Drawable has a valid and
        // non-null Callback before starting it.
        // 核心代码
        setResource(resource);
        maybeUpdateAnimatable(resource);
    
    
    // 核心代码
    protected abstract void setResource(@Nullable Z resource);


这里我们在回到BitmapImageViewTarget的setResource方法中,终于看到Bitmap被设置到了当前的imageView上了。

public class BitmapImageViewTarget extends ImageViewTarget<Bitmap> 

    ...
    
    
    @Override
    protected void setResource(Bitmap resource) 
      view.setImageBitmap(resource);
    


到这里,我们的分析就结束了,从以上的分析可知,Glide将大部分的逻辑处理都放在了最后一个into方法中,里面经过了20多个分析步骤才将请求图片流、解码出图片,到最终设置到对应的imageView上。

1.5.完整Glide加载流程图


可以看到,Glide最核心的逻辑都聚集在into()方法中,它里面的设计精巧而复杂,这部分的源码分析非常耗时,但是,如果你真真正正地去一步步去深入其中,你也许在Android进阶之路上将会有顿悟的感觉。

四丶Dagger 2

1.预备知识

1.1.@Inject

告诉dagger这个字段或类需要依赖注入,然后在需要依赖的地方使用这个注解,dagger会自动生成这个构造器的实例。

获取所需依赖:

  • 全局变量注入
  • 方法注入

提供所需实例:

  • 构造器注入(如果有多个构造函数,只能注解一个,否则编译报错)

1.2.@Module

类注解,表示此类的方法是提供依赖的,它告诉dagger在哪可以找到依赖。用于不能用@Inject提供依赖的地方,如第三方库提供的类,基本数据类型等不能修改源码的情况。

注意:Dagger2会优先在@Module注解的类上查找依赖,没有的情况才会去查询类的@Inject构造方法

1.3.@Singleton

声明这是一个单例,在确保只有一个Component并且不再重新build()之后,对象只会被初始化一次,之后的每次都会被注入相同的对象,它就是一个内置的作用域。

对于@Singleton,大家可能会产生一些误解,这里详细阐述下:

  • Singleton容易给人造成一种误解就是用Singleton注解后在整个Java代码中都是单例,但实际上他和Scope一样,只是在同一个Component是单例。也就是说,如果重新调用了component的build()方法,即使使用了Singleton注解了,但仍然获取的是不同的对象。
  • 它表明了**@Singleton注解只是声明了这是一个单例,为的只是提高代码可读性,其实真正控制对象生命周期的还是Component**。同理,自定义的@ActivityScope 、@ApplicationScope也仅仅是一个声明的作用,真正控制对象生命周期的还是Component

1.4.@Providers

只在@Module中使用,用于提供构造好的实例。一般与@Singleton搭配,用单例方法的形式对外提供依赖,是一种替代@Inject注解构造方法的方式。

注意:

  • 使用了@Providers的方法应使用provide作为前缀,使用了@Module的类应使用Module作为后缀。
  • 如果@Providers方法或@Inject构造方法有参数,要保证它能够被dagger获取到,比如通过其它@Providers方法或者@Inject注解构造器的形式得到

1.5.@Component

@Component作为Dagger2的容器总管,它拥有着@Inject与@Module的所有依赖。同时,它也是一枚注射器,用于获取所需依赖和提供所需依赖的桥梁。这里的桥梁即指@Inject和@Module(或@Inject构造方法)之间的桥梁。定义时需要列出响应的Module组成,此外,还可以使用dependencies继承父Component。

Component与Module的区别:

Component既是注射器也是一个容器总管,而module则是作为容器总管Component的子容器,实质是一个用于提供依赖的模块。

1.6.@Scope

注解作用域,通过自定义注解限定对象作用范围,增强可读性

@Scope有两种常用的使用场景:

  • 模拟Singleton代表全局单例,与Component生命周期关联
  • 模拟局部单例,如登录到退出登录期间

1.7.@Qualifier

限定符,利用它定义注解类以用于区分类的不同实例。例如:2个方法返回不同的Person对象,比如说小明和小华,为了区分,使用@Qualifier定义的注解类。

dependencies

使用它表示ChildComponent依赖于FatherComponent,如下所示:

@Component(modules = ChildModule.class, dependencies = FatherComponent.class)
public interface ChildComponent 
    ...


1.8.@SubComponent

表示是一个子@Component,它能将应用的不同部分封装起来,用来替代@Dependencies

2.简单示例

2.1.首先,创建一个BaseActivityComponent的Subcomponent:

@Subcomponent(modules = AndroidInjectionModule.class)
public interface BaseActivityComponent extends AndroidInjector<BaseActivity> 

    @Subcomponent.Builder
    abstract class BaseBuilder extends AndroidInjector.Builder<BaseActivity>
    


这里必须要注解成@Subcomponent.Builder表示是顶级@Subcomponent的内部类。AndroidInjector.Builder的泛型指定了BaseActivity,即表示每一个继承于BaseActivity的Activity都继承于同一个子组件(BaseActivityComponent)。

2.2.然后,创建一个将会导入Subcomponent的公有Module。

// 1
@Module(subcomponents = BaseActivityComponent.class)
public abstract class AbstractAllActivityModule 

    @ContributesAndroidInjector(modules = MainActivityModule.class)
    abstract MainActivity contributesMainActivityInjector();

    @ContributesAndroidInjector(modules = SplashActivityModule.class)
    abstract SplashActivity contributesSplashActivityInjector();
    
    // 一系列的对应Activity的contributesxxxActivityInjector
    ...
    


在注释1处用subcomponents来表示开放全部依赖给AbstractAllActivityModule,使用Subcomponent的重要原因是它将应用的不同部分封装起来了。@AppComponent负责维护共享的数据和对象,而不同处则由各自的@Subcomponent维护

2.3.接着,配置项目的Application。

public class WanAndroidApp extends Application implements HasActivityInjector 

    // 3
    @Inject
    DispatchingAndroidInjector<Activity> mAndroidInjector;

    private static volatile AppComponent appComponent;
    
    @Override
    public void onCreate() 
        super.onCreate();
        
        ...
        // 1
        appComponent = DaggerAppComponent.builder()
            .build();
        // 2
        appComponent.inject(this);
        
        ...
        
    
    
    ...
    
    // 4
    @Override
    public AndroidInjector<Activity> activityInjector() 
        return mAndroidInjector;
    


首先,在注释1处,使用AppModule模块和httpModule模块构建出AppComponent的实现类DaggerAppComponent。这里看一下AppComponent的配置代码:

@Singleton
@Component(modules = AndroidInjectionModule.class,
        AndroidSupportInjectionModule.class,
        AbstractAllActivityModule.class,
        AbstractAllFragmentModule.class,
        AbstractAllDialogFragmentModule.class
    )
public interface AppComponent 

    /**
     * 注入WanAndroidApp实例
     *
     * @param wanAndroidApp WanAndroidApp
     */
    void inject(WanAndroidApp wanAndroidApp);

以上是关于架构大合集,轻松应对工作需求(中)的主要内容,如果未能解决你的问题,请参考以下文章

架构大合集,轻松应对工作需求(上)

架构大合集,轻松应对工作需求(上)

架构大合集,轻松面对工作需求(下)

架构大合集,轻松面对工作需求(下)

2022最新分布式面试题合集,轻松应对Java面试

2022最新分布式面试题合集,轻松应对Java面试