Glide框架使用及分析(二)

前言

Glide框架使用及分析(一)中学习了Glide的基本使用方法,以其简单的API调用实现了图片加载功能,展现了这个图片加载框架的强大。
其在界面上加载图片只需要一行代码:

Glide.with(this).load(url).into(imageView);

仅仅这一行代码是如何进行图片加载的呢?Glide框架的内部是如何工作的?接下来我们就跟着这行代码窥探一下内部的奥秘吧!
以下代码的分析是基于Glide v4 版本的,有需要的朋友可以在github上面直接下载源码。

Glide.with()

首先我们看一下这个Glide的静态方法with()做了什么工作?

@NonNull
  public static RequestManager with(@NonNull Context context) {
    return getRetriever(context).get(context);
  }
  @NonNull
  public static RequestManager with(@NonNull Activity activity) {
    return getRetriever(activity).get(activity);
  }
  @NonNull
  public static RequestManager with(@NonNull FragmentActivity activity) {
    Log.e(TAG, "with: --根据上下文获取RequestManager对象");
    return getRetriever(activity).get(activity);
  }
  @NonNull
  public static RequestManager with(@NonNull Fragment fragment) {
    return getRetriever(fragment.getContext()).get(fragment);
  }
  @SuppressWarnings("deprecation")
  @Deprecated
  @NonNull
  public static RequestManager with(@NonNull android.app.Fragment fragment) {
    return getRetriever(fragment.getActivity()).get(fragment);
  }
  @NonNull
  public static RequestManager with(@NonNull View view) {
    return getRetriever(view.getContext()).get(view);
  }

Glide中有很多重载的with静态方法,看源码可以了解到重载方法的参数例如之前所说,包含context、activity、fragment、设置是view对象等,方法中调用了getRetriever(view.getContext()).get(view)返回了RequestManager对象,接下来我们具体看一下这句代码做了什么?

@NonNull
  private static RequestManagerRetriever getRetriever(@Nullable Context context) {
    //检测context是否为空,如果为空则抛出异常
    Preconditions.checkNotNull(
        context,
        "You cannot start a load on a not yet attached View or a Fragment where getActivity() "
            + "returns null (which usually occurs when getActivity() is called before the Fragment "
            + "is attached or after the Fragment is destroyed).");
    return Glide.get(context).getRequestManagerRetriever();
  }
    @NonNull
  // 这里是一个典型的双检锁单例模式
  @SuppressWarnings("GuardedBy")
  public static Glide get(@NonNull Context context) {
    if (glide == null) {
      //获取GeneratedAppGlideModuleImpl对象
      GeneratedAppGlideModule annotationGeneratedModule =
          getAnnotationGeneratedGlideModules(context.getApplicationContext());
      synchronized (Glide.class) {
        if (glide == null) {
          checkAndInitializeGlide(context, annotationGeneratedModule);
        }
      }
    }

    return glide;
  }

