Glide加载流程分析(上)

    Glide一个强大的图片加载框架,注重于平滑的滚动,设计简洁易用的API,具有很强大的和扩展性。现在来对他的加载原理进行深入的分析,本文是基于最新版本4.6.1进行分析的。通常情况下Glide的使用如下一行代码就可以搞定。

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

    就沿着这个思路进行一步一步的分析。

一、with方法

    with方法存在于Glide里面,它提供了很多的重载方法,包含Context、Activity、FragmentActivity、Fragment、View五大重载的参数,因此它可以在这五类中使用。with返回的是RequestManager对象,这个对象在后面进一步说明。

      public static RequestManager with(Context context) {
        return getRetriever(context).get(context);
      }

      public static RequestManager with(Activity activity) {
        return getRetriever(activity).get(activity);
      }

      public static RequestManager with(FragmentActivity activity) {
        return getRetriever(activity).get(activity);
      }

      public static RequestManager with(android.app.Fragment fragment) {
        return getRetriever(fragment.getActivity()).get(fragment);
      }

      public static RequestManager with(Fragment fragment) {
        return getRetriever(fragment.getActivity()).get(fragment);
      }

      public static RequestManager with(View view) {
        return getRetriever(view.getContext()).get(view);
      }

    在上面的getRetriever方法主要是对传递过来的context对象做了一个非空校验,返回RequestManagerRetriever对象,这个类主要是区分传递过来的context是所属Activity或者Fragment等。RequestManagerRetriever中的get方法返回RequestManager对象,RequestManager这个类主要是和当前所在的Activity或者Fragment等进行生命周期绑定。

    1、getRetriever方法

      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).");
               //--a               --b
        return Glide.get(context).getRequestManagerRetriever();
      }

        --a、Glide的get方法是一个非常常见的一个双锁校验的单例模式,返回glide实例。

          public static Glide get(@NonNull Context context) {
            if (glide == null) {
              synchronized (Glide.class) {
                if (glide == null) {
                  //--c
                  checkAndInitializeGlide(context);
                }
              }
            }
            return glide;
          }

        --c、这个checkAndInitializeGlide最终调用的是:

          private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
            Context applicationContext = context.getApplicationContext();
            ...........................省略............................
            Glide glide = builder.build(applicationContext);
            ............................省略...........................
            Glide.glide = glide;
          }

       这个builder.build方法就是创建Glide,GlideBuilder里面主要初始化了一些相关参数,例如:资源线程池,内存缓存线程池,Bitmap线程池、动画池,内存创建,缓存大小以及相关设置等等,为了不偏离主线,这个类再次就不在深入了,后面在介绍。

        --b、getRequestManagerRetriever这个没有什么好说的。

          public RequestManagerRetriever getRequestManagerRetriever() {
            return requestManagerRetriever;
          }

    2、get方法

    get方法也有很多重载的方法和with方法类似,不可能全部做分析,这里就以其中的Context作为参数的get方法进行分析,首先是对他做了一个非空校验,然后判断当前的context属于哪个Fragment还是Fragment等,如果都不属于则默认是当前应用的context。

     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) {
            //获取当前FragmentActivity的RequestManager
           return get((FragmentActivity) context);
         } else if (context instanceof Activity) {
            //获取当前FragmentActivity的RequestManager    --a
           return get((Activity) context);
         } else if (context instanceof ContextWrapper) {
           //获取当前FragmentActivity的RequestManager
           return get(((ContextWrapper) context).getBaseContext());
         }
       }
        //获取当前整个应用的RequestManager
       return getApplicationManager(context);
     }

    3、Glide和Activity生命周期绑定

     以上面的--a为例,根据Activity创建一个fragment用来和Glide生命周期绑定。看下面的注释:

     public RequestManager get(@NonNull Activity activity) {
       //判断是否在子线程,如果是在子线程则获取整个应用的application,
       //否则是在主线程,和当前所在的Activity或者Fragment生命周期绑定,这个是在RequestManager类实现的。
       if (Util.isOnBackgroundThread()) {
         return get(activity.getApplicationContext());
       } else {
        //判断当前的Activity是否被销毁
         assertNotDestroyed(activity);
         //获取当前activity的FragmentManager管理类
         android.app.FragmentManager fm = activity.getFragmentManager();
         //根据当前Activity创建一个fragment用来和Glide生命周期绑定
         return fragmentGet(activity, fm, null /*parentHint*/);
       }
     }
       private RequestManager fragmentGet(@NonNull Context context,
           @NonNull android.app.FragmentManager fm,
           @Nullable android.app.Fragment parentHint) {
         //创建一个Fragment    --a
         RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
         //根据当前的Fragment得到RequestManager
         RequestManager requestManager = current.getRequestManager();
         if (requestManager == null) {
           //如果当前的requestManager为空,则获取Glide
           Glide glide = Glide.get(context);
           /** 创建requestManager(核心)
             * 参数一:glide
             * 参数二:当前Fragment的ActivityFragmentLifecycle,他实现了Lifecycle接口是一个观察者设计模式,用set存储
             * LifecycleListener来观察事件的开始、停止、移除、销毁。该方法的初始化值是在getRequestManagerFragment方法里面
             * 请参考--a说明
             * 参数三:基于Context的RequestManager上下文环境,请参考--a说明
             */
           requestManager =factory.build(glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
           //给当前的Fragment设置一个RequestManager
           current.setRequestManager(requestManager);
         }
         return requestManager;
       }
       private static final RequestManagerFactory DEFAULT_FACTORY = new RequestManagerFactory() {

         @Override
         public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle,
             @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) {
           //直接返回RequestManager实例对象,RequestManager中具体的生命周期管理见下面4。
           return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
         }
       };
        --a、getRequestManagerFragment
          RequestManagerFragment getRequestManagerFragment(
              @NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint) {
            //通过tag获取当前的Fragment
            RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
            //如果获取不到
            if (current == null) {
              //从存储的Map集合中获取
              current = pendingRequestManagerFragments.get(fm);
              if (current == null) {
                //如果还是没有则说明没有创建过该Fragment,即该Activity或者Fragment是新的页面,之前没有请求过重写创建  --b
                current = new RequestManagerFragment();
                current.setParentFragmentHint(parentHint);
                //存储到Map集合中
                pendingRequestManagerFragments.put(fm, current);
                //提交
                fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
                //发送消息,设置tag
                handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
              }
            }
            return current;
          }

        --b、RequestManagerFragment

         public class RequestManagerFragment extends Fragment {

              ………………………………………………………………………省略部分代码……………………………………………………………………………………

              private static final String TAG = "RMFragment";

              public RequestManagerFragment() {
                //在此创建ActivityFragmentLifecycle对象,该类实现Lifecycle接口,在该类中创建Set,
                //在重写的方法中监听Activity的生命周期回调
                this(new ActivityFragmentLifecycle());
              }

              RequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
                this.lifecycle = lifecycle;
              }

              public RequestManagerTreeNode getRequestManagerTreeNode() {
                return requestManagerTreeNode;
              }

              public RequestManager getRequestManager() {
                return requestManager;
              }

             //在此返回lifecycle,注意这个lifecycle是当前的页面(Activity、Fragment)所属的的lifecycle
              ActivityFragmentLifecycle getGlideLifecycle() {
                return lifecycle;
              }
              ………………………………………………………………………省略部分代码……………………………………………………………………………………
          }

    4、RequestManager的构造方法

    RequestManager是一个核心类,主要作用是实现图片加载和当前页面的生命周期绑定,便于图片管理,避免了内存泄漏、图片错位等问题,使其更加智能。在上面的Glide和Activity生命周期绑定分析的最后,我们看到RequestManagerRetriever中RequestManagerFactory的build方法直接返回new RequestManager,因此我们从这个构造方法入手。

      RequestManager(
          Glide glide,
          Lifecycle lifecycle,
          RequestManagerTreeNode treeNode,
          RequestTracker requestTracker,//请求操作类,请求的取消,发起,重试,完成,失败
          ConnectivityMonitorFactory factory,
          Context context) {

        this.glide = glide;
        this.lifecycle = lifecycle;
        this.treeNode = treeNode;
        this.requestTracker = requestTracker;
        this.context = context;
        //监控网络连接状态的一个接口
        connectivityMonitor =factory.build(context.getApplicationContext(),new RequestManagerConnectivityListener(requestTracker));
        //观察Activity或者Fragment的生命周期
        if (Util.isOnBackgroundThread()) {
          //如果是子线程,则添加监听,post一个Runnable到主线程
          mainHandler.post(addSelfToLifecycle);
        } else {
          //如果是主线程直接添加监听
          lifecycle.addListener(this);
        }
        //添加当前网络变化的监听
        lifecycle.addListener(connectivityMonitor);
        //设置请求参数配置信息:RequestOptions用于设置Glide的各种参数,例如缓存,圆角,动画,占位图等
        setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());
        //在glide中进行注册,把RequestManager添加进List
        glide.registerRequestManager(this);
      }
    这样通过lifecycle.addListener就绑定了Activity或者Fragment的生命周期,信息被保存在ActivityFragmentLifecycle的Set中,Activity onStart,则Listener.onStart();Activity销毁,则Set销毁。

    with总结:

    with方法的作用主要是校验传入的参数,判断是当前的参数是Activity、Fragment还是Application,从而创建对应的RequestManager,在RequestManager中创建一个虚拟的Fragment,绑定当前Activity、Fragment或者Application生命周期,使Glide和当前页面生命周期保持一致。

