从源码分析Android的Glide库的图片加载流程及特点

0.基础知识
Glide中有一部分单词,我不知道用什么中文可以确切的表达出含义,用英文单词可能在行文中更加合适,还有一些词在Glide中有特别的含义,我理解的可能也不深入,这里先记录一下。

(1)View: 一般情况下,指Android中的View及其子类控件(包括自定义的),尤其指ImageView。这些控件可在上面绘制Drawable
(2)Target: Glide中重要的概念,目标。它即可以指封装了一个View的Target(ViewTarget),也可以不包含View(SimpleTarget)。
(3)Drawable: 指Android中的Drawable类或者它的子类,如BitmapDrawable等。或者Glide中基础Drawable实现的自定义Drawable(如GifDrawable等)
(4)Request - 加载请求,可以是网络请求或者其他任何下载图片的请求,也是Glide中的一个类。
(5)Model:数据源的提供者,如Url,文件路径等,可以从model中获取InputStream。
(6)Signature:签名,可以唯一地标识一个对象。
(7)recycle():Glide中Resource类有此方法,表示该资源不被引用,可以放入池中(此时并没有释放空间)。Android中Bitmap也有此方法,表示释放Bitmap占用的内存。

1.主要特点
(1)支持Memory和Disk图片缓存。
(2)支持gif和webp格式图片。
(3)根据Activity/Fragment生命周期自动管理请求。
(4)使用Bitmap Pool可以使Bitmap复用。
(5)对于回收的Bitmap会主动调用recycle,减小系统回收压力。

2. 总体设计

基本概念
RequestManager:请求管理,每一个Activity都会创建一个RequestManager,根据对应Activity的生命周期管理该Activity上所以的图片请求。
Engine:加载图片的引擎,根据Request创建EngineJob和DecodeJob。
EngineJob:图片加载。
DecodeJob:图片处理。
流程图
这里是大概的总体流程图, 具体的细节中流程下面继续分析。

3. 核心类介绍

3.1 Gilde
用于保存整个框架中的配置。
重要方法:

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

用于创建RequestManager,这里是Glide通过Activity/Fragment生命周期管理Request原理所在,这个类很关键、很关键、很关键,重要的事情我只说三遍。
主要原理是创建一个自定义Fragment,然后通过自定义Fragment生命周期操作RequestManager,从而达到管理Request。

3.2 RequestManagerRetriever

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

这里判断是否只当前RequestManagerFragment是否存在RequestManager,保证一个Activity对应一个RequestManager, 这样有利于管理一个Activity上所有的Request。创建RequestManager的时候会将RequestManagerFragment中的回调接口赋值给RequestManager,达到RequestManager监听RequestManagerFragment的生命周期。

3.3 RequestManager
成员变量:
(1)Lifecycle lifecycle,用于监听RequestManagerFragment生命周期。
(2)RequestTracker requestTracker, 用于保存当前RequestManager所有的请求和带处理的请求。
重要方法:

@Override
//开始暂停的请求
public void onStart() {
 resumeRequests();
}
//停止所有的请求
@Override
public void onStop() {
 pauseRequests();
}

//关闭所以的请求
@Override
public void onDestroy() {
 requestTracker.clearRequests();
}

//创建RequestBuild
public DrawableTypeRequest<String> load(String string) {
 return (DrawableTypeRequest<String>) fromString().load(string);
}

public <Y extends Target<TranscodeType>> Y into(Y target) {
 ...
 Request previous = target.getRequest();
 //停止当前target中的Request。
 if (previous != null) {
 previous.clear(); //这个地方很关键,见Request解析
 requestTracker.removeRequest(previous);
 previous.recycle();
 }
 ...
 return target;
}

3.4 DrawableRequestBuilder
用于创建Request。 这里面包括很多方法,主要是配置加载图片的url、大小、动画、ImageView对象、自定义图片处理接口等。

3.5 Request
主要是操作请求,方法都很简单。

@Override
public void clear() {
 ...
 if (resource != null) {
 //这里会释放资源
 releaseResource(resource);
 }
 ...
}

这里的基本原理是当有Target使用Resource(Resource见下文)时,Resource中的引用记数值会加一,当释放资源Resource中的引用记数值减一。当没有Target使用的时候就会释放资源,放进Lrucache中。

3.6 EngineResource
实现Resource接口,使用装饰模式,里面包含实际的Resource对象

