Glide 源码分析

Posted 安卓开发-顺

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Glide 源码分析相关的知识,希望对你有一定的参考价值。

前言:

Glide 作为android 图片加载领域最火的一款框架,其背后的源码设计同样精彩,今天就来一探究竟(基于Glide4.11.0版本)。

由于Glide框架的源码非常庞大,我们不会把所有细节分析一遍,本文只分析其核心源码,重点分析其对生命周期的监听和缓存的处理。

目录

一、with

二、load

三、into


我们的分析思路就从最简单的

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

开始,来看看其背后的源码到底是怎么样的。

一、with

Glide有6个with的重载方法,返回值都是RequestManager

这6个方法其实可以分为两类:

  • 在主线程调用并且传入 Activity、Fragment或者View类型的Context(这种情况Glide会默认创建一个空的Fragment来感应当前Activity的生命周期)
  • 在子线程调用或者传入的Context是ApplicationContext(只要在子线程调用,无论传入什么都会装换为ApplicationContext)

下面我们通过看源码来验证:

我们看with(Activity)的情况

    @NonNull
    public static RequestManager with(@NonNull Activity activity) 
        return getRetriever(activity).get(activity);
    

其中 getRetriever返回了一个 RequestManagerRetriever 对象

    @NonNull
    private static RequestManagerRetriever getRetriever(@Nullable 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).");
        return get(context).getRequestManagerRetriever();
    

我们来看其get方法:

 看,虽然传入的是Activity,但是如果不是主线程就转换为ApplicationContext来处理,这样就和with(Application)是一样的,我们先来看这条分支:

继续跟进:

    @NonNull
    private RequestManager getApplicationManager(@NonNull Context context) 
        if (this.applicationManager == null) 
            synchronized(this) 
                if (this.applicationManager == null) 
                    Glide glide = Glide.get(context.getApplicationContext());
                    this.applicationManager = this.factory.build(glide, 
                           new ApplicationLifecycle(),
                           new EmptyRequestManagerTreeNode(), 
                           context.getApplicationContext());
                
            
        

        return this.applicationManager;
    

 比较直接,通过工厂模式创建一个 RequestManager 对象返回就结束了。

然后我们重点来看第二条分支的情况(主线程+Activity、Fragment、或者View)

跟进到fragmentGet,通过方法名可以看出,这里面会构造一个Fragment

    /** @deprecated */
    @Deprecated
    @NonNull
    private RequestManager fragmentGet(@NonNull Context context, @NonNull FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) 
        //重点代码,这里会创建出RequestManagerFragment
        RequestManagerFragment current = this.getRequestManagerFragment(fm, parentHint, isParentVisible);
        RequestManager requestManager = current.getRequestManager();
        if (requestManager == null) 
            Glide glide = Glide.get(context);
            requestManager = this.factory.build(glide, current.getGlideLifecycle(), 
                             current.getRequestManagerTreeNode(), context);
            current.setRequestManager(requestManager);
        

        return requestManager;
    

 继续跟进fragmentGet方法的第一行代码:

this.getRequestManagerFragment(fm, parentHint, isParentVisible);

package com.bumptech.glide.manager;
public class RequestManagerRetriever implements Callback 
...
    @NonNull
    private RequestManagerFragment getRequestManagerFragment(@NonNull FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) 
        //第一步 先通过Tag找下当前是否已经有构造好的Fragment
        RequestManagerFragment current = (RequestManagerFragment)fm.findFragmentByTag("com.bumptech.glide.manager");
        if (current == null) 
            //第二步 如果第一步找不到 在从缓存里找下
            current = (RequestManagerFragment)this.pendingRequestManagerFragments.get(fm);
            if (current == null) 
                //第三步 缓存里也没有 就创建一个
                current = new RequestManagerFragment();
                current.setParentFragmentHint(parentHint);
                if (isParentVisible) 
                    current.getGlideLifecycle().onStart();
                

                //放入缓存 避免重复创建,此时再调用此方法就能从缓存直接拿到了
                this.pendingRequestManagerFragments.put(fm, current);
                fm.beginTransaction().add(current, "com.bumptech.glide.manager").commitAllowingStateLoss();
                
                //发handler去移除缓存里的fragment,当此handler消息被执行时,通过
                //fm.findFragmentByTag已经可以获取到当前fragment了
                //注意,这里必须是发handler 不能直接从缓存移除
                //因为fragment的加载也是通过handler消息来驱动的,这里牵扯到handler消息机制的原理,简单理解就是handler消息是排队被处理的,下面发的handler消息排在处理fragment消息的后面
                this.handler.obtainMessage(1, fm).sendToTarget();
            
        

        return current;
    

注释里写的比较清楚了,先通过fm.findFragmentByTag来获取,没有就从缓存取,在没有就创建出RequestManagerFragment。

这里面有个细节就是作者设计了一个缓存pendingRequestManagerFragments(就是一个Map)来防止fragment重复创建,其中从缓存中移除fragment的时机涉及到了fragment的加载原理(handler驱动),和handler机制的原理,如果对二者不熟悉,可能不太容易理解。

注释里面我也给出了详细的解释,如还不能理解请先看下Fragment、Handler相关源码。

现在Fragment有了,那是如何做到感应当前Activity生命周期的呢?

我们来看下RequestManagerFragment的源码:

二、load

三、into

以上是关于Glide 源码分析的主要内容,如果未能解决你的问题,请参考以下文章

Glide 源码分析(4.13.2)

Glide 4.12图片框架之多级缓存源码设计分析

Glide 4.12图片框架之多级缓存源码设计分析

Glide 4.12图片框架之多级缓存源码设计分析

Glide 4.12图片框架之多级缓存源码设计分析

Glide 4.12图片框架之多级缓存源码设计分析