Glide的源码解析(一)(附方法调用图)

前言

上一篇博客讲了Glide的基本使用,知其然,也要知其所以然,这篇博客一起来学习Glide的源码。如果不知道Glide的基本使用,可以看上一篇博客:http://blog.csdn.net/luofen521/article/details/71210005

该博客也是基于郭霖大侠的Glide源码分析总结而得,算是自己做的笔记,郭大侠的博客传送门:http://blog.csdn.net/guolin_blog/article/details/53939176

问题

在没阅读Glide源码之前,我们带着下面几个问题去阅读源码,希望在阅读源码的过程中可以解决:

  1. Glide图片是用什么来下载的?HttpClient还是HttpURLConnection?亦或OKHttp?
  2. Glide图片是通过怎么解码的?是我们通常使用的BitmapFactory.decodeXXX方法么?
  3. Glide下载好图片以后,是怎么加载到ImageView上的?
  4. Glide怎么实现缓存的?是LruCache和DiskLruCache么?
  5. Glide的线程是怎么管理的?几个核心线程?几个最大线程?有最大任务数的限制么?
  6. Glide是怎么支持Gif图的?是通过Movie对象么?

源码版本

不同版本的Glide源码有些出入,该博客基于Glide3.7.0版本,来分析Glide如何在主线程中加载一张网络图片的,由于篇幅问题,该博客不考虑线程、缓存等流程。

源码解析

如何阅读源码:抽丝剥茧、点到即止。
Glide的流程过于复杂,其中的接口很多,为了方便阅读,强烈推荐下载方法调用流程图来对照着源码看,Pdf高清无码链接:http://download.csdn.net/detail/luofen521/9834616
这里写图片描述

从上一篇博客可知,Glide加载图片的流程就是先with,再load,最后into

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

那我们顺着这条主线往下走

1. Glide.with()

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

public static RequestManager with(Activity activity) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(activity);
}

public static RequestManager with(FragmentActivity activity) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(activity);
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static RequestManager with(android.app.Fragment fragment) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(fragment);
}

public static RequestManager with(Fragment fragment) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(fragment);
}

该方法首先调用了 RequestManagerRetriever的get无参方法,并返回一个 RequestManagerRetriever实例,该实例是单例的,代码如下:

private static final RequestManagerRetriever INSTANCE = new RequestManagerRetriever();

public static RequestManagerRetriever get() {
    return INSTANCE;
}

然后调用其get的有参对象,得到RequestManager对象,并返回。下面看看RequestManagerRetriever的get方法:

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);
}

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

public RequestManager get(FragmentActivity activity) {
    if (Util.isOnBackgroundThread()) {
        return get(activity.getApplicationContext());
    } else {
        assertNotDestroyed(activity);
        FragmentManager fm = activity.getSupportFragmentManager();
        return supportFragmentGet(activity, fm);
    }
}

public RequestManager get(Fragment fragment) {
    if (fragment.getActivity() == null) {
        throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
    }
    if (Util.isOnBackgroundThread()) {
        return get(fragment.getActivity().getApplicationContext());
    } else {
        FragmentManager fm = fragment.getChildFragmentManager();
        return supportFragmentGet(fragment.getActivity(), fm);
    }
}

@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);
    }
}

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public RequestManager get(android.app.Fragment fragment) {
    if (fragment.getActivity() == null) {
        throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached");
    }
    if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
        return get(fragment.getActivity().getApplicationContext());
    } else {
        android.app.FragmentManager fm = fragment.getChildFragmentManager();
        return fragmentGet(fragment.getActivity(), fm);
    }
}

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) {
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
        current = pendingRequestManagerFragments.get(fm);
        if (current == null) {
            current = new RequestManagerFragment();
            pendingRequestManagerFragments.put(fm, current);
            fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
            handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
        }
    }
    return current;
}

@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;
}

SupportRequestManagerFragment getSupportRequestManagerFragment(final FragmentManager fm) {
    SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag(
        FRAGMENT_TAG);
    if (current == null) {
        current = pendingSupportRequestManagerFragments.get(fm);
        if (current == null) {
            current = new SupportRequestManagerFragment();
            pendingSupportRequestManagerFragments.put(fm, current);
            fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
            handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
        }
    }
    return current;
}

RequestManager supportFragmentGet(Context context, FragmentManager fm) {
    SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
        requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
        current.setRequestManager(requestManager);
    }
    return requestManager;
}

with方法可以分为两类,一类是参数为Application,一类是参数为非Appliction

参数为Application时,调用的是with(Context context)方法,可知,在其方法里直接调getApplicationManager(context)方法,可以看到,在getApplicationManager方法中,就是直接创建了一个RequestManager并返回,在构建RequestManager对象时,传入了ApplicationLifecycle对象,也就是说,当with方法传入的是Application时,Glide加载图片的生命周期和应用的生命周期一致,当退出应用时,图片停止加载。

参数为非Application时,调用的是with(Activity/Fragment)方法,在其方法里调用了fragmentGet/supportFragmentGet方法,而fragmentGet/supportFragmentGet方法中会先去调用getRequestManagerFragment/getSupportRequestManagerFragment方法去创建RequestManagerFragment/SupportRequestManagerFragment,并添加到Activity/Fragment上去,然后去创建一个RequestManager,在构建RequestManager时,会传入current.getLifeCycle,其实就是ActivityFragmentLifeCycle对象。也就是说,当with方法传入的是Activity或者Fragment时,会创建一个隐藏的Fragment加载到Activity/Fragment上,用于保证Glide加载图片的生命周期和Actiivty/Fragment一致,当退出Activity/Fragment时,图片停止加载。