二、load方法

    load方法提供了多种重载方式支持file,URL,drawable,bitmap等等。默认都是asDrawable形式,除此之外还额外手动设置asGif,asBitmap。

     public RequestBuilder load(@Nullable Bitmap bitmap) {
        return asDrawable().load(bitmap);
      }

      @Override
      public RequestBuilder load(@Nullable Drawable drawable) {
        return asDrawable().load(drawable);
      }

      @Override
      public RequestBuilder load(@Nullable String string) {
        return asDrawable().load(string);
      }

      @Override
      public RequestBuilder load(@Nullable Uri uri) {
        return asDrawable().load(uri);
      }

      @Override
      public RequestBuilder load(@Nullable File file) {
        return asDrawable().load(file);
      }

      @Override
      public RequestBuilder load(@Nullable Integer resourceId) {
        return asDrawable().load(resourceId);
      }

      @Override
      public RequestBuilder load(@Nullable URL url) {
        return asDrawable().load(url);
      }

      @Override
      public RequestBuilder load(@Nullable byte[] model) {
        return asDrawable().load(model);
      }

      @Override
      public RequestBuilder load(@Nullable Object model) {
        return asDrawable().load(model);
      }

     现在以Glide加载URL为例进行分析:

      @Override
      public RequestBuilder load(@Nullable String string) {
        return asDrawable().load(string);
      }

    1、asDrawable

    可以看到有一个asDrawable,除了asDrawable之外Glide支持设置asBitmap、asGif。Glide默认设置为asDrawable,我们来看一下asDrawable方法。

    public RequestBuilder asDrawable() {
        return as(Drawable.class);
    }

    public  RequestBuilder as(@NonNull Class resourceClass) {
      return new RequestBuilder<>(glide, this, resourceClass, context);
    }

    到这一步直接返回了RequestBuilder实例,RequestBuilder是一个图片加载和设置图片参数的一个核心类,几乎绝大部分的图片参数都在这里设置,看下面。

    2、load

    load方法同样存在于RequestBuilder,他有调用loadGeneric方法,初始化一些参数,同样返回RequestBuilder,我们来看这个方法。

    public RequestBuilder load(@Nullable String string) {
        return loadGeneric(string);
    }
    private RequestBuilder loadGeneric(@Nullable Object model) {
        //初始化url
        this.model = model;
        //isModelSet表示model已经被初始化值了
        isModelSet = true;
        return this;
    }
    load总结:

    load方法比较简单,根据传入的参数,创建RequestBuilder对象,初始化一些参数。

