Android中Glide加載庫(kù)的圖片緩存配置究極指南
零、選擇Glide
為什么圖片加載我首先推薦Glide?
圖片加載框架用了不少,從afinal框架的afinalBitmap,Xutils的BitmapUtils,老牌框架universalImageLoader,著名開源組織square的picasso,google推薦的glide到FaceBook推出的fresco。這些我前前后后都體驗(yàn)過(guò),那么面對(duì)這么多的框架,該如何選擇呢?下面簡(jiǎn)單分析下我的看法。
afinal和Xuils在github上作者已經(jīng)停止維護(hù)了,開源社區(qū)最新的框架要屬KJFramework,不過(guò)這種快速開發(fā)框架看似很好用,功能也應(yīng)有盡有,小型項(xiàng)目也罷,大型項(xiàng)目我不是很推薦,這樣做項(xiàng)目的耦合度太高,一旦出現(xiàn)停止維護(hù),而新的問(wèn)題不斷增加,沒(méi)人處理就麻煩了。
在glide和fresco還未出來(lái)的時(shí)候,當(dāng)時(shí)最火的莫過(guò)于universalImageLoader和picasso了,當(dāng)時(shí)覺(jué)得universalImageLoader配置相對(duì)picasso麻煩,雖然提供了各種配置,但是沒(méi)有實(shí)踐過(guò),根本不知道如何配置,還不如都采用默認(rèn)配置,就選擇了picasso作為圖片加載框架,用了近一年的時(shí)間,沒(méi)有太大的問(wèn)題,且使用簡(jiǎn)單,或許是因?yàn)橹暗捻?xiàng)目太過(guò)于簡(jiǎn)單,周期也并不是很長(zhǎng),還有使用eclipse開發(fā),一個(gè)很大的問(wèn)題一直都沒(méi)有暴露出來(lái),換上了最新的Android Studio可以清晰的看到各種性能相關(guān)的監(jiān)控,如cpu還有內(nèi)存監(jiān)控,終于知道了之前做的項(xiàng)目都那么的卡頓的罪魁禍?zhǔn)?,picasso加載稍微大一點(diǎn)的圖片就特別耗內(nèi)存,通常一個(gè)listView或者頂部滑動(dòng)廣告欄都含有多張圖片,這使得做出的頁(yè)面只要含圖片較多就異??D(之前的時(shí)候還把它歸結(jié)為測(cè)試機(jī)不好),知道這一點(diǎn)后我就有點(diǎn)想把picasso給替換掉,但這一次我不能那么粗心。
測(cè)試了picasso,glide,universalImageLoader,fresco這四個(gè)框架,測(cè)試內(nèi)容大概有以下幾項(xiàng),內(nèi)存測(cè)試,大圖片測(cè)試,小圖片測(cè)試,本地圖片,網(wǎng)絡(luò)圖片當(dāng)然還結(jié)合官方文檔體驗(yàn)其特色功能,內(nèi)存測(cè)試中,glide,universalImageLoader,fresco表現(xiàn)都非常優(yōu)秀,picasso這一點(diǎn)上實(shí)在是太糟糕了,小圖片差別也不是很大,稍微大點(diǎn)圖片內(nèi)存消耗就要比其他高出幾倍,這一點(diǎn)上證明了我的猜想,picasso不能再用了,下面一項(xiàng)項(xiàng)分析其他框架,在高于2M左右大圖測(cè)試中fresco的表現(xiàn)則和picasso一樣直接神馬都不顯示,項(xiàng)目中要實(shí)現(xiàn)大圖預(yù)覽功能,這點(diǎn)上是不行的,接著看universalImageLoader和glide在這幾項(xiàng)測(cè)試中成績(jī)都很好,到底該如何選擇呢?
因?yàn)槲翼?xiàng)目之前用的picasso,glide從用法上幾乎就是另一個(gè)picasso,從picasso轉(zhuǎn)移到glide相對(duì)改動(dòng)較少,還有一點(diǎn)就是這個(gè)項(xiàng)目是google在維護(hù),我也能給它更多的信任,相比較universalImageLoader,glide可以支持gif和短視頻,后期也需要用到,這里不得不談一下glide優(yōu)秀的緩存機(jī)制了,glide圖片緩存默認(rèn)使用RGB565相當(dāng)于ARGB8888可以節(jié)省不少的空間,支持與activity,fragment,application生命周期的聯(lián)動(dòng),更智能管理圖片請(qǐng)求當(dāng)然還有其他的擴(kuò)展更多可以看?glide介紹?當(dāng)然,glide的方法數(shù)量比universalImageLoader多了1000多個(gè),遇到64k問(wèn)題的會(huì)比較關(guān)注這個(gè)。
剛才只是掠過(guò)fresco,其實(shí)我對(duì)他的期待還是蠻大的,因?yàn)閯偝鰜?lái)還有居多不穩(wěn)定的地方,里面存在著大量吸引著我的功能,支持webps格式(和jpg一樣都是有損壓縮格式,webps相同質(zhì)量圖片更節(jié)省空間),支持漸進(jìn)式j(luò)peg,可以輕松的定制image的各種屬性,支持多圖請(qǐng)求和圖片復(fù)用,并支持手勢(shì)縮放和旋轉(zhuǎn)等等,更多介紹?fresco,當(dāng)然,實(shí)際用的時(shí)候并沒(méi)有那么好,很多功能都有待完善。
還有一點(diǎn)細(xì)節(jié)的地方要注意的,最好不要直接拿來(lái)用,至少經(jīng)過(guò)自己簡(jiǎn)單的封裝,而不是直接在項(xiàng)目中使用,一個(gè)簡(jiǎn)單的例子,后期圖片過(guò)多,可能需要另外配置一臺(tái)機(jī)器單獨(dú)存放圖片,主機(jī)地址做成可配置,可不要因?yàn)橐粋€(gè)簡(jiǎn)單的需求又要加班了
更多。
一、Glide3.0以來(lái)的新特性
1.動(dòng)態(tài)的GIF圖片加載:
Glide.with(context).load(...).asBitmap() //顯示gif靜態(tài)圖片 Glide.with(context).load(...).asGif() //顯示gif動(dòng)態(tài)圖片
2.本地視頻快照:
Glide現(xiàn)在還可以把視頻解碼為一張圖片:
Glide.with(context).load(“視頻路徑“)
(經(jīng)過(guò)我的測(cè)試,只能把手機(jī)本地的mp4視頻解析為一張圖片,把mp4文件放在raw文件中,不能解析)
3.對(duì)縮略圖的支持:
//加載yourView1/10尺寸的縮略圖,然后加載全圖 Glide.with(yourFragment).load(yourUrl).thumbnail(0.1f).into(yourView)
4.生命周期集成
同時(shí)將Activity/Fragment作為with()參數(shù)的好處是:圖片加載會(huì)和Activity/Fragment的生命周期保持一致,
請(qǐng)求會(huì)在onStop的時(shí)候自動(dòng)暫停,
在onStart的時(shí)候重新啟動(dòng),gif的動(dòng)畫也會(huì)在onStop的時(shí)候停止,以免在后臺(tái)消耗電量。
5.轉(zhuǎn)碼
Glide的.toBytes()和.transcode()方法允許在后臺(tái)獲取、解碼和轉(zhuǎn)換一個(gè)圖片,你可以將一張圖片轉(zhuǎn)換成更多有用的圖片格式,比如,上傳一張250*250的圖片
Glide.with(context) .load(“/user/profile/photo/path”) .asBitmap() .toBytes() .centerCrop() .into(new SimpleTarget<byte[]>(250, 250) { @Override public void onResourceReady(byte[] data, GlideAnimation anim) { // Post your bytes to a background thread and upload them here. } });
6.動(dòng)畫:3.x加入了cross fades和View的屬性動(dòng)畫的支持
比如
(.animate(ViewPropertyAnimation.Animator))
7. 網(wǎng)絡(luò)模塊可以選擇OkHttp或者Volley的支持
You can now choose to use either OkHttp, or Volley, or Glide's HttpUrlConnection default as your network stack.
Volley和OkHttp可以在gradle文件當(dāng)中添加依賴,注冊(cè)相應(yīng)的ModelLoaderFactory
二、圖片的緩存和緩存的時(shí)效機(jī)制
1.圖片緩存的鍵值
圖片緩存的鍵值主要用于DiskCacheStrategy.RESULT,Glide當(dāng)中的鍵值主要包含三個(gè)部分:
通過(guò)DataFetcher.getId()方法返回的String數(shù)據(jù)作為鍵值。一般的DataFetchers會(huì)簡(jiǎn)單返回?cái)?shù)據(jù)模型data model的toString()結(jié)果,如果是URL/File會(huì)返回相應(yīng)的路徑
圖片的尺寸,主要是通過(guò)override(width,height)或者通過(guò)Target's getSize()方法確定的尺寸信息
包含一個(gè)可選的簽名所有的這些東西會(huì)通過(guò)一種散列算法生成一個(gè)獨(dú)有、安全的文件名,通過(guò)此文件名將圖片緩存在disk中
2.緩存失效
因?yàn)镚lide當(dāng)中圖片緩存key的生成是通過(guò)一個(gè)散列算法來(lái)實(shí)現(xiàn)的,所以很難手動(dòng)去確定哪些文件可以從緩存當(dāng)中進(jìn)行刪除
2.1 當(dāng)內(nèi)容(url,file path)改變的時(shí)候,改變相應(yīng)的標(biāo)識(shí)符就可以了,Glide當(dāng)中也提供了signature()方法,將一個(gè)附加的數(shù)據(jù)加入到緩存key當(dāng)中
多媒體存儲(chǔ)數(shù)據(jù),可用MediaStoreSignature類作為標(biāo)識(shí)符,會(huì)將文件的修改時(shí)間、mimeType等信息作為cacheKey的一部分
文件,使用StringSignature
Urls ,使用StringSignature
Glide.with(yourFragment) .load(yourFileDataModel) .signature(new StringSignature(yourVersionMetadata)) .into(yourImageView); Glide.with(fragment) .load(mediaStoreUri) .signature(new MediaStoreSignature(mimeType, dateModified, orientation)) .into(view);
自定義標(biāo)識(shí)符:
public class IntegerVersionSignature implements Key { private int currentVersion; public IntegerVersionSignature(int currentVersion) { this.currentVersion = currentVersion; } @Override public boolean equals(Object o) { if (o instanceof IntegerVersionSignature) { IntegerVersionSignature other = (IntegerVersionSignature) o; return currentVersion = other.currentVersion; } return false; } @Override public int hashCode() { return currentVersion; } @Override public void updateDiskCacheKey(MessageDigest md) { messageDigest.update(ByteBuffer.allocate(Integer.SIZE) .putInt(signature).array()); } }
2.2、不緩存可以通過(guò)diskCacheStrategy(DiskCacheStrategy.NONE.)實(shí)現(xiàn)
三、配置GlideModules
可以通過(guò)GlideModule接口來(lái)配置Glide的配置文件,并且像ModelLoaders一樣注冊(cè)相關(guān)組件。
包含一個(gè)GlideMode :
第一步、To use and register a GlideModule, first implement the interface with your configuration and components:
public class MyGlideModule implements GlideModule { @Override public void applyOptions(Context context, GlideBuilder builder) { // Apply options to the builder here. } @Override public void registerComponents(Context context, Glide glide) { // register ModelLoaders here. } }
第二步、然后將上面的實(shí)現(xiàn)了加入到proguard.cfg當(dāng)中:
-keepnames class * com.mypackage.MyGlideModule
第三步、在AndroidManifest.xml文件中添加meta-data,以便Glide能夠找到你的Module
<meta-data android:name="com.bumptech.glide.samples.flickr.FlickrGlideModule" android:value="GlideModule" />
四、Library項(xiàng)目
一個(gè)Library項(xiàng)目可能會(huì)定義一個(gè)或者多個(gè)GlideModules,如果一個(gè)Library項(xiàng)目添加一個(gè)Module到Library項(xiàng)目的manifest當(dāng)中,依賴于此Library的應(yīng)用就會(huì)自動(dòng)加載依賴庫(kù)(Library項(xiàng)目)當(dāng)中的Module。
當(dāng)然,如果manifest的合并不正確,那么Library里面Module就必須手動(dòng)地在應(yīng)用當(dāng)中添加進(jìn)去。
五、GlideModules沖突
雖然Glide允許一個(gè)應(yīng)用當(dāng)中存在多個(gè)GlideModules,Glide并不會(huì)按照一個(gè)特殊的順序去調(diào)用已注冊(cè)的GlideModules,如果一個(gè)應(yīng)用的多個(gè)依賴工程當(dāng)中有多個(gè)相同的Modules,就有可能會(huì)產(chǎn)生沖突。
如果一個(gè)沖突是不可避免的,應(yīng)用應(yīng)該默認(rèn)去定義一個(gè)自己的Module,用來(lái)手動(dòng)地處理這個(gè)沖突,在進(jìn)行Manifest合并的時(shí)候,可以用下面的標(biāo)簽排除沖突的module。
<meta-data android:name=”com.mypackage.MyGlideModule” tools:node=”remove”/>
六、通過(guò)GlideBuilder配置全局配置文件
Glide允許開發(fā)者配置自定義的全局操作應(yīng)用于所有的請(qǐng)求,這個(gè)部分可以通過(guò)GlideModule接口中的applyOptions方法的GlideBuilder參數(shù)實(shí)現(xiàn) :
1.DiskCache
1.1、硬盤緩存是在一個(gè)后臺(tái)線程當(dāng)中,通過(guò)一個(gè)DiskCache.Factory接口進(jìn)行緩存的。
開發(fā)者能夠通過(guò)GlideBuilder的setDiskCache(DiskCache.Factory df)方法設(shè)置存儲(chǔ)的位置和大小
通過(guò)傳入DiskCacheAdapter來(lái)完全禁用緩存
自定義一個(gè)DiskCache來(lái)完全禁用緩存,
Glide默認(rèn)是用InternalCacheDiskCacheFactory類來(lái)創(chuàng)建硬盤緩存的,這個(gè)類會(huì)在應(yīng)用的內(nèi)部緩存目錄下面創(chuàng)建一個(gè)最大容量250MB的緩存文件夾,使用這個(gè)緩存目錄而不用sd卡,意味著除了本應(yīng)用之外,其他應(yīng)用是不能訪問(wèn)緩存的圖片文件的。
1.2.設(shè)置disk緩存的大小 : InternalCacheDiskCacheFactory
builder.setDiskCache(new InternalCacheDiskCacheFactory(context, yourSizeInBytes));
1.3.設(shè)置緩存的路徑
可以通過(guò)實(shí)現(xiàn)DiskCache.Factory,然后使用DiskLruCacheWrapper創(chuàng)建一個(gè)新的緩存目錄,比如,可以通過(guò)如下方式在外存當(dāng)中創(chuàng)建緩存目錄:
builder .setDiskCache(new DiskCache.Factory() { @Override public DiskCache build() { // Careful: the external cache directory doesn't enforce permissions File cacheLocation = new File(context.getExternalCacheDir(), "cache_dir_name"); cacheLocation.mkdirs(); return DiskLruCacheWrapper.get(cacheLocation, yourSizeInBytes); } });
2.內(nèi)存當(dāng)中的緩存和POOLS
GlideBuilder當(dāng)中,允許開發(fā)者去設(shè)置內(nèi)存當(dāng)中圖片緩存區(qū)的大小,主要涉及到的類包括MemoryCache和BitmapPool
2.1 大小的設(shè)置
默認(rèn)內(nèi)存緩存的大小是用過(guò)MemorySizeCalculator來(lái)實(shí)現(xiàn)的,這個(gè)類會(huì)根據(jù)設(shè)備屏幕的大小,計(jì)算出一個(gè)合適的size,開發(fā)者可以獲取到相關(guān)的默認(rèn)設(shè)置信息:
MemorySizeCalculator calculator = new MemorySizeCalculator(context); int defaultMemoryCacheSize = calculator.getMemoryCacheSize(); int defaultBitmapPoolSize = calculator.getBitmapPoolSize();
如果在應(yīng)用當(dāng)中想要調(diào)整內(nèi)存緩存的大小,開發(fā)者可以通過(guò)如下方式:
Glide.get(context).setMemoryCategory(MemoryCategory.HIGH);
2.2 Memory Cache
Glide內(nèi)存緩存的目的是減少I/O,提高效率
可以通過(guò)GlideBuidler的setMemoryCache(MemoryCache memoryCache)去設(shè)置緩存的大小,開發(fā)者可以通過(guò)LruResourceCache類去設(shè)置緩存區(qū)的大小
builder.setMemoryCache(new LruResourceCache(yourSizeInBytes));
2.3 Bitmap Pool
可以通過(guò)GlideBuilder的setBitmapPool()方法設(shè)置池子的大小,LruBitmapPool是Glide的默認(rèn)實(shí)現(xiàn),使用如下:
builder.setBitmapPool(new LruBitmapPool(sizeInBytes));
.圖片格式
GlideBuilder允許開發(fā)者設(shè)置一個(gè)全局的默認(rèn)圖片格式,
在默認(rèn)情況下,Glide使用RGB_565格式加載圖片,如果想要使用高質(zhì)量的圖片,可以通過(guò)如下方式設(shè)置系統(tǒng)的圖片格式:
builder.setDecodeFormat(DecodeFormat.ALWAYS_ARGB_8888);
七、自定義顯示控件
除了可以將圖片、視頻快照和GIFS顯示在View上面之外,開發(fā)者也可以在自定義的Target上面顯示這些媒體文件
1.SimpleTarget
重點(diǎn)內(nèi)容
如果你想簡(jiǎn)單地加載一個(gè)Bitmap,你可以通過(guò)以下簡(jiǎn)單的方式而不是直接地顯示給用戶,可能是顯示一個(gè)notification,或者上傳一個(gè)頭像,Glide都能很好地實(shí)現(xiàn)
SimpleTarget提供了對(duì)Target的簡(jiǎn)單實(shí)現(xiàn),并且讓你專注于對(duì)加載結(jié)果的處理
為了使用SimpleTarget,開發(fā)者需要提供一個(gè)寬和高的像素值,用來(lái)加載你的資源文件,并且你需要去實(shí)現(xiàn)
onResourceReady(R resource,GlideAnimation<? super R> glideAnimation) int myWidth = 512; int myHeight = 384; Glide.with(yourApplicationContext)) .load(youUrl) .asBitmap() .into(new SimpleTarget<Bitmap>(myWidth, myHeight) { @Override public void onResourceReady(Bitmap bitmap, GlideAnimation anim) { // Do something with bitmap here. } };
說(shuō)明:
通常你去加載資源的時(shí)候,是將他們加載到一個(gè)view當(dāng)中,當(dāng)fragment或者activity失去焦點(diǎn)或者distroyed的時(shí)候,Glide會(huì)自動(dòng)停止加載相關(guān)資源,確保資源不會(huì)被浪費(fèi)
在大多數(shù)SimpleTarget的實(shí)現(xiàn)當(dāng)中,如果需要資源的加載不受組件生命周期的影響,Glide.width(context)當(dāng)中的context是application context而不是fragment或者activity
另外,由于一些long running operations可能會(huì)導(dǎo)致內(nèi)存泄露,如果你打算使用一個(gè)這樣的操作,可以考慮使用一個(gè)靜態(tài)的內(nèi)部類而不是一個(gè)動(dòng)態(tài)的內(nèi)部類。
2.ViewTarget
如果你想加載一張圖片到一個(gè)view當(dāng)中,但是又想改變或者監(jiān)聽(tīng)Glide默認(rèn)的部分設(shè)置,就可以通過(guò)重寫ViewTarget或者他的子類來(lái)實(shí)現(xiàn)
如果你想Gidle加載圖片的時(shí)候可以自定義圖片的大小,或者想要設(shè)置一個(gè)自定義的顯示動(dòng)畫,就可以通過(guò)ViewTarget來(lái)實(shí)現(xiàn),可以通過(guò)一個(gè)靜態(tài)的ViewTarget或者動(dòng)態(tài)的內(nèi)部類來(lái)實(shí)現(xiàn)相關(guān)的功能
Glide.with(yourFragment) .load(yourUrl) .into(new ViewTarget<YourViewClass, GlideDrawable>(yourViewObject) { @Override public void onResourceReady(GlideDrawable resource, GlideAnimation anim) { YourViewClass myView = this.view; // Set your resource on myView and/or start your animation here. } });
說(shuō)明:
加載一張靜態(tài)的圖片或者一張GIF動(dòng)態(tài)圖,可以在load后面加上asBitmap()/asGif()
.Load(url)會(huì)通過(guò)asXXX()替換ViewTarget當(dāng)中的GlideDrawable參數(shù),也可以通過(guò)實(shí)現(xiàn)LifecycleLisener,給target設(shè)置一個(gè)回調(diào)。
3.覆蓋默認(rèn)的相關(guān)設(shè)置
如果只是想使用Glide的默認(rèn)配置,可以使用Glide當(dāng)中ImageViewTargets的兩個(gè)子類:
GlideDrawableImageViewTarget 默認(rèn)的實(shí)現(xiàn),可以通過(guò)asGif()加載動(dòng)態(tài)圖片
BitmapImageViewTarget 可以通過(guò)asBitmap()加載靜態(tài)圖片
如果想要使用Glide默認(rèn)實(shí)現(xiàn),可以在他們的子類方法當(dāng)中使用super.xx()即可,例如:
Glide.with(yourFragment) .load(yourUrl) .asBitmap() .into(new BitmapImageViewTarget(yourImageView)) { @Override public void onResourceReady(Bitmap bitmap, GlideAnimation anim) { super.onResourceReady(bitmap, anim); Palette.generateAsync(bitmap, new Palette.PaletteAsyncListener() { @Override public void onGenerated(Palette palette) { // Here's your generated palette } }); } });
八、使用Glide下載自定義尺寸的圖片
Glide的ModelLoader接口為開發(fā)者提供了裝載圖片的view的尺寸,并且允許開發(fā)者使用這些尺寸信息去選擇合適的URL去下載圖片。選用適當(dāng)?shù)某叽缈梢怨?jié)省寬帶和設(shè)備的空間開銷,提高app的性能
2014年googleI/o大會(huì)發(fā)表了一篇文章,闡述了他們?nèi)绾问褂肕odelLoader接口去適配圖片的尺寸,見(jiàn)下面的連接:https://github.com/google/iosched/blob/master/doc/IMAGES.md
1、通過(guò)http/https下載圖片,可以通過(guò)繼承BaseGlideUtlLoader來(lái)實(shí)現(xiàn):
public interface MyDataModel { public String buildUrl(int width, int height); } public class MyUrlLoader extends BaseGlideUrlLoader<MyDataModel> { @Override protected String getUrl(MyDataModel model, int width, int height) { // Construct the url for the correct size here. return model.buildUrl(width, height); } }
2、可以使用你自定義的ModelLoader去加載圖片了
Glide.with(yourFragment) .using(new MyUrlLoader()) .load(yourModel) .into(yourView);
如果你想避免每次加載圖片都要使用.using(new MyUrlLoader()) ,可以實(shí)現(xiàn)是一個(gè)
ModelLoaderFactory然后使用Glide將它注冊(cè)到GlideModule當(dāng)中 public class MyGlideModule implements GlideModule { ... @Override public void registerComponents(Context context, Glide glide) { glide.register(MyDataModel.class, InputStream.class, new MyUrlLoader.Factory()); } }
這樣你就可以跳過(guò).using()了
Glide.with(yourFragment) .load(yourModel) .into(yourView);
九、集成庫(kù)
1.什么是集成庫(kù)
Glide包含一些小的、可選的集成庫(kù),目前Glide集成庫(kù)當(dāng)中包含了訪問(wèn)網(wǎng)絡(luò)操作的Volley和OkHttp
2.為什么要包含集成庫(kù)
這些集成庫(kù),和Glide的ModelLoader系統(tǒng)允許開發(fā)者使用一致地框架去進(jìn)行網(wǎng)絡(luò)相關(guān)的操作
3.如何將一個(gè)庫(kù)集成到Glide當(dāng)中,
將一個(gè)庫(kù)集成到Glide當(dāng)中需要兩步操作,
包含正確的dependency,
確保創(chuàng)建了該集成庫(kù)的GlideModule,比如,
將Volley集成到Glide當(dāng)中
第一步、添加依賴
dependencies { compile 'com.github.bumptech.glide:volley-integration:1.2.2' compile 'com.mcxiaoke.volley:library:1.0.5' }
第二步、創(chuàng)建Volley集成庫(kù)的GlideModule
<meta-data android:name="com.bumptech.glide.integration.volley.VolleyGlideModule" android:value="GlideModule" />
然后改變混淆文件:
-keep class com.bumptech.glide.integration.volley.VolleyGlideModule #or -keep public class * implements com.bumptech.glide.module.GlideModule
將OkHttp集成到Glide當(dāng)中:
第一步、添加依賴
dependencies { compile 'com.github.bumptech.glide:okhttp-integration:1.2.2' compile 'com.squareup.okhttp:okhttp:2.0.0' }
第二步、創(chuàng)建OkHttp集成庫(kù)的GlideModule
<meta-data android:name="com.bumptech.glide.integration.okhttp.OkHttpGlideModule" android:value="GlideModule" />
-keep class com.bumptech.glide.integration.okhttp.OkHttpGlideModule #or -keep public class * implements com.bumptech.glide.module.GlideModule
十、在后臺(tái)線程當(dāng)中進(jìn)行加載和緩存
為了保證Glide在后臺(tái)線程當(dāng)中加載資源文件更加容易,Glide除了Glide.with(fragment).load(url).into(view)之外還提供了
downloadOnly(int width, int height) downloadOnly(Y target)// Y extends Target<File> into(int width, int height)
1.downloadOnly
Glide的downloadOnly()允許開發(fā)者將Image的二進(jìn)制文件下載到硬盤緩存當(dāng)中,以便在后續(xù)使用,
在UI線程當(dāng)中異步下載,在異步線程當(dāng)中則是使用width和height
在異步線程當(dāng)中同步調(diào)用下載,在同步線程當(dāng)中,
downloadOnly使用一個(gè)target作為參數(shù)
(1)在后臺(tái)線程當(dāng)中下載圖片,可以通過(guò)如下的方式:
FutureTarget<File> future = Glide.with(applicationContext) .load(yourUrl) .downloadOnly(500, 500); File cacheFile = future.get();
當(dāng)future返回的時(shí)候,image的二進(jìn)制文件信息就存入了disk緩存了,值得注意的是downloadOnly API只是保證圖片個(gè)bytes數(shù)據(jù)在disk當(dāng)中是有效的。
(2)下載完畢之后如果想要進(jìn)行顯示,可以通過(guò)如下方式進(jìn)行調(diào)用:
Glide.with(yourFragment) .load(yourUrl) .diskCacheStrategy(DiskCacheStrategy.ALL) .into(yourView);
通過(guò)DiskCacheStrategy.ALL或者DiskCacheStrategy.SOURCE,可以保證程序會(huì)去讀取緩存文件
2. 如果想要在后臺(tái)線程當(dāng)中獲取某個(gè)URL對(duì)應(yīng)的Bitmap
不通過(guò)downloadOnly,可以使用into(),會(huì)返回一個(gè)FutureTarget對(duì)象,比如,想要得到一個(gè)URL對(duì)應(yīng)的500*500的centerCrop裁剪圖片,可以通過(guò)如下方式實(shí)現(xiàn):
Bitmap myBitmap = Glide.with(applicationContext) .load(yourUrl) .asBitmap() .centerCrop() .into(500, 500) .get()
注意:上面的調(diào)用只能在異步線程當(dāng)中,如果在main Thread當(dāng)中調(diào)用.get(),會(huì)阻塞主線
十一、轉(zhuǎn)換器
1.默認(rèn)的轉(zhuǎn)換器
Glide兩個(gè)默認(rèn)的轉(zhuǎn)換器,fitCenter和CenterCrop,其他的轉(zhuǎn)換器詳見(jiàn)https://github.com/wasabeef/glide-transformations,可以將圖片轉(zhuǎn)為各種形狀,例如圓形,圓角型等等
用法:
Glide.with(yourFragment) .load(yourUrl) .fitCenter() .into(yourView); Glide.with(yourFragment) .load(yourUrl) .centerCrop() .into(yourView); // For Bitmaps: Glide.with(yourFragment) .load(yourUrl) .asBitmap() .centerCrop() .into(yourView); // For gifs: Glide.with(yourFragment) .load(yourUrl) .asGif() .fitCenter() .into(yourView);
甚至可以在兩幅圖片進(jìn)行類型轉(zhuǎn)換的時(shí)候進(jìn)行transformed
Glide.with(yourFragment) .load(yourUrl) .asBitmap() .toBytes() .centerCrop() .into(new SimpleTarget<byte[]>(...) { ... });
2.自定義轉(zhuǎn)換器
方法:
第一步、編寫轉(zhuǎn)換器類 ,繼承BitmapTransformation:
private static class MyTransformation extends BitmapTransformation { public MyTransformation(Context context) { super(context); } @Override protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { Bitmap myTransformedBitmap = ... // apply some transformation here. return myTransformedBitmap; } @Override public String getId() { // Return some id that uniquely identifies your transformation. return "com.example.myapp.MyTransformation"; } }
第二步、在Glide方法鏈當(dāng)中用.transform(…)替換fitCenter()/centerCrop()
Glide.with(yourFragment) .load(yourUrl) .transform(new MyTransformation(context)) .into(yourView); // For Bitmaps: Glide.with(yourFragment) .load(yourUrl) .asBitmap() .transform(new MyTransformation(context)) .into(yourView); // For Gifs: Glide.with(yourFragment) .load(yourUrl) .asGif() .transform(new MyTransformation(context)) .into(yourView);
3.自定義轉(zhuǎn)換器的尺寸
在上面使用過(guò)程當(dāng)中沒(méi)有設(shè)置尺寸值,那么轉(zhuǎn)換器轉(zhuǎn)換的圖片尺寸怎么確定呢,
Glide實(shí)際上已經(jīng)足夠智能根據(jù)view的尺寸來(lái)確定轉(zhuǎn)換圖片的尺寸了
如果需要自定義尺寸,而不是用view和target當(dāng)中的尺寸,那么可以使用override(int,int)設(shè)置相關(guān)的寬和高
4. Bitmap 再利用
為了減少垃圾收集,可以通過(guò)BitmapPool接口去釋放不需要的Bitmaps,當(dāng)然也可以對(duì)里面的bitmap進(jìn)行再利用。
例如在一次轉(zhuǎn)換中,
從pool當(dāng)中得到一個(gè)bitmap
將Bitmap回設(shè)給Canvas
使用Matrix、Paint在Canvas上面繪制原始的Bitmap,或者通過(guò)一個(gè)Shader來(lái)轉(zhuǎn)換一個(gè)image
4.1 不要手動(dòng)地去釋放一個(gè)轉(zhuǎn)換的bitmap資源,也不要將transform()之后的Bitmap重新放置到BitmapPool當(dāng)中去
protected Bitmap transform(BitmapPool bitmapPool, Bitmap original, int width, int height) { Bitmap result = bitmapPool.get(width, height, Bitmap.Config.ARGB_8888); // If no matching Bitmap is in the pool, get will return null, so we should //allocate. if (result == null) { // Use ARGB_8888 since we're going to add alpha to the image. result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); } // Create a Canvas backed by the result Bitmap. Canvas canvas = new Canvas(result); Paint paint = new Paint(); paint.setAlpha(128); // Draw the original Bitmap onto the result Bitmap with a transformation. canvas.drawBitmap(original, 0, 0, paint); // Since we've replaced our original Bitmap, we return our new Bitmap here. Glide will // will take care of returning our original Bitmap to the BitmapPool for us. return result; }
- Android中Glide獲取緩存大小并清除緩存圖片
- Android異步下載圖片并且緩存圖片到本地DEMO詳解
- Android基于SoftReference緩存圖片的方法
- Android Universal ImageLoader 緩存圖片
- android實(shí)現(xiàn)緩存圖片等數(shù)據(jù)
- android中圖片的三級(jí)緩存cache策略(內(nèi)存/文件/網(wǎng)絡(luò))
- android異步加載圖片并緩存到本地實(shí)現(xiàn)方法
- Android中Glide加載圖片并實(shí)現(xiàn)圖片緩存
- Android實(shí)現(xiàn)緩存大圖到SD卡
相關(guān)文章
flutter實(shí)現(xiàn)頭部tabTop滾動(dòng)欄
這篇文章主要為大家詳細(xì)介紹了flutter實(shí)現(xiàn)頭部tabTop滾動(dòng)欄,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03Android Studio無(wú)法執(zhí)行Java類的main方法問(wèn)題及解決方法
這篇文章主要介紹了Android Studio無(wú)法執(zhí)行Java main方法的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03Android Studio 3.0 gradle提示版本太老
這篇文章主要介紹了Android Studio 3.0 gradle提示版本太老的配置和解決方法。2017-11-11Android?RecyclerBarChart繪制使用教程
這篇文章主要為大家介紹了Android?RecyclerBarChart繪制使用教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12Android ViewPager實(shí)現(xiàn)左右滑動(dòng)的實(shí)例
這篇文章主要介紹了Android ViewPager實(shí)現(xiàn)左右滑動(dòng)的實(shí)例的相關(guān)資料,這里提供實(shí)現(xiàn)代碼實(shí)現(xiàn)左右滑動(dòng)的功能,希望能幫助到大家,需要的朋友可以參考下2017-08-08Android實(shí)現(xiàn)圖片點(diǎn)擊爆炸效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)圖片點(diǎn)擊爆炸效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08FragmentTabHost FrameLayout實(shí)現(xiàn)底部導(dǎo)航欄
這篇文章主要為大家詳細(xì)介紹了FragmentTabHost和FrameLayout實(shí)現(xiàn)底部導(dǎo)航欄,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03