void release() {
 if (--acquired == 0) {
 listener.onResourceReleased(key, this);
 }
} 

void acquire() {
 ++acquired;
} 

@Override
public void recycle() {
 isRecycled = true;
 resource.recycle();
}

acquire和release两个方法是对资源引用计数;recycle释放资源,一般在Lrucache饱和时会触发。

3.7 Engine(重要)
请求引擎,主要做请求的开始的初始化。
3.7.1 load方法
这个方法很长,将分为几步分析
(1)获取MemoryCache中缓存 首先创建当前Request的缓存key,通过key值从MemoryCache中获取缓存,判断缓存是否存在。

private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
 ....
 EngineResource<?> cached = getEngineResourceFromCache(key);
 if (cached != null) {
 cached.acquire();
 activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
 }
 return cached;
}

@SuppressWarnings("unchecked")
private EngineResource<?> getEngineResourceFromCache(Key key) {
 Resource<?> cached = cache.remove(key);

 final EngineResource result;
 ...
 return result;
}

(重点)从缓存中获取的时候使用的cache.remove(key),然后将值保存在activeResources中,然后将Resource的引用计数加一。
优点:
> 正使用的Resource将会在activeResources中,不会出现在cache中,当MemoryCache中缓存饱和的时候或者系统内存不足的时候,清理Bitmap可以直接调用recycle,不用考虑Bitmap正在使用导致异常,加快系统的回收。
(2)获取activeResources中缓存
activeResources通过弱引用保存recouse ,也是通过key获取缓存,

private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable)

(3)判断当前的请求任务是否已经存在

EngineJob current = jobs.get(key);
if (current != null) {
 current.addCallback(cb);
 return new LoadStatus(cb, current);
}

如果任务请求已经存在,直接将回调事件传递给已经存在的EngineJob,用于请求成功后触发回调。
(4)执行请求任务

EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
 transcoder, diskCacheProvider, diskCacheStrategy, priority);
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(runnable);

3.8 EngineRunnable
请求执行Runnable,主要功能请求资源、处理资源、缓存资源。

private Resource<?> decodeFromCache() throws Exception {
 Resource<?> result = null;
 try {
 result = decodeJob.decodeResultFromCache();
 } catch (Exception e) {
 if (Log.isLoggable(TAG, Log.DEBUG)) {
  Log.d(TAG, "Exception decoding result from cache: " + e);
 }
 }

 if (result == null) {
 result = decodeJob.decodeSourceFromCache();
 }
 return result;
} 

private Resource<?> decodeFromSource() throws Exception {
 return decodeJob.decodeFromSource();
}

加载DiskCache和网络资源。加载DiskCache包括两个,因为Glide默认是保存处理后的资源(压缩和裁剪后),缓存方式可以自定义配置。如果客户端规范设计,ImageView大小大部分相同可以节省图片加载时间和Disk资源。

3.9 DecodeJob
public Resource<Z> decodeResultFromCache() throws Exception  
从缓存中获取处理后的资源。上面有关Key的内容,Key是一个对象,可以获取key和orginKey。decodeResultFromCache就是通过key获取缓存,decodeSourceFromCache()就是通过orginKey获取缓存。
private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded)
处理和包装资源;缓存资源。
保存原资源
private Resource<T> cacheAndDecodeSourceData(A data) throws IOException 
保存处理后的资源
private void writeTransformedToCache(Resource<T> transformed)

3.10 Transformation
Resource<T> transform(Resource<T> resource, int outWidth, int outHeight);
处理资源,这里面出现BitmapPool类,达到Bitmap复用。
3.11 ResourceDecoder
用于将文件、IO流转化为Resource
3.12 BitmapPool
用于存放从LruCache中remove的Bitmap, 用于后面创建Bitmap时候的重复利用。

4.杂谈
Glide的架构扩展性高,但是难以理解,各种接口、泛型,需要一定的学习才能熟练运用。
Glide的优点:
(1)支持对处理后的资源Disk缓存。
(2)通过BitmapPool对Bitmap复用。
(3)使用activityResources缓存正在使用的resource,对于BitmapPool饱和移除的Bitmap直接调用recycle加速内存回收。

(0)

