图片Glide

Glide 系列(三) Glide源码整体流程梳理

2018-03-22  本文已影响402人  嘎啦果安卓兽
目录.jpg

闲聊

回顾了一下历史文章,不知不觉,我们安卓兽已经坚持整整一年时间来维护我们的公众号了,陆陆续续一共发布了7个系列的文章。总觉得不管是对于团队,还是个人,这都是一件非常有意义的事儿。无所谓关注度,无所谓点赞数,无所谓打赏数,只要安卓兽的成员们能够持续成长,记录下自己的成长历程,就好了。
在新的一年,安卓兽们,继续加油~~~

前言

在前面几个不同系列的源码分析之后,今天我们终于来到图片加载框架的源代码分析。先说说为什么要选择Glide,而不选择其他,其实理由说起来很简单也很粗暴:Google推荐,没毛病!
相比较前面几个系列的源代码,Glide的源代码读起来确实还是有些麻烦的,里面涉及的类众多而繁杂,调用链条错综而冗长。如果真的想把每一行代码搞清楚,那势必会花费超长的时间。因此对于Glide的源码分享,我们的整体计划是:本篇先做一个整体的流程梳理,让大家知道Glide在图片加载过程中,到底做了哪几件大事,围绕每件大事又做了哪几件小事;然后接下来的几篇文章,会针对各个特性,进行针对性介绍。
那么现在就开始我们的介绍吧,本篇文章主要基于Glide 3.7.0版本。

主流程梳理

虽然Glide代码量比较大,但经过我们的抽丝剥茧,Glide在图片加载过程中,其实主要只做了几件大事。把这几件大事先梳理清楚,非常有助于我们对于源代码的阅读。具体可参考下图:


主流程图.jpg

三件大事:

经过这一番图文讲解,Glide的主流程是不是更清晰了些?对的,万变不离其宗,Glide也一样的,显示图片不过就是经过这么几步而已。

主流程细化

接下来,我们对于主流程进行进一步细化。
对于用户来说,想要显示一张图,只需要简单的调用下面的代码就可以了。

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

那么我就从这三个函数入手,看看Glide是如何通过这三个函数,最终跑通以上主流程的。
注意,以下依然通过图文的方式进行介绍,以方便读者理解。另外,以下时序图非常详细,几乎包含了源代码调用的每一处细节,比较难理解的对象,我也基本都写了简单的注释,方便读者追溯其由来,从而疏通整个调用流程。所以我就不贴太多源代码了,读者如果有不清楚的地方,对照一下源代码,应该就可以理解了。

with

with属于“准备数据”之“第一阶段”,我们先展示其时序图:


时序图--with().jpg

从上图我们可以看出,with的代码流程,还是比较简单,最终会返回一个RequestManager类型的对象,以供下一步调用。
另外需要说明的是:

想特别了解的同学可以看一下源码。

load

load属于“准备数据”之“第一阶段”,我们先展示其时序图: 时序图--load().jpg

从上图我们可以看出,load的代码流程,稍微复杂了一些,但是实质上还是做前期的数据准备,主要就是构造对象,封装对象。
另外需要说明的是:

register(String.class, InputStream.class, new StreamStringLoader.Factory());

into

into比较复杂,其涉及了“准备数据”,“异步处理”,“切换到主线程”这三大步的内容。因为其内容较多,一张时序图实在展示不下,我们会分解成5张时序图,来顺序进行说明。

into-1

into-1涉及了“准备数据”的“第一阶段”和“第二阶段”,我们先展示其时序图:


时序图--into()-1.jpg

从上图我们可以看出,into-1的代码流程,实质上还是做数据准备,主要就是构造对象,封装对象。需要关注的是其构造出了GenericRequest对象。
另外需要说明的是:

into-2

into-2属于“准备数据”之“第二阶段”,并最终开启了“异步调用”的大门,先展示其时序图:


时序图--into()-2.jpg

