Glide原理

Glide

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

三步走:先with(),再load(),最后into()

with()方法

是Glide类中的一组静态方法,

with()方法的重载种类非常多,既可以传入Activity,也可以传入Fragment或者是Context。每一个with()方法重载的代码都非常简单,都是先调用RequestManagerRetriever的静态get()方法得到一个

RequestManagerRetriever对象,这个静态get()方法就是一个单例实现,

然后再调用RequestManagerRetriever的实例get()方法,去获取RequestManager对象。

publicRequestManagerget(Context context){if(context==null){thrownewIllegalArgumentException("You cannot start a load on a null Context");}elseif(Util.isOnMainThread()&&!(context instanceof Application)){if(context instanceof FragmentActivity){returnget((FragmentActivity)context);}elseif(context instanceof Activity){returnget((Activity)context);}elseif(context instanceof ContextWrapper){returnget(((ContextWrapper)context).getBaseContext());}}returngetApplicationManager(context);}--------------------------------------------------------------------------------------publicRequestManagerget(FragmentActivity activity){if(Util.isOnBackgroundThread()){returnget(activity.getApplicationContext());}else{assertNotDestroyed(activity);FragmentManager fm=activity.getSupportFragmentManager();returnsupportFragmentGet(activity,fm);}}

get方法首先会判断传入的Context的类型,如果传入的Context类型是Application或者是在子线程加载的图片,这会通过getApplicationManager方法单例形式创建一个RequestManager对象。

否则会调用fragmentGet方法,传入Context对象和FragmentManager对象

image.png

这几个重载方法最终都是调用RequestManagerRetriever.get()方法获取RequestManagerRetriever对象,然后通过这个对象获取RequestManager对象

总结

width方法最终目的都是通过RequestManagerRetriever对象的get方法获取RequestManager对象,传入参数主要分Application类型和非Application类型

如果with方法传入的是Application,会通过调用getApplicationManager()来获取一个RequestManager对象,不需要处理生命周期,因为Application对象的生命周期就是应用程序的生命周期

如果with方法传入的不是Application类型,最终流程都是一样,那就是会向当前的Activity当中添加一个隐藏的Fragment,app包下的fragment会调用fragmentGet方法创建隐藏fragment,v4包下的fragment会调用supportFragmentGet方法创建fragment,都会返回RequestManager对象,创建隐藏fragment的目的是Glide需要知道加载的生命周期,可是Glide并没有办法知道Activity的生命周期,于是Glide就使用了添加隐藏Fragment的这种小技巧,因为Fragment的生命周期和Activity是同步的,如果Activity被销毁了,Fragment是可以监听到的,这样Glide就可以捕获这个事件并停止图片加载了。

如果我们是在非主线程当中使用的Glide,那么不管你是传入的Activity还是Fragment,都会被强制当成Application来处理,调用getApplicationManager()来获取RequestManager对象

SupportRequestManagerFragment类里面 构造方法中创建了一个ActivityFragmentLifecycle对象,这个对象就是监听fragment生命周期的,从fragment的生命周期方法中可以很明确看出来。

image.png

load()方法

参数类型:String,File,byte[],URL,图片资源ID,Uri,我这里只看参数类型为String类型的,这些方法都会返回DrawableTypeRequest对象。

image.png

load内部调用了fromString方法,fromString方法调用了loadGeneric方法,

loadGeneric()方法也没几行代码,这里分别调用了Glide.buildStreamModelLoader()方法和Glide.buildFileDescriptorModelLoader()方法来获得ModelLoader对象。

ModelLoader对象是用于加载图片的,而我们给load()方法传入不同类型的参数,这里也会得到不同的ModelLoader对象,最后返回一个DrawableTypeRequest对象。

DrawableTypeRequest的父类是DrawableRequestBuilder,

DrawableRequestBuilder中有很多个方法,这些方法其实就是Glide绝大多数的API了。里面有不少我们在上篇文章中已经用过了,比如说placeholder()方法、error()方法、diskCacheStrategy()方法、override()方法等,都是在DrawableRequestBuilder 类里面。提供了glide加载图片过程的很多方法

image.png

