Android开发经验谈Android开发

〔两行哥〕提纲挈领,带你梳理Glide主要源码逻辑(一)

2018-04-23  本文已影响124人  两行哥

Glide的简介就不多说了,只要记住这是Google推荐AndroidDev使用的图片开源框架就好了。直接进入正题,看看Glide的设计到底有何精妙之处,为何获得了Google的青睐?

一个最简单的Glide图片加载逻辑举例:

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

我们的分析会以Glide3.8.0版本为例,基于此行代码展开,分别分析with()、load()、into()三个方法内部的逻辑。

一、基础概念

Glide中涉及几个概念,为便于理解,先粗略解释:

1.Model

指的是对图片源的封装。在AndroidDev中,比较常见的就是网络图片地址、本地文件或资源ID。比如,String url = "https://www.baidu.com/img/bd_logo1.png",这里的url经过Glide内部的封装后,就可以理解为一个Model。

2.Data

指的是对Model处理后的数据源的封装,通常是InputStream。而在Glide中,将Model处理为Data的类便是ModelLoader。比如,通过上文的"https://www.baidu.com/img/bd_logo1.png"而取得的图片输入流,就可以理解为Data。

3.Resource

拿到图片的输入流可以直接展示在UI上吗?显然不可以。在第2点中我们提及了Data,即输入流,如果要将其展示就需要对Data进行解码,解码后的数据就是Resource。比如,上文的图片输入流经过解码后成为一个Bitmap对象或Drawable对象,这个对象就可以理解为Resource。而担任解码任务的角色,被成为ResourceDecoder(资源解码器)。

4.TransformedResource&TranscodedResource

有时候我们获取到的Resource并不适合展示,而是需要经过处理才能展示,比如需要裁剪变换等(如调用centerCrop()、fitCenter()),那么经过如此变换后的Rescourse称为TransformedResource。
我们知道Glide是可以展示静态图,也可以展示动态图(动态Gif),而解码后的静态图片和动态图片(例如drawable和gif-drawable)类型是不同的, 为了统一处理逻辑,Glide内部将这两种类型的对象再次封装为统一的GlideBitmapDrawable,这里的GlideBitmapDrawable就可以理解为TranscodedResource。

5.Target

这个比较容易理解,即需要在哪个目标上进行展示,比如ImageView。而Glide内部将ImageView再次进行了封装,封装后对象就可以理解为Target。

综上所述,一个完整的图片处理及展示流程如下:


图1 Glide流程图

二、基本用法

直接看代码和注释:

Glide.with(context)
        .load(url)
        .placeholder(R.mipmap.ic_launcher)//图片加载前的占位图
        .error(R.mipmap.ic_launcher)//图片加载错误的占位图
        .fitCenter()
        .centerCrop()
        .override(500, 500)//调整图片大小
        .skipMemoryCache(true)//跳过内存缓存
        .crossFade(1000)//渐变显示时间
        .diskCacheStrategy(DiskCacheStrategy.RESULT)//缓存处理后的图像(如尺寸调整、裁剪后的图像)
        .diskCacheStrategy(DiskCacheStrategy.SOURCE)//缓存原尺寸的图像
        .diskCacheStrategy(DiskCacheStrategy.ALL)//缓存所有图像
        .diskCacheStrategy(DiskCacheStrategy.NONE)//跳过磁盘缓存
        .priority(Priority.HIGH)//指定优先级
        .into(imageView);

三、with()源码逻辑

跟进Glide类中寻找with()方法,发现with()方法有多种重载,包括with(Context context)、with(Activity activity)、with(Fragment fragment)等等。Glide之所以设计如此之多的with()方法重载,其目的在于将图片的加载与传入的Context组件或Fragment的生命周期相关联。比如,当用户关闭当前Activity,那么即使该Activity有正在进行中的图片网络请求,Glide也会随之取消该网络请求。如果传入的是ApplicationContext,那么网络请求会持续进行,直至App进程被销毁。
这里以with(Context context)为例看一下源码实现,其他重载方法逻辑基本一致:

Glide.java
    public static RequestManager with(Context  context) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(activity);
    }

RequestManager类是Glide中用来处理图片加载请求的管理类。RequestManagerRetriever类是用来创建和管理RequestManager对象的,其get()方法获取了RequestManagerRetriever实例。继续追踪源码,查看RequestManagerRetriever类中get()方法的逻辑。

RequestManagerRetriever.java
    public RequestManager get(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) {
                return get(((ContextWrapper) context).getBaseContext());
            }
        }

        return getApplicationManager(context);
    }

在get()方法中,对Context的类型进行了区分,有多种重载。我们主要分析一下Application和Activity类型的方法参数,其他类型的参数读者可以自行追踪源码。

RequestManagerRetriever.java
    private RequestManager getApplicationManager(Context context) {
        if (applicationManager == null) {
            synchronized (this) {
                if (applicationManager == null) {
                    applicationManager = new RequestManager(context.getApplicationContext(),
                            new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
                }
            }
        }
        return applicationManager;
    }

上述get(Application context)的方法中采取了双重锁单例模式获取了一个RequestManager对象。可以发现,Glide在RequestManager的构造方法中传入了ApplicationLifecycle的实例,其作用是将RequestManager与Application生命周期绑定。

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public RequestManager get(Activity activity) {
        if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
            return get(activity.getApplicationContext());
        } else {
            assertNotDestroyed(activity);
            android.app.FragmentManager fm = activity.getFragmentManager();
            return fragmentGet(activity, fm);
        }
    }

