Android中Glide加載庫的圖片緩存配置究極指南
零、選擇Glide
為什么圖片加載我首先推薦Glide?
圖片加載框架用了不少,從afinal框架的afinalBitmap,Xutils的BitmapUtils,老牌框架universalImageLoader,著名開源組織square的picasso,google推薦的glide到FaceBook推出的fresco。這些我前前后后都體驗過,那么面對這么多的框架,該如何選擇呢?下面簡單分析下我的看法。
afinal和Xuils在github上作者已經(jīng)停止維護了,開源社區(qū)最新的框架要屬KJFramework,不過這種快速開發(fā)框架看似很好用,功能也應(yīng)有盡有,小型項目也罷,大型項目我不是很推薦,這樣做項目的耦合度太高,一旦出現(xiàn)停止維護,而新的問題不斷增加,沒人處理就麻煩了。
在glide和fresco還未出來的時候,當(dāng)時最火的莫過于universalImageLoader和picasso了,當(dāng)時覺得universalImageLoader配置相對picasso麻煩,雖然提供了各種配置,但是沒有實踐過,根本不知道如何配置,還不如都采用默認(rèn)配置,就選擇了picasso作為圖片加載框架,用了近一年的時間,沒有太大的問題,且使用簡單,或許是因為之前的項目太過于簡單,周期也并不是很長,還有使用eclipse開發(fā),一個很大的問題一直都沒有暴露出來,換上了最新的Android Studio可以清晰的看到各種性能相關(guān)的監(jiān)控,如cpu還有內(nèi)存監(jiān)控,終于知道了之前做的項目都那么的卡頓的罪魁禍?zhǔn)?,picasso加載稍微大一點的圖片就特別耗內(nèi)存,通常一個listView或者頂部滑動廣告欄都含有多張圖片,這使得做出的頁面只要含圖片較多就異常卡頓(之前的時候還把它歸結(jié)為測試機不好),知道這一點后我就有點想把picasso給替換掉,但這一次我不能那么粗心。
測試了picasso,glide,universalImageLoader,fresco這四個框架,測試內(nèi)容大概有以下幾項,內(nèi)存測試,大圖片測試,小圖片測試,本地圖片,網(wǎng)絡(luò)圖片當(dāng)然還結(jié)合官方文檔體驗其特色功能,內(nèi)存測試中,glide,universalImageLoader,fresco表現(xiàn)都非常優(yōu)秀,picasso這一點上實在是太糟糕了,小圖片差別也不是很大,稍微大點圖片內(nèi)存消耗就要比其他高出幾倍,這一點上證明了我的猜想,picasso不能再用了,下面一項項分析其他框架,在高于2M左右大圖測試中fresco的表現(xiàn)則和picasso一樣直接神馬都不顯示,項目中要實現(xiàn)大圖預(yù)覽功能,這點上是不行的,接著看universalImageLoader和glide在這幾項測試中成績都很好,到底該如何選擇呢?
因為我項目之前用的picasso,glide從用法上幾乎就是另一個picasso,從picasso轉(zhuǎn)移到glide相對改動較少,還有一點就是這個項目是google在維護,我也能給它更多的信任,相比較universalImageLoader,glide可以支持gif和短視頻,后期也需要用到,這里不得不談一下glide優(yōu)秀的緩存機制了,glide圖片緩存默認(rèn)使用RGB565相當(dāng)于ARGB8888可以節(jié)省不少的空間,支持與activity,fragment,application生命周期的聯(lián)動,更智能管理圖片請求當(dāng)然還有其他的擴展更多可以看?glide介紹?當(dāng)然,glide的方法數(shù)量比universalImageLoader多了1000多個,遇到64k問題的會比較關(guān)注這個。
剛才只是掠過fresco,其實我對他的期待還是蠻大的,因為剛出來還有居多不穩(wěn)定的地方,里面存在著大量吸引著我的功能,支持webps格式(和jpg一樣都是有損壓縮格式,webps相同質(zhì)量圖片更節(jié)省空間),支持漸進式j(luò)peg,可以輕松的定制image的各種屬性,支持多圖請求和圖片復(fù)用,并支持手勢縮放和旋轉(zhuǎn)等等,更多介紹?fresco,當(dāng)然,實際用的時候并沒有那么好,很多功能都有待完善。
還有一點細(xì)節(jié)的地方要注意的,最好不要直接拿來用,至少經(jīng)過自己簡單的封裝,而不是直接在項目中使用,一個簡單的例子,后期圖片過多,可能需要另外配置一臺機器單獨存放圖片,主機地址做成可配置,可不要因為一個簡單的需求又要加班了
更多。
一、Glide3.0以來的新特性
1.動態(tài)的GIF圖片加載:
Glide.with(context).load(...).asBitmap() //顯示gif靜態(tài)圖片 Glide.with(context).load(...).asGif() //顯示gif動態(tài)圖片
2.本地視頻快照:
Glide現(xiàn)在還可以把視頻解碼為一張圖片:
Glide.with(context).load(“視頻路徑“)
(經(jīng)過我的測試,只能把手機本地的mp4視頻解析為一張圖片,把mp4文件放在raw文件中,不能解析)
3.對縮略圖的支持:
//加載yourView1/10尺寸的縮略圖,然后加載全圖 Glide.with(yourFragment).load(yourUrl).thumbnail(0.1f).into(yourView)
4.生命周期集成
同時將Activity/Fragment作為with()參數(shù)的好處是:圖片加載會和Activity/Fragment的生命周期保持一致,
請求會在onStop的時候自動暫停,
在onStart的時候重新啟動,gif的動畫也會在onStop的時候停止,以免在后臺消耗電量。
5.轉(zhuǎn)碼
Glide的.toBytes()和.transcode()方法允許在后臺獲取、解碼和轉(zhuǎn)換一個圖片,你可以將一張圖片轉(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.動畫:3.x加入了cross fades和View的屬性動畫的支持
比如
(.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)中添加依賴,注冊相應(yīng)的ModelLoaderFactory
二、圖片的緩存和緩存的時效機制
1.圖片緩存的鍵值
圖片緩存的鍵值主要用于DiskCacheStrategy.RESULT,Glide當(dāng)中的鍵值主要包含三個部分:
通過DataFetcher.getId()方法返回的String數(shù)據(jù)作為鍵值。一般的DataFetchers會簡單返回數(shù)據(jù)模型data model的toString()結(jié)果,如果是URL/File會返回相應(yīng)的路徑
圖片的尺寸,主要是通過override(width,height)或者通過Target's getSize()方法確定的尺寸信息
包含一個可選的簽名所有的這些東西會通過一種散列算法生成一個獨有、安全的文件名,通過此文件名將圖片緩存在disk中
2.緩存失效
因為Glide當(dāng)中圖片緩存key的生成是通過一個散列算法來實現(xiàn)的,所以很難手動去確定哪些文件可以從緩存當(dāng)中進行刪除
2.1 當(dāng)內(nèi)容(url,file path)改變的時候,改變相應(yīng)的標(biāo)識符就可以了,Glide當(dāng)中也提供了signature()方法,將一個附加的數(shù)據(jù)加入到緩存key當(dāng)中
多媒體存儲數(shù)據(jù),可用MediaStoreSignature類作為標(biāo)識符,會將文件的修改時間、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)識符:
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、不緩存可以通過diskCacheStrategy(DiskCacheStrategy.NONE.)實現(xiàn)
三、配置GlideModules
可以通過GlideModule接口來配置Glide的配置文件,并且像ModelLoaders一樣注冊相關(guān)組件。
包含一個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. } }
第二步、然后將上面的實現(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項目
一個Library項目可能會定義一個或者多個GlideModules,如果一個Library項目添加一個Module到Library項目的manifest當(dāng)中,依賴于此Library的應(yīng)用就會自動加載依賴庫(Library項目)當(dāng)中的Module。
當(dāng)然,如果manifest的合并不正確,那么Library里面Module就必須手動地在應(yīng)用當(dāng)中添加進去。
五、GlideModules沖突
雖然Glide允許一個應(yīng)用當(dāng)中存在多個GlideModules,Glide并不會按照一個特殊的順序去調(diào)用已注冊的GlideModules,如果一個應(yīng)用的多個依賴工程當(dāng)中有多個相同的Modules,就有可能會產(chǎn)生沖突。
如果一個沖突是不可避免的,應(yīng)用應(yīng)該默認(rèn)去定義一個自己的Module,用來手動地處理這個沖突,在進行Manifest合并的時候,可以用下面的標(biāo)簽排除沖突的module。
<meta-data android:name=”com.mypackage.MyGlideModule” tools:node=”remove”/>
六、通過GlideBuilder配置全局配置文件
Glide允許開發(fā)者配置自定義的全局操作應(yīng)用于所有的請求,這個部分可以通過GlideModule接口中的applyOptions方法的GlideBuilder參數(shù)實現(xiàn) :
1.DiskCache
1.1、硬盤緩存是在一個后臺線程當(dāng)中,通過一個DiskCache.Factory接口進行緩存的。
開發(fā)者能夠通過GlideBuilder的setDiskCache(DiskCache.Factory df)方法設(shè)置存儲的位置和大小
通過傳入DiskCacheAdapter來完全禁用緩存
自定義一個DiskCache來完全禁用緩存,
Glide默認(rèn)是用InternalCacheDiskCacheFactory類來創(chuàng)建硬盤緩存的,這個類會在應(yīng)用的內(nèi)部緩存目錄下面創(chuàng)建一個最大容量250MB的緩存文件夾,使用這個緩存目錄而不用sd卡,意味著除了本應(yīng)用之外,其他應(yīng)用是不能訪問緩存的圖片文件的。
1.2.設(shè)置disk緩存的大小 : InternalCacheDiskCacheFactory
builder.setDiskCache(new InternalCacheDiskCacheFactory(context, yourSizeInBytes));
1.3.設(shè)置緩存的路徑
可以通過實現(xiàn)DiskCache.Factory,然后使用DiskLruCacheWrapper創(chuàng)建一個新的緩存目錄,比如,可以通過如下方式在外存當(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)存緩存的大小是用過MemorySizeCalculator來實現(xiàn)的,這個類會根據(jù)設(shè)備屏幕的大小,計算出一個合適的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ā)者可以通過如下方式:
Glide.get(context).setMemoryCategory(MemoryCategory.HIGH);
2.2 Memory Cache
Glide內(nèi)存緩存的目的是減少I/O,提高效率
可以通過GlideBuidler的setMemoryCache(MemoryCache memoryCache)去設(shè)置緩存的大小,開發(fā)者可以通過LruResourceCache類去設(shè)置緩存區(qū)的大小
builder.setMemoryCache(new LruResourceCache(yourSizeInBytes));
2.3 Bitmap Pool
可以通過GlideBuilder的setBitmapPool()方法設(shè)置池子的大小,LruBitmapPool是Glide的默認(rèn)實現(xiàn),使用如下:
builder.setBitmapPool(new LruBitmapPool(sizeInBytes));
.圖片格式
GlideBuilder允許開發(fā)者設(shè)置一個全局的默認(rèn)圖片格式,
在默認(rèn)情況下,Glide使用RGB_565格式加載圖片,如果想要使用高質(zhì)量的圖片,可以通過如下方式設(shè)置系統(tǒng)的圖片格式:
builder.setDecodeFormat(DecodeFormat.ALWAYS_ARGB_8888);
七、自定義顯示控件
除了可以將圖片、視頻快照和GIFS顯示在View上面之外,開發(fā)者也可以在自定義的Target上面顯示這些媒體文件
1.SimpleTarget
重點內(nèi)容
如果你想簡單地加載一個Bitmap,你可以通過以下簡單的方式而不是直接地顯示給用戶,可能是顯示一個notification,或者上傳一個頭像,Glide都能很好地實現(xiàn)
SimpleTarget提供了對Target的簡單實現(xiàn),并且讓你專注于對加載結(jié)果的處理
為了使用SimpleTarget,開發(fā)者需要提供一個寬和高的像素值,用來加載你的資源文件,并且你需要去實現(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. } };
說明:
通常你去加載資源的時候,是將他們加載到一個view當(dāng)中,當(dāng)fragment或者activity失去焦點或者distroyed的時候,Glide會自動停止加載相關(guān)資源,確保資源不會被浪費
在大多數(shù)SimpleTarget的實現(xiàn)當(dāng)中,如果需要資源的加載不受組件生命周期的影響,Glide.width(context)當(dāng)中的context是application context而不是fragment或者activity
另外,由于一些long running operations可能會導(dǎo)致內(nèi)存泄露,如果你打算使用一個這樣的操作,可以考慮使用一個靜態(tài)的內(nèi)部類而不是一個動態(tài)的內(nèi)部類。
2.ViewTarget
如果你想加載一張圖片到一個view當(dāng)中,但是又想改變或者監(jiān)聽Glide默認(rèn)的部分設(shè)置,就可以通過重寫ViewTarget或者他的子類來實現(xiàn)
如果你想Gidle加載圖片的時候可以自定義圖片的大小,或者想要設(shè)置一個自定義的顯示動畫,就可以通過ViewTarget來實現(xiàn),可以通過一個靜態(tài)的ViewTarget或者動態(tài)的內(nèi)部類來實現(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. } });
說明:
加載一張靜態(tài)的圖片或者一張GIF動態(tài)圖,可以在load后面加上asBitmap()/asGif()
.Load(url)會通過asXXX()替換ViewTarget當(dāng)中的GlideDrawable參數(shù),也可以通過實現(xiàn)LifecycleLisener,給target設(shè)置一個回調(diào)。
3.覆蓋默認(rèn)的相關(guān)設(shè)置
如果只是想使用Glide的默認(rèn)配置,可以使用Glide當(dāng)中ImageViewTargets的兩個子類:
GlideDrawableImageViewTarget 默認(rèn)的實現(xiàn),可以通過asGif()加載動態(tài)圖片
BitmapImageViewTarget 可以通過asBitmap()加載靜態(tài)圖片
如果想要使用Glide默認(rèn)實現(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大會發(fā)表了一篇文章,闡述了他們?nèi)绾问褂肕odelLoader接口去適配圖片的尺寸,見下面的連接:https://github.com/google/iosched/blob/master/doc/IMAGES.md
1、通過http/https下載圖片,可以通過繼承BaseGlideUtlLoader來實現(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()) ,可以實現(xiàn)是一個
ModelLoaderFactory然后使用Glide將它注冊到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()); } }
這樣你就可以跳過.using()了
Glide.with(yourFragment) .load(yourModel) .into(yourView);
九、集成庫
1.什么是集成庫
Glide包含一些小的、可選的集成庫,目前Glide集成庫當(dāng)中包含了訪問網(wǎng)絡(luò)操作的Volley和OkHttp
2.為什么要包含集成庫
這些集成庫,和Glide的ModelLoader系統(tǒng)允許開發(fā)者使用一致地框架去進行網(wǎng)絡(luò)相關(guān)的操作
3.如何將一個庫集成到Glide當(dāng)中,
將一個庫集成到Glide當(dāng)中需要兩步操作,
包含正確的dependency,
確保創(chuàng)建了該集成庫的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集成庫的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集成庫的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
十、在后臺線程當(dāng)中進行加載和緩存
為了保證Glide在后臺線程當(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的二進制文件下載到硬盤緩存當(dāng)中,以便在后續(xù)使用,
在UI線程當(dāng)中異步下載,在異步線程當(dāng)中則是使用width和height
在異步線程當(dāng)中同步調(diào)用下載,在同步線程當(dāng)中,
downloadOnly使用一個target作為參數(shù)
(1)在后臺線程當(dāng)中下載圖片,可以通過如下的方式:
FutureTarget<File> future = Glide.with(applicationContext) .load(yourUrl) .downloadOnly(500, 500); File cacheFile = future.get();
當(dāng)future返回的時候,image的二進制文件信息就存入了disk緩存了,值得注意的是downloadOnly API只是保證圖片個bytes數(shù)據(jù)在disk當(dāng)中是有效的。
(2)下載完畢之后如果想要進行顯示,可以通過如下方式進行調(diào)用:
Glide.with(yourFragment) .load(yourUrl) .diskCacheStrategy(DiskCacheStrategy.ALL) .into(yourView);
通過DiskCacheStrategy.ALL或者DiskCacheStrategy.SOURCE,可以保證程序會去讀取緩存文件
2. 如果想要在后臺線程當(dāng)中獲取某個URL對應(yīng)的Bitmap
不通過downloadOnly,可以使用into(),會返回一個FutureTarget對象,比如,想要得到一個URL對應(yīng)的500*500的centerCrop裁剪圖片,可以通過如下方式實現(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(),會阻塞主線
十一、轉(zhuǎn)換器
1.默認(rèn)的轉(zhuǎn)換器
Glide兩個默認(rèn)的轉(zhuǎn)換器,fitCenter和CenterCrop,其他的轉(zhuǎ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);
甚至可以在兩幅圖片進行類型轉(zhuǎ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)換器的尺寸
在上面使用過程當(dāng)中沒有設(shè)置尺寸值,那么轉(zhuǎn)換器轉(zhuǎn)換的圖片尺寸怎么確定呢,
Glide實際上已經(jīng)足夠智能根據(jù)view的尺寸來確定轉(zhuǎn)換圖片的尺寸了
如果需要自定義尺寸,而不是用view和target當(dāng)中的尺寸,那么可以使用override(int,int)設(shè)置相關(guān)的寬和高
4. Bitmap 再利用
為了減少垃圾收集,可以通過BitmapPool接口去釋放不需要的Bitmaps,當(dāng)然也可以對里面的bitmap進行再利用。
例如在一次轉(zhuǎn)換中,
從pool當(dāng)中得到一個bitmap
將Bitmap回設(shè)給Canvas
使用Matrix、Paint在Canvas上面繪制原始的Bitmap,或者通過一個Shader來轉(zhuǎn)換一個image
4.1 不要手動地去釋放一個轉(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; }
相關(guān)文章
Android Studio無法執(zhí)行Java類的main方法問題及解決方法
這篇文章主要介紹了Android Studio無法執(zhí)行Java main方法的問題,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-03Android Studio 3.0 gradle提示版本太老
這篇文章主要介紹了Android Studio 3.0 gradle提示版本太老的配置和解決方法。2017-11-11Android?RecyclerBarChart繪制使用教程
這篇文章主要為大家介紹了Android?RecyclerBarChart繪制使用教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12Android ViewPager實現(xiàn)左右滑動的實例
這篇文章主要介紹了Android ViewPager實現(xiàn)左右滑動的實例的相關(guān)資料,這里提供實現(xiàn)代碼實現(xiàn)左右滑動的功能,希望能幫助到大家,需要的朋友可以參考下2017-08-08FragmentTabHost FrameLayout實現(xiàn)底部導(dǎo)航欄
這篇文章主要為大家詳細(xì)介紹了FragmentTabHost和FrameLayout實現(xiàn)底部導(dǎo)航欄,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-03-03