三、Glide相关类

    1、Glide

    Glide实现了ComponentCallbacks2接口,用于设置七种内存模式和值,这些值和图片占用内存的大小和回收标准有关。主要包括以下:

    (1)设置和获取图片缓存路径,如果不进行设置,默认缓存在CacheDir的"image_manager_disk_cache"文件夹下面。

    (2)获取glide对象。这个glide是通过initializeGlide方法返回如上分析。

    (3)  Glide的构造方法,构造方法的参数比较多,一共11个例如:Engine,MemoryCache,BitmapPool,requestManagerRetriever,RequestOptions等等,并且在GlideBuilder创建glide对象。

    (4)with的重载方法,见上面分析。

    (5)内存模式和大小、本地缓存相关设置等。

    (6)RequestManager的注册与解绑。

    2、GlideBuilder

        GlideBuilder是管理Glide,为其初始化和设置默认参数的一个类。和Glide功能类似提供了设置类存大小、磁盘缓存大小、资源池设置等方法,并且提供了一些默认设置,再通过Glide的构造方法,传递到Glide。

      public Glide build(@NonNull Context context) {
      ……………………………………………………省略一些默认对象创建作为参数的代码…………………………………………………
        return new Glide(
            context,
            engine,
            memoryCache,
            bitmapPool,
            arrayPool,
            requestManagerRetriever,
            connectivityMonitorFactory,
            logLevel,
            defaultRequestOptions.lock(),
            defaultTransitionOptions);
      }

    3、GlideContext

    GlideContext的继承关系GlideContext ——> ContextWrapper ——> Context,可以看出GlideContext最终继承自Context,ContextWrapper主要是对Context的一些方法进行了包装例如MainLooper,Theme,PackageName,CacheDir等等,GlideContext主要是获取一些相关设置和以下主要的两个方法:

  //获取设置的动画
  public  TransitionOptions getDefaultTransitionOptions(@NonNull Class transcodeClass) {
    TransitionOptions result = defaultTransitionOptions.get(transcodeClass);
    if (result == null) {
      for (Entry, TransitionOptions> value : defaultTransitionOptions.entrySet()) {
        if (value.getKey().isAssignableFrom(transcodeClass)) {
          result = value.getValue();
        }
      }
    }
    //如果没有设置任何动画,走默认
    if (result == null) {
      result = DEFAULT_TRANSITION_OPTIONS;
    }
    return (TransitionOptions) result;
  }

  //load方法内部参数的ViewTarget,详情见上面分析
  @NonNull
  public  ViewTarget buildImageViewTarget(
      @NonNull ImageView imageView, @NonNull Class transcodeClass) {
    return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
  }

    以上就是Glide.with(this).load(url)的流程分析,现在汇总为一个图,如下:

Glide加载流程分析(上)_第1张图片

    以上就是Glide的with、load方法加载的整体过程,下一篇文章将对into方法进行分析点击打开链接,这篇文章就到此结束!


你可能感兴趣的:(android,Glide,源码,流程,分析)