Glide 简单流程


Glide 支持类型 model

index type example
1 Bitmap
2 Drawable
3 String
4 Uri
5 File
6 URL
7 Integer
8 byte[]
9 Object

在 Activity 中,一行代码可实现图片加载。

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

三个方法,参数,context,url 和 view。

GlideRequest 类关系图

GlideApp 、GlideRequests,GlideRequest 类,编译自动生成。

with() 方法,生成 GlideRequests。
load() 方法,生成 GlideRequest。

一、with() 方法

1,with() 方法支持多个参数类型。
返回 GlideRequests 对象,父类 RequestManager。

GlideApp with() 重载方法
//GlideApp的with()方法。
public static GlideRequests with(@NonNull View arg0) {
    return (GlideRequests) Glide.with(arg0);
}

//这些方法都会调用Glide的with()方法,参数也支持。
//Glide的with方法。
public static RequestManager with(@NonNull View view) {
    return getRetriever(view.getContext()).get(view);
}

2,生成 RequestManager
Glide 类内部 RequestManagerRetriever,维护 context 和 RequestManager 的关系,负责生成 GlideRequests ( RequestManager ),同时发起多个请求使用同一个 GlideRequests,和同一个上下文 Activity / Fragment 相关的请求。

#RequestManagerRetriever类get()方法。
public RequestManager get(@NonNull View view) {
    //非主线程
    if (Util.isOnBackgroundThread()) {
        return get(view.getContext().getApplicationContext());
    }
    Activity activity = findActivity(view.getContext());
    if (activity == null) {
        return get(view.getContext().getApplicationContext());
    }
    if (activity instanceof FragmentActivity) {
        Fragment fragment = findSupportFragment(view, (FragmentActivity) activity);
        return fragment != null ? get(fragment) : get(activity);
    }
    android.app.Fragment fragment = findFragment(view, activity);
    if (fragment == null) {
        return get(activity);
    }
    return get(fragment);
}

get() 方法,支持多个参数。
参数 View 类型时,非主线程或 View 上下文 Activity 是空,由全局 ApplicationContext 加载,其他情况,解析 View 对应 Fragment 或 Activity 加载。
参数 Context 时,判断具体类型 Fragment、Activity、FragmentActivity。
最终,有三个地方通过工厂模式创建 RequestManager。全局 Context,获取它内部的 RequestManager 对象。

fragmentGet() 方法,支持普通 Fragment 和 Activity
supportFragmentGet() 方法,支持 (support-v4) FragmentActivity 和 (support-v4) Fragment。
子类 RequestManagerFragment 和 SupportRequestManagerFragment。
将当前 Activity 新增一个 Fragment,将 RequestManager 绑定内部。

fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();

复用 Fragment 绑定的 RequestManager。

 fm.findFragmentByTag(FRAGMENT_TAG)

当参数Context上下文和Activity组件无关时,统一使用全局RequestManager,即applicationManager。

@NonNull
private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm,
                                          @Nullable Fragment parentHint) {
     //parentHint是加载图片的那个Fragment。
    SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
        Glide glide = Glide.get(context);
        requestManager =
                factory.build(
                        glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
        current.setRequestManager(requestManager);
    }
    return requestManager;
}

创建的 RequestManager 对象保存 SupportRequestManagerFragment,空时才会创建。
RequestManagerFactory 工厂创建 RequestManager,在 GlideBuilder 类中,最后在 build() 方法时,保存在 RequestManagerRetriever 内部。
GeneratedRequestManagerFactory 工厂类是自动生成的 Java 类,实现了抽象工厂接口 RequestManagerFactory。

@Override
GeneratedRequestManagerFactory getRequestManagerFactory() {
    return new GeneratedRequestManagerFactory();
}

final class GeneratedRequestManagerFactory implements RequestManagerRetriever.RequestManagerFactory {
  @Override
  public RequestManager build(Glide glide, Lifecycle lifecycle, RequestManagerTreeNode treeNode,
      Context context) {
    return new GlideRequests(glide, lifecycle, treeNode, context);
  }
}

该工厂创建一个 GlideRequests 对象,继承 RequestManager。在 GlideApp 的 with() 方法,将它转换成 GlideRequests 对象。

综上,with() 方法,根据当前请求的组件或视图上下文,返回一个请求实体管理者 GlideRequests。

二、load() 方法

load() 方法流程

GlideRequests 管理对象对 load() 方法,生成 GlideRequest,支持多种类型数据源入参。
通过 url ( String 类型) 参数进行解析 GlideRequests 的 load() 方法。

//GlideRequests方法
public GlideRequest<Drawable> load(@Nullable String arg0) {
    return (GlideRequest<Drawable>) super.load(arg0);
}

父类 RequestManager 的 load() 方法。

//RequestManager方法
public RequestBuilder<Drawable> load(@Nullable String string) {
    return asDrawable().load(string);
}

asDrawable() 方法,负责创建 RequestBuilder 对象,代表一个具体请求,支持不同类型,如 asBitmap(),asFile()。as() 方法,参数不同。

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

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

GlideRequests 类重写了 as() 方法。
因此,GlideRequests 的 load() 方法,创建的是 RequestBuilder 子类,即GlideRequest 对象,强制类型转换。

asDrawable() 方法,资源类型 <ResourceType> 是 Drawable 类,请求实体内部最终需要转换的资源类型,即 transcodeClass。