从上图我们可以看出,into-2的代码流程,实质上还是做数据准备,主要就是构造对象,封装对象。需要注意的是,这里开始使用“第一阶段”生成的GenericRequest对象,从GenericRequest对象取出各种需要的对象,传递给Engine的load函数,最终构造出了decodeJob对象。
另外需要说明的是:

register(String.class, InputStream.class, new StreamStringLoader.Factory());
register(Uri.class, InputStream.class, new StreamUriLoader.Factory());
register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());
public static class Factory implements ModelLoaderFactory<String, InputStream> {
    @Override
    public ModelLoader<String, InputStream> build(Context context, GenericLoaderFactory factories) {
        return new StreamStringLoader(factories.buildModelLoader(Uri.class, InputStream.class));
    }
}
public static class Factory implements ModelLoaderFactory<Uri, InputStream> {
    @Override
    public ModelLoader<Uri, InputStream> build(Context context, GenericLoaderFactory factories) {
        return new StreamUriLoader(context, factories.buildModelLoader(GlideUrl.class, InputStream.class));
    }
}
public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {
    @Override
    public ModelLoader<GlideUrl, InputStream> build(Context context, GenericLoaderFactory factories) {
        return new HttpUrlGlideUrlLoader(modelCache);
    }
}
public class HttpUrlGlideUrlLoader implements ModelLoader<GlideUrl, InputStream> {
    @Override
    public DataFetcher<InputStream> getResourceFetcher(GlideUrl model, int width, int height) {
        return new HttpUrlFetcher(url);
    }
}

into-3

into-3和into-4可以连在一起看。into-3属于“异步处理”之“发起网络请求,拿到数据流”和“将数据流解码成bitmap对象”,先展示其时序图:


时序图--into()-3.jpg

从上图我们可以看出,into-3的代码流程,主要完成了“发起网络请求,拿到数据流”和“将数据流解码成bitmap对象”两件小事。
另外需要说明的是:

into-4

into-4和into-3可以连在一起看。into-4属于“异步处理”之“将bitmap对象转码成Drawable对象”,先展示其时序图:


时序图--into()-4.jpg

从上图我们可以看出,into-4的代码流程,主要完成了“异步处理”中的第三件小事:“将bitmap对象转码成Drawable对象”
另外需要说明的是:

public Resource<GlideDrawable> transcode(Resource<GifBitmapWrapper> toTranscode) {
    GifBitmapWrapper gifBitmap = toTranscode.get();
    Resource<Bitmap> bitmapResource = gifBitmap.getBitmapResource();

    final Resource<? extends GlideDrawable> result;
    if (bitmapResource != null) {
        result = bitmapDrawableResourceTranscoder.transcode(bitmapResource);
    } else {
        result = gifBitmap.getGifResource();
    }
    // This is unchecked but always safe, anything that extends a Drawable can be safely cast to a Drawable.
    return (Resource<GlideDrawable>) result;
}

public Resource<Bitmap> getBitmapResource() {
    return bitmapResource;
}

public Resource<GifDrawable> getGifResource() {
    return gifResource;
}

into-5

into-5属于“切换到主线程”之“显示Drawable对象”,先展示其时序图:


时序图--into()-5.jpg

从上图我们可以看出,into-5的代码流程,主要完成了在主线程中显示Drawable对象
另外需要说明的是:

总结

经过一番图文讲解,读者是不是对于Glide源码整体流程有了大致的了解。如果想进一步了解的话,建议读者跟着时序图,走一遍源代码,应该会收获更多。
对于阅读复杂的源码,分享给大家一点经验:先从框架或者主流程入手,然后再逐个细化各个模块,最后再想想作者为什么要这么设计,我们能学习或者借鉴到什么。
好了,这一篇就到这里吧,接下来的几篇文章,会针对各个特性,进行针对性介绍,敬请期待。

上一篇 下一篇

猜你喜欢

热点阅读