相关推荐

  • Android自定义View基础开发之图片加载进度条

    学会了Paint,Canvas的基本用法之后,我们就可以动手开始实践了,先写个简单的图片加载进度条看看. 按照惯例,先看效果图,再决定要不要往下看: 既然看到这里了,应该是想了解这个图片加载进度条了,我们先看具体用法,再看自定义View的实现: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.co

  • 深入剖析Android的Volley库中的图片加载功能

    一.基本使用要点回顾 Volley框架在请求网络图片方面也做了很多工作,提供了好几种方法.本文介绍使用ImageLoader来进行网络图片的加载. ImageLoader的内部使用ImageRequest来实现,它的构造器可以传入一个ImageCache缓存形参,实现了图片缓存的功能,同时还可以过滤重复链接,避免重复发送请求. 下面是ImageLoader加载图片的实现方法: public void displayImg(View view){ ImageView imageView = (Im

  • 详解Android之图片加载框架Fresco基本使用(二)

    PS:最近看到很多人都开始写年终总结了,时间过得飞快,又到年底了,又老了一岁. 学习内容: 1.进度条 2.缩放 3.ControllerBuilder,ControllerListener,PostProcesser,Image Request 4.渐进式JPEG与动图的显示 最近这两天把Fresco的官方文档算是看了个差不多,就剩下Fresco的基本原理还有结合okHttp等类库如何使用的问题,虽然官方文档给出的功能比较的多,比如说自定义View,缩略图显示等等,这些我也基本就看了个大概,觉

  • Android程序开发ListView+Json+异步网络图片加载+滚动翻页的例子(图片能缓存,图片不错乱)

    例子中用于解析Json的Gson请自己Google下载 主Activity: package COM.Example.Main; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import COM.Example.Main.R; import COM.Example.Main.stringG

  • Android开发中ImageLoder进行图片加载和缓存

    图片处理类: package com.longfei.admin.imageloder_text; import android.app.Application; import android.graphics.Bitmap; import android.os.Environment; import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache; import com.nostra13.universa

  • Android图片加载缓存框架Glide

    Glide开源框架是Google推荐的图片加载和缓框架,其在Github上的开源地址是:https://github.com/bumptech/glide 当然一个Google推荐的框架肯定就是Volley啦. 目前Android主流开发工具是AndroidStudio,在AndroidStudio如何使用Glide,https://github.com/bumptech/glide上有详细的介绍说明. 因为刚换新工作不久,公司和的还是Eclipse,所以学习Glide我暂时还用的Eclipse

  • Android 常见的图片加载框架详细介绍

    Android 常见的图片加载框架 图片加载涉及到图片的缓存.图片的处理.图片的显示等.而随着市面上手机设备的硬件水平飞速发展,对图片的显示要求越来越高,稍微处理不好就会造成内存溢出等问题.很多软件厂家的通用做法就是借用第三方的框架进行图片加载. 开源框架的源码还是挺复杂的,但使用较为简单.大部分框架其实都差不多,配置稍微麻烦点,但是使用时一般只需要一行,显示方法一般会提供多个重载方法,支持不同需要.这样会减少很不必要的麻烦.同时,第三方框架的使用较为方便,这大大的减少了工作量.提高了开发效率.

  • Android图片加载案例分享

    HttpURLConnection和HttpClient都可以访问网络,前者是Java的标准类,后者是Apache的一个开源项目,两者使用起来效果一样,但后者更为简单.  以下是针对前者完成的一个实例: 首先写好布局文件: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"

  • 一起动手编写Android图片加载框架

    开发一个简洁而实用的Android图片加载缓存框架,并在内存占用与加载图片所需时间这两个方面与主流图片加载框架之一Universal Image Loader做出比较,来帮助我们量化这个框架的性能.通过开发这个框架,我们可以进一步深入了解Android中的Bitmap操作.LruCache.LruDiskCache,让我们以后与Bitmap打交道能够更加得心应手.若对Bitmap的大小计算及inSampleSize计算还不太熟悉,请参考这里:高效加载Bitmap.由于个人水平有限,叙述中必然存在

  • Android Glide图片加载(加载监听、加载动画)

    本文实例为大家分享了Android Glide图片加载的具体代码,供大家参考,具体内容如下 1.普通用法 Glide.with(context) .load(url) .into(view); with中可以放context.activity.fragment..:当放activity.fragment时glide会根据生命周期来加载图片.推荐使用activity. 2.设置加载中和加载失败的图片 Glide.with(context) .load(url) .placeholder(R.dra

随机推荐