返回

Glide源码分析(一)

Android

Glide源码分析(一)

前面几片文章主要介绍了下Picasso,相对来说Picasso源码看起来会比较轻松,所以如果想研究图片框架的话,建议先从Picasso下手,这样会比较容易。

今天只分析最简单的一行代码,后面会慢慢深入。

虽然只有一行代码,但是里面的整个逻辑确实非常复杂。

对,这应该也是我们使用第三方框架最头疼的问题。

我们经常会遇到一些特别牛逼的代码,让我们不知道从哪里下手。

但是我从很久以前写代码到现在,基本上都有一个方法来分析这些牛逼的代码,而这个方法说起来也很简单,那就是从入口入手。

而对于Glide这个库来说,入口在哪里呢?

我们先看下如何使用Glide加载图片。

Glide.with(this).load("http://....").into(imageView);

其中Glide.with(this)就是入口,而Glide这个类是Glide框架的核心类,也是所有功能的入口,从入口开始分析整个框架的逻辑。

而这个类的源码看起来并没有那么复杂,如下:

public class Glide {

    private static volatile Glide glide;

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

    private static void checkAndInitializeGlide(Context context) {
        // double check for null as another thread may have run initializeGlide already
        if (glide == null) {
            initializeGlide(context);
        }
    }

    private static void initializeGlide(Context context) {
        Glide glide = new GlideBuilder(context).build();
        // ...
        glide.applyOptions();
        // ...
        glide.registerComponents();
        // ...
    }

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

这个类的逻辑很明显,就是有一个静态的方法get,用于获取Glide实例,而这个实例就是通过静态的glide字段来缓存的,当glide为null时,会通过同步锁来创建一个新的Glide实例。

然后通过GlideBuilder来构建Glide实例,并初始化Glide,最后返回RequestManager。

而RequestManager就是负责图片加载的类,也就是把我们的图片加载请求交给他来处理。

RequestManager的源码如下:

public class RequestManager {
    // ...
    private final Context context;
    private final Lifecycle lifecycle;
    private final RequestTracker requestTracker;
    private final Glide glide;
    // ...
    // ...
    public RequestManager(Context context, Lifecycle lifecycle, RequestTracker requestTracker, Glide glide) {
        this.context = context;
        this.lifecycle = lifecycle;
        this.requestTracker = requestTracker;
        this.glide = glide;
        //...
    }
    // ...
    public <R> Target<R> into(ImageView view) {
        GlideContext glideContext = glide.getGlideContext();
        if (view == null) {
            throw new IllegalArgumentException("You must pass in a non null view");
        }
        if (!isContextValid(view.getContext())) {
            throw new IllegalArgumentException("You cannot start a load for a view in a Context that is not the current "
                    + "context");
        }

        if (view.getParent() null) {
            throw new IllegalArgumentException("You cannot start a load for a view that has not been attached to "
                    + "a window");
        }
        Target<R> target = glideContext.buildImageViewTarget(view, glideContext.getRegistry().getImageHeaderParsers());
        return into(target);
    }
    // ...
}

而加载图片的时候,最终是通过into方法来完成的,该方法接收一个Target参数,用于接收加载好的图片。

Target的源码如下:

public interface Target<R> {
    void onStart();
    void onStop();
    void onDestroy();

    void onLoadStarted(@Nullable Drawable placeholder);

    void onLoadFailed(@Nullable Drawable errorDrawable);

    void onResourceReady(R resource, @Nullable Transition<? super R> transition);

    void onLoadCleared(@Nullable Drawable placeholder);

    void getSize(SizeReadyCallback cb);

    void removeCallback(SizeReadyCallback cb);
}

Target主要用于接收加载好的图片,并把图片显示到UI上。

而into方法内部主要做了以下几件事:

  1. 检查view是否为null,如果不为null,则抛出异常。
  2. 检查view的父控件是否为null,如果不为null,则抛出异常。
  3. 检查view是否已经被添加到窗口中,如果没有,则抛出异常。
  4. 创建一个Target对象,用于接收加载好的图片。
  5. 调用into方法,把Target对象传进去。

而into方法内部主要做了以下几件事:

  1. 创建一个GlideContext对象,用于管理图片加载的上下文。
  2. 检查view的上下文是否有效,如果不有效,则抛出异常。
  3. 创建一个Target对象,用于接收加载好的图片。
  4. 调用onStart方法,通知Target对象加载已经开始。
  5. 调用into方法,把Target对象传进去。