上述get(Activity context)的方法中,首先进行了线程判断,如果在非主线程的情况下,返回了get(Application context)类型的RequestManager,而在主线程的情况下,通过该Activity context获取到了相关联的FragmentManager。这是Glide设计精妙之处之一,为什么要获取FragmentManger呢?继续追踪源码到fragmentGet(activity,fm)中。

RequestManagerRetriever.java
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
        RequestManagerFragment current = getRequestManagerFragment(fm);
        RequestManager requestManager = current.getRequestManager();
        if (requestManager == null) {
            requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
            current.setRequestManager(requestManager);
        }
        return requestManager;
    }

分析一下fragmentGet()的逻辑。首先,方法第一行getRequestManagerFragment()返回了RequestManagerFragment的实例current。RequestManagerFragment是啥?其实这是Glide封装的Fragment,这里当作Fragment来理解。先来截取部分RequestManagerFragment类的代码:

RequestManagerFragment.java
public class RequestManagerFragment extends Fragment {

    ......
    private final ActivityFragmentLifecycle lifecycle;
    private RequestManager requestManager;

    public RequestManagerFragment() {
        this(new ActivityFragmentLifecycle());
    }

    /**
     * Sets the current {@link com.bumptech.glide.RequestManager}.
     *
     * @param requestManager The request manager to use.
     */
    public void setRequestManager(RequestManager requestManager) {
        this.requestManager = requestManager;
    }

    ActivityFragmentLifecycle getLifecycle() {
        return lifecycle;
    }

    /**
     * Returns the current {@link com.bumptech.glide.RequestManager} or null if none exists.
     */
    public RequestManager getRequestManager() {
        return requestManager;
    }

    @Override
    public void onStart() {
        super.onStart();
        lifecycle.onStart();
    }

    @Override
    public void onStop() {
        super.onStop();
        lifecycle.onStop();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        lifecycle.onDestroy();
    }

}

对RequestManagerFragment划重点:
1.含有一个RequestManager类型的成员变量requestManager,通过getRequestManager()返回,通过setRequestManager()赋值。

即每个RequestManagerFragment对象都与一个RequestManager对象绑定。

2.含有一个ActivityFragmentLifecycle类型的成员变量lifecycle。通过对lifecycle实现的LifecycleListener接口回调来监听其生命周期,可以发现在RequestManagerFragment类的onStart()、onStop()、onDestroy()方法中对其进行了调用。

即lifecycle对象实现了对RequestManagerFragment实例的生命周期监听。

回到fragmentGet()方法中,调用RequestManagerFragment中的getRequestManager()方法返回与其绑定的RequestManager对象(成员变量),如果为null(没有与其绑定的RequestManager对象),则创建一个RequestManager对象,并调用setRequestManager()将其与RequestManagerFragment绑定。至此实现了RequestManagerFragment对象与RequestManager对象的一一绑定。
现在思考一个问题,Glide如何监听目标Activity或Fragment的生命周期?上文已经说明,根据传入Glide的Context不同,Glide会监听其生命周期,根据生命周期管理图片的网络请求。
Glide直接监听Activity并不方便。那么在这里,Glide采用了另外的方法:
1.在Activity或Fragment的上层添再加一个Fragment,也就是上文一直在分析的RequestManagerFragment。这个Fragment并没有覆写createFragmentView(),即这是一个无UI的Fragment,当添加了该Fragment,用户是无法感知到的。
2.我们知道依附于Activity的Fragment有与被依附的Activity相关联的生命周期,监听Fragment的生命周期也就是获取到了被依附的Activity的生命周期。上文已经划过重点:RequestManagerFragment通过接口回调的方式,在onStart()、onStop()、onDestroy()中调用了ActivityFragmentLifecycle的相应生命周期方法,实现了对其生命周期的监听。
3.如果传入Glide.with()参数为Fragment,那么处理逻辑同上。大家应该也在Fragment中添加过Fragment吧?Glide同样监听了RequestManagerFragment的生命周期。
4.每个RequestManagerFragment对象又与RequestManager对象一一绑定。至此,所有疑问解开:

Glide的每个RequestManager想要监听目标Activity或Fragment生命周期用于执行相关操作:
---> 每个RequestManager关联着唯一的RequestManagerFragment
---> 该RequestManagerFragment是无UI的,被添加在目标Activity或Fragment上, 而RequestManagerFragment的生命周期又与目标Activity或Fragment相关联
---> RequestManagerFragment通过接口回调的方式,在onStart()、onStop()、onDestroy()中调用了ActivityFragmentLifecycle的相应生命周期方法,实现了生命周期的监听
综上,RequestManager通过监听RequestManagerFragment这个不可见的Fragment的生命周期,间接监听了目标Activity或Fragment。

这次的Glide源码分析就到这里,主要分析了Glide内部的处理流程以及with()方法中所做的操作,建议自行参阅相关源码的同时阅读本文。下一篇我们将继续分析Glide的load()方法,再会。

上一篇下一篇

猜你喜欢

热点阅读