这时候Glide.with()方法就完成了,它的主要作用是根据with的参数类型,创建一个RequestManager对象,在RequestManager的构造方法中,会调用Glide.get方法,在这个方法里会初始化线程池、缓存、Engin对象和Glide对象,等下篇讲线程池博客时再详细展开。这里要记住的就是RequestManager对象持有了不同的LifeCycle对象, 用于控制Glide加载图片的生命周期。

2.load()

由于Glide.with返回的是RequestManager,则需要到RequestManager类中查看load源码

public DrawableTypeRequest<String> load(String string) {
     return (DrawableTypeRequest<String>) fromString().load(string);
}

load方法直接调用了fromString方法,然后用返回值调用了load方法,下面看看fromString方法

public DrawableTypeRequest<String> fromString() {
    return loadGeneric(String.class);
}

而fromString方法直接调用了loadGeneric 方法并返回,下面看看loadGeneric方法

private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
    ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
    ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader =
            Glide.buildFileDescriptorModelLoader(modelClass, context);

    return optionsApplier.apply(
            new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
                    glide, requestTracker, lifecycle, optionsApplier));
}

这里调用了Glide.buildStreamModelLoader和Glide.buildFileDescriptorModelLoader去创建了两个ModelLoader,用于后续的图片加载,其中Glide.buildStreamModelLoader返回的是StreamStringLoader,至于为什么返回StreamStringLoader,可以从Glide的构造方法中找到原因。然后直接构建出了一个DrawableTypeRequest,这里用到了之前返回的StreamStringLoader,最后调用了OptionsApplier.apply方法,返回了一个DrawableTypeRequest对象。

这里需要注意的是构建出DrawableTypeRequest的步骤,其中初始化了很多后续步骤需要使用到的数据。

DrawableTypeRequest(Class<ModelType> modelClass, ModelLoader<ModelType, InputStream> streamModelLoader,
        ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader, Context context, Glide glide,
        RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier) {
    super(context, modelClass,
            buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class,
                    GlideDrawable.class, null),
            glide, requestTracker, lifecycle);
    this.streamModelLoader = streamModelLoader;
    this.fileDescriptorModelLoader = fileDescriptorModelLoader;
    this.optionsApplier = optionsApplier;
}

在DrawableTypeRequest的构造方法里,调用了buildProvider方法,并把返回值传入到了DrawableTypeRequest的父类构造方法当中。先看看buildProvider方法:

private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide,
        ModelLoader<A, InputStream> streamModelLoader,
        ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader, Class<Z> resourceClass,
        Class<R> transcodedClass,
        ResourceTranscoder<Z, R> transcoder) {
    if (streamModelLoader == null && fileDescriptorModelLoader == null) {
        return null;
    }

    if (transcoder == null) {
        transcoder = glide.buildTranscoder(resourceClass, transcodedClass);
    }
    DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class,
            resourceClass);
    ImageVideoModelLoader<A> modelLoader = new ImageVideoModelLoader<A>(streamModelLoader,
            fileDescriptorModelLoader);
    return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider);
}

这里需要注意的是glide.buildTranscoder方法,它返回了一个GifBitmapWrapperDrawableTranscoder对象,用于后续图片格式的转换;通过glide.buildDataProvider得到一个DataLoadProvider对象;通过StreamStringLoader包装出来一个ImageVideoModelLoader对象,最后创建一个FixedLoadProvider对象,并把之前创建的三个对象传入构造方法中,最后把FixedLoadProvider对象返回。

回到loadGeneric方法中可知,返回的是一个DrawableTypeRequest对象,即fromString方法返回的是DrawableTypeRequest对象,在之前RequestManager中的load方法调用formString().load(),则是调用DrawableTypeRequest中的load方法,但是发现DrawableTypeRequest中并没有load方法,原来是在其父类DrawableRequestBuilder中,下面看看DrawableRequestBuilder中的load方法。

@Override
public DrawableRequestBuilder<ModelType> load(ModelType model) {
    super.load(model);
    return this;
}

这里没有多余的逻辑,只是调用了父类中的load方法,并返回了this,最后看看其父类GenericRequestBuilder中的load方法

public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) {
    this.model = model;
    isModelSet = true;
    return this;
}

到这里,RequestManager中的load方法就结束了,可知,最后返回的是一个DrawRequestBuilder对象。

3. into()

因为RequestManager类中的load方法返回了DrawableRequestBuilder对象,则到DrawableRequestBuilder中看into方法,代码如下:

public Target<GlideDrawable> into(ImageView view) {
    return super.into(view);
}

没有什么逻辑,直接调用父类的into方法,那我们看下其父GenericRequestBuilder的into方法,代码如下:

public Target<TranscodeType> into(ImageView view) {
    Util.assertMainThread();
    if (view == null) {
        throw new IllegalArgumentException("You must pass in a non null View");
    }
    if (!isTransformationSet && view.getScaleType() != null) {
        switch (view.getScaleType()) {
            case CENTER_CROP:
                apply
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值