load() 方法。

public RequestBuilder<TranscodeType> load(@Nullable String string) {
    return loadGeneric(string);
}

String 类型的 url,调用通用 loadGeneric() 方法。

@NonNull
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model){
    this.model = model;
    isModelSet = true;
    return this;
}

保存加载资源 model,该示例保存 String 类型 url。

load() 方法,根据请求资源类型,由 GlideRequests 管理者创建一个具体的GlideRequest 请求实体。

三、into() 方法

GlideRequest<Drawable> 的 into() 方法,父类 RequestBuilder 的 into() 方法,参数 ImageView 对象。

public ViewTarget<ImageView, TranscodeType> into(ImageView view) {
    RequestOptions requestOptions = this.requestOptions;
    if (!requestOptions.isTransformationSet()
            && requestOptions.isTransformationAllowed()
            && view.getScaleType() != null) {
        switch (view.getScaleType()) {
            case CENTER_CROP:
                requestOptions = requestOptions.clone().optionalCenterCrop();
                break;
            case CENTER_INSIDE:
                requestOptions = requestOptions.clone().optionalCenterInside();
                break;
             ...//ScaleType类型判断,其他类型相关代码省略。
        }
    }
    return into(
            glideContext.buildImageViewTarget(view, transcodeClass),
            /*targetListener=*/ null,
            requestOptions);
}

根据 ImageView 的 ScaleType 类型,设置 RequestOptions 配置项。
ImageView 和 Class<TranscodeType> 即 as() 的入参。
GlideContext 的 buildImageViewTarget() 方法,创建 ViewTarget<ImageView, X>。

GlideContext 内部 ImageViewTargetFactory工厂类。
根据 Class<TranscodeType> transcodeClasss,创建 ViewTarget 有两种类型。
transcodeClasss 类型,即 as() 方法的入参,RequestBuilder 对象构造方法参数。

创建 ViewTarget 后,调用另一个 into() 方法。

private <Y extends Target<TranscodeType>> Y into(
        @NonNull Y target,
        @Nullable RequestListener<TranscodeType> targetListener,
        @NonNull RequestOptions options) {
    //在into之前,调用load方法设置model,并设置isModelSet为true。
    if (!isModelSet) {
        throw new IllegalArgumentException("You must call #load() before calling #into()");
    }
    options = options.autoClone();
    Request request = buildRequest(target, targetListener, options);
    ...
    requestManager.clear(target);
    target.setRequest(request);
    requestManager.track(target, request);
    return target;
}

buildRequest() 方法,创建一个 Request 请求,Request 是一个接口,表示目标 Target 加载资源的请求,绑定 ViewTarget 内部。
RequestManager 请求管理器,清理。

Target 绑定 Request,调用请求管理器的 track 方法,每个请求实体都引用 RequestManager,RequestBuilder 构造方法传入。

void track(Target<?> target, Request request) {
    targetTracker.track(target);
    requestTracker.runRequest(request);
}

TargetTracker 类维护一个 Target 集合,调用 RequestTracker 的 runRequest() 方法,监听 Glide Fragment 生命周期 LifecycleListener。

public void runRequest(Request request) {
    requests.add(request);
    if (!isPaused) {
      request.begin();
    } else {
      pendingRequests.add(request);
    }
}

RequestTracker 追踪器,管理请求集合,请求加入内部 Set 集合,根据暂停状态,调用 SingleRequest 的 begin() 方法,开始,或 pendingRequests 加入等待列表。

开始请求数据,Request 的 begin() 方法。

public void begin() {
    startTime = LogTime.getLogTime();
    if (model == null) {
        ...
        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)) {
        onSizeReady(overrideWidth, overrideHeight);
    } else {
        target.getSize(this);
    }
    if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
            && canNotifyStatusChanged()) {
        target.onLoadStarted(getPlaceholderDrawable());
    }
}

创建 RequestBuilder<Drawable> 时,将加载资源 (网络是 url )保存在内部 model 对象,obtain() 方法 创建 SingleRequest,初始化 包括 model 参数。
状态 WAITING_FOR_SIZE , 判断 size 是否准备好,Target 的 getSize() 方法,准备宽高。
SizeReadyCallback 接口 , onSizeReady() 方法中进行 load 加载。

public void onSizeReady(int width, int height) {
    stateVerifier.throwIfRecycled();
    //状态必须是WAITING_FOR_SIZE。
    if (status != Status.WAITING_FOR_SIZE) {
        return;
    }
    status = Status.RUNNING;//状态更新RUNNING
    float sizeMultiplier = requestOptions.getSizeMultiplier();
    this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
    this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
    loadStatus = engine.load(
            glideContext,
            model,
            requestOptions.getSignature(),
            this.width,
            this.height,...);//load参数较多
    if (status != Status.RUNNING) {
        loadStatus = null;
    }
}

改变 RUNNING 状态。

通过 SingleRequest 内部加载引擎 Engine,load() 方法加载,返回一个状态 LoadStatus,参数多是请求配置参数。

每次图片加载请求,创建一个 SingleRequest,加载引擎 Engine 对象通用。


任重而道远

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,843评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,538评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,187评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,264评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,289评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,231评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,116评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,945评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,367评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,581评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,754评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,458评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,068评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,692评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,842评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,797评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,654评论 2 354