publicclassDrawableRequestBuilder<ModelType>extends GenericRequestBuilder<ModelType,ImageVideoWrapper,GifBitmapWrapper,GlideDrawable>implements BitmapOptions,DrawableOptions{DrawableRequestBuilder(Context context,Class<ModelType>modelClass,LoadProvider<ModelType,ImageVideoWrapper,GifBitmapWrapper,GlideDrawable>loadProvider,Glide glide,RequestTracker requestTracker,Lifecycle lifecycle){super(context,modelClass,loadProvider,GlideDrawable.class,glide,requestTracker,lifecycle);// Default to animating.crossFade();}//图片的一种显示格式@SuppressWarnings("unchecked")publicDrawableRequestBuilder<ModelType>centerCrop(){returntransform(glide.getDrawableCenterCrop());}//图片的一种显示格式@SuppressWarnings("unchecked")publicDrawableRequestBuilder<ModelType>fitCenter(){returntransform(glide.getDrawableFitCenter());}//图片显示设置渐变时间publicDrawableRequestBuilder<ModelType>crossFade(int duration){super.animate(new DrawableCrossFadeFactory<GlideDrawable>(duration));returnthis;}//磁盘缓存策略@OverridepublicDrawableRequestBuilder<ModelType>diskCacheStrategy(DiskCacheStrategy strategy){super.diskCacheStrategy(strategy);returnthis;}//是否跳过内存缓存@OverridepublicDrawableRequestBuilder<ModelType>skipMemoryCache(boolean skip){super.skipMemoryCache(skip);returnthis;}//设置图片尺寸@OverridepublicDrawableRequestBuilder<ModelType>override(int width,int height){super.override(width,height);returnthis;}//设置图片加载优先级@OverridepublicDrawableRequestBuilder<ModelType>priority(Priority priority){super.priority(priority);returnthis;}}

GenericRequestBuilder类:DrawableRequestBuilder的父类,这里面提供了绝大部分glide加载图片过程中的方法,它的子类都是实现了这个父类。

into()方法的作用:

①初始化各种参数,做好准备工作(网络请求、基于MVP的各种接口回调),②使用最原始的HTTPConnect网络连接,读取文件流,③根据文件判断是GIF动图还是Bitmap静态图片,④通过相关复杂逻辑将下载的图片资源取出来,赋值给ImageView控件。

into(ImageViewimageView)方法:@OverridepublicTarget<GlideDrawable>into(ImageViewview){returnsuper.into(view);}调用父类GenericRequestBuilder的into方法publicTarget<TranscodeType>into(ImageViewview){//断言是不是在主线程 因为ui更新操作在主线程Util.assertMainThread();if(view==null){thrownewIllegalArgumentException("You must pass in a non null View");}if(!isTransformationSet&&view.getScaleType()!=null){switch(view.getScaleType()){caseCENTER_CROP:applyCenterCrop();break;caseFIT_CENTER:caseFIT_START:caseFIT_END:applyFitCenter();break;//$CASES-OMITTED$default:// Do nothing.}}returninto(glide.buildImageViewTarget(view,transcodeClass));}

into方法最终会调用into(Target target)方法返回一个target对象,通过glide.buildImageViewTarget(view, transcodeClass)创建一个target对象

public<YextendsTarget<TranscodeType>>Yinto(Ytarget){Util.assertMainThread();if(target==null){thrownewIllegalArgumentException("You must pass in a non null Target");}if(!isModelSet){thrownewIllegalArgumentException("You must first set a model (try #load())");}Requestprevious=target.getRequest();if(previous!=null){previous.clear();requestTracker.removeRequest(previous);previous.recycle();}Requestrequest=buildRequest(target);target.setRequest(request);lifecycle.addListener(target);//RequestTracker类用于跟踪、取消和重新启动进程中、已完成和失败请求//执行请求requestTracker.runRequest(request);returntarget;}@OverridepublicvoidsetRequest(Requestrequest){setTag(request);}

这里首先还是检查是不是在主线程,因为更新ui的操作必须在主线程,这里首先会通过target对象获取request对象,然后清除之前的request对象,回收request对象,然后重新构建一个新的request对象,并且给这个target设置request对象,这其实就是好比listView加载图片时候给图片设置tag,防止图片错位问题,这里requestTracker.runRequest这个方法就是执行图片请求的方法

publicvoidrunRequest(Requestrequest){requests.add(request);if(!isPaused){request.begin();// begin方法: 真正执行request请求的方法}else{pendingRequests.add(request);}}

注意点

1、对于Application类型参数:

在非主线程当中使用的Glide,那么不管你是传入的Activity还是Fragment,都会被强制当成Application来处理。

如果传入的就是Application类型参数(Glide.with(getApplicationContext())),那么会通过getApplicationManager()方法返回RequestManager。Glide加载图片的生命周期是和with里的参数保持一致,而对于Application类型,只有当应用程序被杀掉的时候,图片加载才会停止。

2、Glide添加请求头 cookie

GlideUrl glideUrl=newGlideUrl(url,newHeaders(){@Overridepublic Map<String,String>getHeaders(){Map<String,String>header=newHashMap<>();//不一定都要添加,具体看原站的请求信息header.put("Referer","http://www.baidu.com");returnheader;}});Glide.with(context).load(url).into(imageView);

Glide的核心思想:

对象池:

Glide原理的核心是为bitmap维护一个对象池。对象池的主要目的是通过减少大对象内存的分配以重用来提高性能。

生命周期绑定:

第一个with方法,这个其实就是一个工厂方法,虽然有许多重载的形式,其实都是要创建一个RequestManager对象。

创建一个透明的 RequestManagerFragment 加入到FragmentManager 之中

通过添加的这个 Fragment 感知 Activity 、Fragment 的生命周期。

图片的加载任务会与activity或者Fragment的生命周期绑定,当界面执行onStop的使用自动暂定,而当执行onStart的时候又会自动重新开启,同样的,动态Gif图的加载也是如此,以用来节省电量,同时Glide会对网络状态做监听,当网络状态发生改变时,会重启失败的任务,以减少任务因网络连接问题而失败的概率。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,284评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,115评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,614评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,671评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,699评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,562评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,309评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,223评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,668评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,859评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,981评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,705评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,310评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,904评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,023评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,146评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,933评论 2 355

推荐阅读更多精彩内容

  • 前言 1. Glide 基本用法 接下来的讲解将基于 Glide 目前的最新版本 4.11。 Glide 的使用特...
    灯不利多阅读 2,239评论 0 3
  • Glide是一个优秀的图片加载库,它有如下优点: Glide可以监听Activity的生命周期管理,更加合理的管理...
    Ihesong阅读 3,372评论 1 5
  • 1.Glide是什么? Glide是Google在2014的IO大会发布一款图片处理框架,是目前android领域...
    无语_4c3f阅读 3,209评论 0 4
  • 原理: 在glide中的with方法中,需要传入上下文,他底层都是调用的getretriever方法,当传入fra...
    BnAO阅读 564评论 1 0
  • Glide分析 发展到现在Android的图片加载框架越来越成熟从一开始的UIL到后来的Glide、Picasso...
    Jesse_zhao阅读 6,162评论 1 8