1,getRetriever()此方法判断了传入的context是否为空,为空则抛出异常,不为空则调用了Glide.get()方法。
2,Glide.get()方法是一个典型的双检锁单例模式,主要是创建Glide对象,以及初始化Glide相关参数(Glide对象的创建以及初始化的参数比较复杂)。
3,通过Glide对象获取RequestManagerRetriever对象
4,调用RequestManagerRetriever中的get()方法,这个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)) {
      if (context instanceof FragmentActivity) {
        return get((FragmentActivity) context);
      } else if (context instanceof Activity) {
        return get((Activity) context);
      } else if (context instanceof ContextWrapper
          && ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
        return get(((ContextWrapper) context).getBaseContext());
      }
    }
    return getApplicationManager(context);
  }
  @NonNull
  public RequestManager get(@NonNull FragmentActivity activity) {
    Log.e(TAG, "get: isOnBackgroundThread::"+Util.isOnBackgroundThread() );
    //判断是否是后台线程,如果是则使用ApplicationContext重新获取
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else {
      //判断页面是否销毁
      assertNotDestroyed(activity);
      maybeRegisterFirstFrameWaiter(activity);
      //获取当前页面的fragmentmanager
      FragmentManager fm = activity.getSupportFragmentManager();
      return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }
  @NonNull
  public RequestManager get(@NonNull Fragment fragment) {
    Preconditions.checkNotNull(
        fragment.getContext(),
        "You cannot start a load on a fragment before it is attached or after it is destroyed");
    if (Util.isOnBackgroundThread()) {
      return get(fragment.getContext().getApplicationContext());
    } else {
      maybeRegisterFirstFrameWaiter(fragment.getActivity());
      FragmentManager fm = fragment.getChildFragmentManager();
      return supportFragmentGet(fragment.getContext(), fm, fragment, fragment.isVisible());
    }
  }
  @SuppressWarnings("deprecation")
  @NonNull
  public RequestManager get(@NonNull Activity activity) {
    if (Util.isOnBackgroundThread()) {
      return get(activity.getApplicationContext());
    } else if (activity instanceof FragmentActivity) {
      return get((FragmentActivity) activity);
    } else {
      assertNotDestroyed(activity);
      maybeRegisterFirstFrameWaiter(activity);
      android.app.FragmentManager fm = activity.getFragmentManager();
      return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
    }
  }
  @SuppressWarnings("deprecation")
  @NonNull
  public RequestManager get(@NonNull View view) {
    if (Util.isOnBackgroundThread()) {
      return get(view.getContext().getApplicationContext());
    }
    Preconditions.checkNotNull(view);
    Preconditions.checkNotNull(
        view.getContext(), "Unable to obtain a request manager for a view without a Context");
    Activity activity = findActivity(view.getContext());
    // The view might be somewhere else, like a service.
    if (activity == null) {
      return get(view.getContext().getApplicationContext());
    }
    if (activity instanceof FragmentActivity) {
      Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
      return fragment != null ? get(fragment) : get((FragmentActivity) activity);
    }
    // Standard Fragments.
    android.app.Fragment fragment = findFragment(view, activity);
    if (fragment == null) {
      return get(activity);
    }
    return get(fragment);
  }

这里分析一下参数为fragmentactivity的:
1,首先判断一下是否是子线程执行,如果是子线程则直接强制使用ApplicationContext从新获取
2,判断页面是否销毁,如果没有在获取当前页面的fragmentmanager,
3,调用supportFragmentGet()方法来获取RequestManager对象:

//Glide是通过在页面中添加一个Fragment来动态监听页面的创建和销毁,
  // 从而达到依赖页面生命周期,动态管理请求的目的
  @NonNull
  private RequestManager supportFragmentGet(
      @NonNull Context context,
      @NonNull FragmentManager fm,
      @Nullable Fragment parentHint,
      boolean isParentVisible) {
    SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
      // TODO(b/27524013): Factor out this Glide.get() call.
      Glide glide = Glide.get(context);
      requestManager =
          factory.build(
              glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
      if (isParentVisible) {
        requestManager.onStart();
      }
      current.setRequestManager(requestManager);
    }
    return requestManager;
  }

到此,我们的with方法中获取RequestManager对象就已完成。
来看下with方法执行的顺序图:
在这里插入图片描述

load()方法

接下来我们点击进入查看一下load()方法做了什么事情?在RequestManager类中,load()方法也有很多重载方法,着重看一下我们使用到的,如下所示:

/**
   * 下载图片
   * @param string url地址
   * @return
   */
  @NonNull
  @CheckResult
  @Override
  public RequestBuilder<Drawable> load(@Nullable String string) {
    Log.e(TAG, "load string url: "+string );
    return asDrawable().load(string);
  }

我们将url传入load()方法中,此方法先是调用了asDrawable()方法,这个方法主要是配置图片的信息,设置其显示的形式,主要调用了as()方法。

/**
   * @return A new request builder for loading a {@link Drawable}.
   * 配置图片的信息,
   * 加载获取的图片资源是转换为drawable或者其他的例如bitmap或者GIF进行图片显示
   */
  @NonNull
  @CheckResult
  public RequestBuilder<Drawable> asDrawable() {
    return as(Drawable.class);
  }
   @NonNull
  @CheckResult
  public <ResourceType> RequestBuilder<ResourceType> as(
      @NonNull Class<ResourceType> resourceClass) {
    //初始化了RequestBinder对象,将Glide对象,requestmanager对象,以及图片class及上下文传入
    Log.e(TAG, "as: 初始化了RequestBuilder对象" );
    return new RequestBuilder<>(glide, this, resourceClass, context);
  }

as方法主要创建了一个RequestBuilder对象,并传入了相关的参数进去,完成了asDrawable()方法调用之后返回来RequestBuilder对象调用load方法:

  @NonNull
  @Override
  @CheckResult
  public RequestBuilder<TranscodeType> load(@Nullable String string) {
    Log.e(TAG, "load: "+string );
    return loadGeneric(string);
  }
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
    Log.e(TAG, "loadGeneric: -------load方法调用完成");
    this.model = model;
    isModelSet = true;
    return this;
  }

load方法中调用了loadGeneric()方法,loadGeneric()方法中也没有做太多的操作,只是保存了我们的url并且将isModelSet设置为true,意思是model已经设置了。
到此load方法执行完毕了,最终返回了RequestBuilder对象。
接下来将执行into方法了,我们的图片加载以及图片显示的逻辑都是这个方法完成的,由此可知其内部是十分复杂的,接下来我们会单独介绍一下into方法。欢迎点击!

十分感谢各位的阅读,如有大家有什么疑问或者有好的见解,欢迎给我留言,谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值