by hzwusibo? 20190504
優(yōu)點(diǎn):
支持gif
鏈?zhǔn)秸{(diào)用 (? 編程性強(qiáng)扩所、? 可讀性強(qiáng)? 围详、 代碼簡潔)
glide三級(jí)緩存
Glide會(huì)自動(dòng)判斷ImageView的大小,然后只將這么大的圖片像素加載到內(nèi)存當(dāng)中祖屏,幫助我們節(jié)省內(nèi)存開支助赞。
對(duì)象池的使用生命周期綁定:圖片的加載任務(wù)會(huì)與activity或者Fragment的生命周期綁定,當(dāng)界面執(zhí)行onStop的使用自動(dòng)暫定袁勺,而當(dāng)執(zhí)行onStart的時(shí)候又會(huì)自動(dòng)重新開啟雹食,同樣的,動(dòng)態(tài)Gif圖的加載也是如此期丰,以用來節(jié)省電量群叶,
同時(shí)Glide會(huì)對(duì)網(wǎng)絡(luò)狀態(tài)做監(jiān)聽吃挑,當(dāng)網(wǎng)絡(luò)狀態(tài)發(fā)生改變時(shí),會(huì)重啟失敗的任務(wù)街立,以減少任務(wù)因網(wǎng)絡(luò)連接問題而失敗的概率舶衬。
預(yù)覽圖的使用
Q1:看過Glide源碼嗎,你印象最深的是什么赎离?
Glide的緩存設(shè)計(jì)非常先進(jìn)逛犹,考慮的場(chǎng)景也很周全。在緩存上Glide 分成了兩個(gè)模塊梁剔,一個(gè)是內(nèi)存緩存虽画,一個(gè)是硬盤緩存。
這兩個(gè)緩存模塊的作用各不相同荣病,內(nèi)存緩存的主要作用是防止應(yīng)用重復(fù)將圖片數(shù)據(jù)讀取到內(nèi)存當(dāng)中码撰,而硬盤緩存的主要作用是防止應(yīng)用重復(fù)從網(wǎng)絡(luò)或其他地方重復(fù)下載和讀取數(shù)據(jù)。
Q2:簡單說一下Glide的三級(jí)緩存个盆?
Glide緩存機(jī)制大致分為三層:內(nèi)存緩存灸拍、弱引用緩存、磁盤緩存砾省。
存的順序是:弱引用、內(nèi)存混槐、磁盤
取的順序是:內(nèi)存编兄、弱引用、磁盤
Q3:?glide三級(jí)緩存声登,glide加載一個(gè)一兆的圖片(100*100)狠鸳,是否會(huì)壓縮后再加載,放到一個(gè)200*200的view上會(huì)怎樣悯嗓,1000*1000呢件舵,圖片會(huì)很模糊,怎么處理脯厨?
而使用Glide铅祸,我們不用擔(dān)心圖片內(nèi)存浪費(fèi),內(nèi)存溢出的問題合武。因?yàn)镚lide不會(huì)直接將圖片的完整尺寸全部加載到內(nèi)存中临梗,而是用多少加載多少。Glide會(huì)自動(dòng)判斷ImageView的大小稼跳,然后只將這么大的圖片像素加載到內(nèi)存當(dāng)中盟庞,幫助我們節(jié)省內(nèi)存開支。
安卓圖片顯示的質(zhì)量配置主要分為四種:
ARGB_8888 :32位圖,帶透明度,每個(gè)像素占4個(gè)字節(jié)
ARGB_4444 :16位圖,帶透明度,每個(gè)像素占2個(gè)字節(jié)
RGB_565 :16位圖,不帶透明度,每個(gè)像素占2個(gè)字節(jié)
ALPHA_8 :32位圖,只有透明度,不帶顏色,每個(gè)像素占4個(gè)字節(jié)
Glide的默認(rèn)質(zhì)量則為 RGB_565
Picasso的默認(rèn)質(zhì)量是 ARGB_8888?
Glide也并沒有使用什么神奇的魔法汤善,它內(nèi)部的實(shí)現(xiàn)原理其實(shí)就是insmaplesize技術(shù)什猖,
Android高效加載大圖票彪、多圖解決方案,有效避免程序OOM
https://blog.csdn.net/guolin_blog/article/details/9316683
inSampleSize優(yōu)化
http://www.reibang.com/p/f15cd2ed6ec0
一個(gè)可選的BitmapFactory.Options參數(shù)不狮,將這個(gè)參數(shù)的inJustDecodeBounds屬性設(shè)置為true就可以讓解析方法禁止為bitmap分配內(nèi)存降铸,返回值也不再是一個(gè)Bitmap對(duì)象,而是null荤傲。雖然Bitmap是null了垮耳,但是BitmapFactory.Options的outWidth、outHeight和outMimeType屬性都會(huì)被賦值遂黍。
inSampleSize的默認(rèn)值和最小值為1(當(dāng)小于1時(shí)终佛,解碼器將該值當(dāng)做1來處理),且在大于1時(shí)雾家,該值只能為2的冪(當(dāng)不為2的冪時(shí)铃彰,解碼器會(huì)取與該值最接近的2的冪)。例如芯咧,當(dāng)inSampleSize為2時(shí)牙捉,一個(gè)20001000的圖片,將被縮小為1000500敬飒,相應(yīng)地邪铲,它的像素?cái)?shù)和內(nèi)存占用都被縮小為了原來的1/4:
Glide VS Picasso
不僅僅是 Google的推薦,支持 GIF 无拗。 在沒有 Glide 之前带到,常用的做法就是寫了個(gè)自定義 view 然后 用一個(gè) media 去播放。有了 Glide 之后可以像普通圖片那樣去加載并且顯示出來動(dòng)圖英染。
Glide VS fresco
fresco 最大只支持圖片文件大小為 2M 揽惹。有時(shí)候大的時(shí)候,? Glide 正常顯示四康, fresco顯示黑屏搪搏。。闪金。
fresco 更多是native實(shí)現(xiàn)疯溺。所以需要對(duì)NDK有所了解,哎垦,相比較于 Glide喝检, 同樣遇到問題之后,修改源碼的成本撼泛,Glide 更方便挠说。
Glide VS Android-Universal-Image-Loader
已經(jīng)不再維護(hù)的開源庫,
Android碎片化那么嚴(yán)重愿题,我們自己維護(hù)起來還是要考慮成本的损俭。所以 Glide 勝出蛙奖。?
Glide 支持功能更多。 比如 BitmapTransformation杆兵,比如圓形雁仲,圓角等。
更多變換
在圖片組件中我實(shí)現(xiàn)了三種自定義變換琐脏,包含圓形攒砖,圓角和模糊。
網(wǎng)上也有很多Glide的圖片變換開源庫日裙,我感覺做的最好的是glide-transformations這個(gè)庫了吧吹艇。它實(shí)現(xiàn)了很多通用的圖片變換效果,如裁剪變換昂拂、顏色變換受神、模糊變換等等,使得我們可以非常輕松地進(jìn)行各種各樣的圖片變換格侯。不過我們用不到那么多功能的話也不需要依賴一個(gè)三方庫了吧鼻听,主要還是要學(xué)習(xí)為主。
Glide 是如何解決圖片加載生命周期的联四?
Glide 的使用方式上撑碴,一定需要傳入一個(gè) context 給它〕眨可以根據(jù)不同的上下文進(jìn)行處理灰羽,拿到 context (除了application context)之后,Glide做了一件很巧妙的事情鱼辙,就是在這個(gè)界面上追加一個(gè) fragment,由于 fragment 添加到了 activity 上玫镐,是可以捕獲到生命周期的倒戏,因此可以在 destroy 的時(shí)候取消掉當(dāng)前context下的 glide對(duì)象中的加載任務(wù)。
Glide 坑爹的 wrap_content 不支持的問題
官方說了的恐似,不支持并且不建議imageview設(shè)置wrap_content杜跷。因?yàn)檫@樣 glide 不知道要加載多大的圖片給我們才好。? 普通的imageview其實(shí)也還好矫夷,如果放在列表(RecyclerView)中,? 由于我們并不知道目標(biāo)圖片大小是多大的葛闷,所以我們選擇了wrap_content,那么在上下來回滾動(dòng)過程中双藕,就會(huì)導(dǎo)致圖片一會(huì)大一會(huì)小的bug.
Glide Module自定義緩存
圖片框架中很多自定義的實(shí)現(xiàn),而緩存也是框架中最為常見的行為之一淑趾。因此在開發(fā)使用中有些項(xiàng)目需求不凡試下自定義Glide的緩存.
https://blog.csdn.net/qq_38859786/article/details/80291476
源碼解析
1,Glide采用的是三級(jí)緩存,內(nèi)存–>磁盤–>網(wǎng)絡(luò)
Glide的緩存功能,大部分都是在load()方法中進(jìn)行的
?A:內(nèi)存緩存的主要作用 :??? 是防止應(yīng)用重復(fù)將圖片數(shù)據(jù)讀取到內(nèi)存當(dāng)中,
?B:磁盤緩存的主要作用 :?? 是防止應(yīng)用重復(fù)從網(wǎng)絡(luò)或其他地方重復(fù)下載和讀取數(shù)據(jù)忧陪。
?C:Glide內(nèi)存緩存的實(shí)現(xiàn)使用的LruCache算法扣泊。結(jié)合弱引用的機(jī)制近范,共同完成了內(nèi)存緩存功能
3,Glide.with()
?????With方法有5個(gè)重載的構(gòu)造方法,運(yùn)行你在activity,frgament或者其他地方使用.得到一個(gè)RequestManager對(duì)象 ,RequestManager實(shí)現(xiàn)了LifeCycleListener接口,綁定Activity/Fragment生命周期延蟹,對(duì)請(qǐng)求進(jìn)行暫停评矩,恢復(fù),清除操作.
下面是5個(gè)構(gòu)造方法
//RequestManager實(shí)現(xiàn)了LifeCycleListener接口
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);
}
//V4包的fragment
public static RequestManager with(Fragment fragment) {
? ? RequestManagerRetriever retriever = RequestManagerRetriever.get();
? ? return retriever.get(fragment);
}
3.1RequestManage對(duì)象源碼
public class RequestManager implements LifecycleListener {
? ? private final Context context;
? ? private final Lifecycle lifecycle;
? ? private final RequestManagerTreeNode treeNode;
? ? private final RequestTracker requestTracker;
? ? private final Glide glide;
? ? public RequestManager(Context context, Lifecycle lifecycle, RequestManagerTreeNode treeNode) {
? ? ? ? this(context, lifecycle, treeNode, new RequestTracker(), new ConnectivityMonitorFactory());
? ? }
? ? RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode,
? ? ? ? ? ? ? ? ? RequestTracker requestTracker, ConnectivityMonitorFactory factory) {
? ? ? ? this.context = context.getApplicationContext();
? ? ? ? this.lifecycle = lifecycle;
? ? ? ? this.treeNode = treeNode;
? ? ? ? this.requestTracker = requestTracker;
? ? ? ? //通過Glide的靜態(tài)方法獲取實(shí)例對(duì)象,Glide是通過單利創(chuàng)建的
? ? this.glide = Glide.get(context);
? ? ? ? this.optionsApplier = new OptionsApplier();
4,load(url)
Glide的緩存功能,大部分都是在load()方法中進(jìn)行的
load()也有很多重載的方法,它可以加載網(wǎng)絡(luò)圖片,本地圖片,gif(動(dòng)態(tài)圖)圖,Uri,File,
public DrawableTypeRequest<String> load(String string) {
? ? return (DrawableTypeRequest<String>) fromString().load(string);
}
//加載Uri
public DrawableTypeRequest<Uri> load(Uri uri) {
? ? return (DrawableTypeRequest<Uri>) fromUri().load(uri);
}
//加載File
public DrawableTypeRequest<File> load(File file) {
? ? return (DrawableTypeRequest<File>) fromFile().load(file);
}
//直接加載圖片資源id,? R.mipmap.ic_launcher
public DrawableTypeRequest<Integer> load(Integer resourceId) {
? ? return (DrawableTypeRequest<Integer>) fromResource().load(resourceId);
}
//加載URL
@Deprecated
public DrawableTypeRequest<URL> load(URL url) {
? ? return (DrawableTypeRequest<URL>) fromUrl().load(url);
}
5,Glide的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:
? ? ? ? ? ? ? ? applyCenterCrop();
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case FIT_CENTER:
? ? ? ? ? ? case FIT_START:
? ? ? ? ? ? case FIT_END:
? ? ? ? ? ? ? ? applyFitCenter();
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? //$CASES-OMITTED$
? ? ? ? ? ? default:
? ? ? ? ? ? ? ? // Do nothing.
? ? ? ? }
? ? }
? ? return into(glide.buildImageViewTarget(view, transcodeClass));
}
最終調(diào)用的into方法
//Target我們可以理解成View,只是Glide對(duì)我們的View做了一層封裝阱飘。
public <Y extends Target<TranscodeType>> Y into(Y target) {
? ? //判斷是否在主線程,(UI界面更新只能在主線程),不在主線程就報(bào)異常
? ? Util.assertMainThread();
? ? if (target == null) {
? ? ? ? throw new IllegalArgumentException("You must pass in a non null Target");
? ? }
? ? if (!isModelSet) {
? ? ? ? throw new IllegalArgumentException("You must first set a model (try #load())");
? ? }
? ? //獲取request對(duì)象
? ? Request previous = target.getRequest();
? ? //requestTracker是請(qǐng)求跟蹤類對(duì)象斥杜,主要管理請(qǐng)求的發(fā)起,暫停沥匈,清除
? ? if (previous != null) {
? ? ? ? previous.clear();
? ? ? ? requestTracker.removeRequest(previous);
? ? ? ? previous.recycle();
? ? }
? ? //創(chuàng)建request對(duì)象
? ? Request request = buildRequest(target);
? ? target.setRequest(request);
? ? //將target加入lifecycle,綁定生命周期
? ? lifecycle.addListener(target);
? ? //執(zhí)行請(qǐng)求
? ? requestTracker.runRequest(request);
? ? return target;
Android圖片加載框架最全解析(一)蔗喂,Glide的基本用法
https://blog.csdn.net/guolin_blog/article/details/53759439
Android圖片加載框架最全解析(二),從源碼的角度理解Glide的執(zhí)行流https://blog.csdn.net/guolin_blog/article/details/53939176
Android圖片加載框架最全解析(五)咐熙,Glide強(qiáng)大的圖片變換功能
https://blog.csdn.net/guolin_blog/article/details/71524668
Android圖片加載框架最全解析(七)弱恒,實(shí)現(xiàn)帶進(jìn)度的Glide圖片加載功能
https://blog.csdn.net/guolin_blog/article/details/78357251
磁盤緩存
//DiskCacheStrategy.SOURCE:緩存原始數(shù)據(jù),
// DiskCacheStrategy.RESULT:緩存變換后的資源數(shù)據(jù)棋恼,
// DiskCacheStrategy.NONE:什么都不緩存返弹,
DiskCacheStrategy.ALL:緩存SOURC和RESULT。
? // 默認(rèn)采用DiskCacheStrategy.RESULT策略
Glide會(huì)為每種大小的ImageView緩存一次爪飘。盡管一張圖片已經(jīng)緩存了一次义起,但是假如你要在另外一個(gè)地方再次以不同尺寸顯示,需要重新下載师崎,調(diào)整成新尺寸的大小默终,然后將這個(gè)尺寸的也緩存起來。具體說來就是:假如在第一個(gè)頁面有一個(gè)200x200的ImageView犁罩,在第二個(gè)頁面有一個(gè)100x100的ImageView齐蔽,這兩個(gè)ImageView本來是要顯示同一張圖片,卻需要下載兩次;可以通過改變Glide的行為讓它即加載全尺寸圖片,也加載不同尺寸圖片
Glide.with(this)?
.load("http://nuuneoi.com/uploads/source/playstore/cover.jpg")?
.diskCacheStrategy(DiskCacheStrategy.ALL)?
.into(ivImgGlide);?
下次在任何ImageView中加載圖片的時(shí)候床估,全尺寸的圖片將從緩存中取出含滴,重新調(diào)整大小,然后緩存丐巫。