android學習之路(一)--Glide學習


一、Glide3.0新特性
1.動態的GIF圖片加載:

Glide.with(context).load(...).asBitmap() //顯示gif靜態圖片
Glide.with(context).load(...).asGif() //顯示gif動態圖片

2.本地視頻快照:
   除了解碼gif,Glide現在還可以從視頻解碼設備,就像gif,同樣Glide.with(…).load(…)功能調用將為任何本地視頻Android可以解碼工作。
3.對縮略圖的支持:

Glide.with(yourFragment).load(yourUrl).thumbnail(0.1f).into(yourView)
//加載yourView1/10尺寸的縮略圖,然后加載全圖

4.生命周期集成
      現在請求會在onStop的時候自動暫停,然后在onStart的時候重新啟動,gif的動畫也會在onStop的時候停止,以免在后台消耗電量, 此外,當設備的鏈接狀態發生改變的時候,所有失敗的請求會自動重啟,保證數據的正確性。
5.轉碼
      除了解碼資源以外,Glide的.toBytes()和.transcode()方法允許在后台獲取、解碼和轉換一個圖片,你可以將一張圖片轉換成更多有用的圖片格式,比如,上傳一張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.
}
});

5.動畫:3.x加入了cross fades和View的屬性動畫的支持,比如

(.animate(ViewPropertyAnimation.Animator)),

6. 網絡模塊可以選擇OkHttp或者Volley的支持: You can now choose to use either OkHttp, or Volley, or Glide’s HttpUrlConnection default as your network stack.
      Volley和OkHttp可以在gradle文件當中添加依賴,注冊相應的ModelLoaderFactory
二、圖片的緩存和緩存的時效機制
1.圖片緩存的鍵值
      圖片緩存的鍵值主要用於DiskCacheStrategy.RESULT,Glide當中的鍵值主要包含三個部分:
      1.1 通過DataFetcher.getId()方法返回的String數據作為鍵值。一般的DataFetchers會簡單返回數據模型data model的toString()結果,如果是URL/File會返回相應的路徑
      1.2 圖片的尺寸,主要是通過override(width,height)或者通過Target’s getSize()方法確定的尺寸信息
      1.3 包含一個可選的簽名所有的這些東西會通過一種散列算法生成一個獨有、安全的文件名,通過此文件名將圖片緩存在disk中

2.緩存失效
      因為Glide當中圖片緩存key的生成是通過一個散列算法來實現的,所以很難手動去確定哪些文件可以從緩存當中進行刪除,通常的做法就是當內容(url,file path)改變的時候,改變相應的標識符就可以了,通常標識符的改變可能很困難,Glide當中也提供了signature()方法,可以將一個附加的數據加入到緩存key當中,
—-多媒體存儲數據,可以使用MediaStoreSignature類作為標識符,會將文件的修改時間、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);

也可以自定義標識符來,

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

      不緩存可以通過diskCacheStrategy(DiskCacheStrategy.NONE.)實現
三、配置–GlideModules
      可以通過GlideModule接口懶配置Glide的配置文件,並且像ModelLoaders一樣注冊相關組件。
      1.包含一個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.
}
}

第二步、然后將上面的實現了加入到proguard.cfg當中:

-keepnames class * com.mypackage.MyGlideModule

第三步、在AndroidManifest.xml文件中祖冊,以便Glide能夠找到你的Module

<meta-data
android:name="com.bumptech.glide.samples.flickr.FlickrGlideModule"
android:value="GlideModule" />

四、Library項目
      一個Library項目可能會定義一個或者多個GlideModules,如果一個Library項目添加一個Module到他的manifest當中,依賴於此Library的應用就會自動加載依賴庫當中的Module。當然,如果manifest的合並不正確,那么Library里面Module就必須手動地在應用當中添加進去

五、GlideModules沖突
      雖然Glide允許一個應用當中存在多個GlideModules,Glide並不會按照一個特殊的順序去調用已注冊的GlideModules,如果一個應用的多個依賴工程當中有多個相同的Modules,就有可能會產生沖突。
      如果一個沖突是不可避免的,應用應該默認去定義一個自己的Module,用來手動地處理這個沖突,在進行Manifest合並的時候,可以用下面的標簽排除沖突的module

<meta-data android:name=”com.mypackage.MyGlideModule” tools:node=”remove”/>

六、通過GlideBuilder配置全局配置文件
      Glide允許開發者配置一些不同的全局操作應用於所有的請求,這個部分可以通過GlideModule→applyOptions方法里面的GlideBuilder參數實現
1.DiskCache
      1.1開發者能夠通過GlideBuilder的setDiskCache(DiskCache.Factory df)方法設置存儲的位置和大小,也可以通過傳入DiskCacheAdapter或者自定義一個DiskCache來完全禁用緩存,硬盤緩存是在一個后台鮮城當中,通過一個DiskCache.Factory接口進行緩存的。
      Glide默認是用InternalCacheDiskCacheFactory類來創建硬盤緩存的,這個類會在應用的內部緩存目錄下面創建一個最大容量250MB的緩存文件夾,使用這個緩存目錄而不用sd卡,意味着除了本應用之外,其他應用是不能訪問緩存的圖片文件的。

1.2.設置disk緩存的大小 : InternalCacheDiskCacheFactory

new GlideBuilder(context)
.setDiskCache(new InternalCacheDiskCacheFactory(context, yourSizeInBytes));

1.3.設置緩存的路徑
      可以通過實現DiskCache.Factory,然后使用DiskLruCacheWrapper創建一個新的緩存目錄,比如,可以通過如下方式在外存當中創建緩存目錄:

new GlideBuilder(context)
.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.內存當中的緩存和POOLS
      GlideBuilder當中,允許開發者去設置內存當中圖片緩存區的大小,主要涉及到的類包括MemoryCache和BitmapPool
2.1 大小的設置
      默認內存緩存的大小是用過MemorySizeCalculator來實現的,這個類會根據設備屏幕的大小,計算出一個合適的size,開發者可以獲取到相關的默認設置信息:

MemorySizeCalculator calculator = new MemorySizeCalculator(context);
int defaultMemoryCacheSize = calculator.getMemoryCacheSize();
int defaultBitmapPoolSize = calculator.getBitmapPoolSize();
如果在應用當中想要調整內存緩存的大小,開發者可以通過如下方式:
Glide.get(context).setMemoryCategory(MemoryCategory.HIGH);

2.2 Memory Cache
      Glide內存緩存的目的是減少I/O,提高效率
      可以通過GlideBuidler的setMemoryCache(MemoryCache memoryCache)去設置緩存的大小,開發者可以通過LruResourceCache去設置緩存區的大小

new GlideBuilder(context)
.setMemoryCache(new LruResourceCache(yourSizeInBytes));

2.3 Bitmap Pool
      可以通過GlideBuilder的setBitmapPool()方法設置池子的大小,LruBitmapPool是Glide的默認實現,使用如下:

new GlideBuilder(context)
.setBitmapPool(new LruBitmapPool(sizeInBytes));

3.圖片格式
      GlideBuilder允許開發者設置一個全局的默認圖片格式,
在默認情況下,Glide使用RGB_565格式加載圖片,如果想要使用高質量的圖片,可以通過如下方式設置系統的圖片格式:

new GlideBuilder(context)
.setDecodeFormat(DecodeFormat.ALWAYS_ARGB_8888);

七、自定義顯示控件
      除了可以將圖片、視頻快照和GIFS顯示在View上面之外,開發者也可以在自定義的Target上面顯示這些媒體文件
1.SimpleTarget
重點內容如果你想簡單地加載一個Bitmap,你可以通過以下簡單的方式而不是直接地顯示給用戶,可能是顯示一個notification,或者上傳一個頭像,Glide都能很好地實現
**重點內容**SimpleTarget提供了對Target的簡單實現,並且讓你專注於對加載結果的處理
重點內容為了使用SimpleTarget,開發者需要提供一個寬和高的像素值,用來加載你的資源文件,並且你需要去實現

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當中,當fragment或者activity失去焦點或者distroyed的時候,Glide會自動停止加載相關資源,確保資源不會被浪費
      在大多數SimpleTarget的實現當中,如果需要資源的加載不受組件生命周期的影響,Glide.width(context)當中的context是application context而不是fragment或者activity
      另外,由於一些long running operations可能會導致內存泄露,如果你打算使用一個這樣的操作,可以考慮使用一個靜態的內部類而不是一個動態的內部類。

2.ViewTarget
      如果你想加載一張圖片到一個view當中,但是又想改變或者監聽Glide默認的部分設置,就可以通過重寫ViewTarget或者他的子類來實現
      如果你想Gidle加載圖片的時候可以自定義圖片的大小,或者想要設置一個自定義的顯示動畫,就可以通過ViewTarget來實現,可以通過一個靜態的ViewTarget或者動態的內部類來實現相關的功能

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

說明:如果想要加載一張靜態的圖片或者一張GIF動態圖,可以在load后面加上asBitmap()/asGif(),
.Load(url)會通過asXXX()替換ViewTarget當中的GlideDrawable,也可以通過實現LifecycleLisener,給target設置一個回調。

3.覆蓋默認的相關設置
      如果只是想使用Glide的默認配置,可以使用Glide當中ImageViewTargets的兩個默認API:
      GlideDrawableImageViewTarget 默認的實現,可以通過asGif()加載動態圖片
      BitmapImageViewTarget 可以通過asBitmap()加載靜態圖片
      如果想要使用Glide默認實現,可以在他們的子類方法當中使用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接口為開發者提供了裝在圖片的view的尺寸,並且允許開發者使用這些尺寸信息去選擇合適的URL去下載圖片。選用適當的尺寸可以節省寬帶和設備的空間開銷,提高app的性能
      2014年googleI/o大會發表了一篇文章,闡述了他們如何使用ModelLoader接口去適配圖片的尺寸,見下面的連接:https://github.com/google/iosched/blob/master/doc/IMAGES.md
      通過http/https下載圖片,可以通過繼承BaseGlideUtlLoader來實現:

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

      接下來你就可以使用你自定義的ModelLoader去加載圖片了,

Glide.with(yourFragment)
.using(new MyUrlLoader())
.load(yourModel)
.into(yourView);

      如果你想避免每次加載圖片都要使用.using(new MyUrlLoader()) ,可以實現是一個
ModelLoaderFactory然后使用Glide將它注冊到GlideModule當中

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集成庫當中包含了訪問網絡操作的Volley和OkHttp
2.為什么要包含集成庫
      這些集成庫,和Glide的ModelLoader系統允許開發者使用一致地框架去進行網絡相關的操作
3.如何將一個庫集成到Glide當中,
      將一個庫集成到Glide當中需要兩步操作,第一、需要包含正確的dependency,第二 確保包含了該集成庫的GlideModule,比如,將Volley集成到Glide當中,
第一步、添加依賴

dependencies {
compile 'com.github.bumptech.glide:volley-integration:1.2.2'
compile 'com.mcxiaoke.volley:library:1.0.5'
}

第二步、創建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當中
第一步、添加依賴

dependencies {
compile 'com.github.bumptech.glide:okhttp-integration:1.2.2'
compile 'com.squareup.okhttp:okhttp:2.0.0'
}

第二步、

<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

十、在后台線程當中進行加載和緩存
      為了保證Glide在后台線程當中加載資源文件更加容易,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()允許開發者將Image的二進制文件下載到硬盤緩存當中,以便在后續使用,可以在UI線程當中異步下載,也可以在異步線程當中同步調用下載,值得注意的是,如果在同步線程當中,
downloadOnly使用一個target作為參數,而在異步線程當中則是使用width和height
      在后台線程當中下載圖片,可以通過如下的方式:

FutureTarget<File> future = Glide.with(applicationContext)
.load(yourUrl)
.downloadOnly(500, 500);
File cacheFile = future.get();

      當future返回的時候,image的二進制文件信息就存入了disk緩存了,值得注意的是downloadOnly API只是保證圖片個bytes數據在disk當中是有效的。
      下載完畢之后如果想要進行顯示,可以通過如下方式進行調用:

Glide.with(yourFragment)
.load(yourUrl)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(yourView);

      通過DiskCacheStrategy.ALL或者DiskCacheStrategy.SOURCE,可以保證程序會去讀取緩存文件
2. 如果想要在后台線程當中獲取某個URL對應的Bitmap,而不通過downloadOnly,可以使用into(),會返回一個FutureTarget對象,比如,想要得到一個URL對應的500*500的centerCrop裁剪圖片,可以通過如下方式實現:

Bitmap myBitmap = Glide.with(applicationContext)
.load(yourUrl)
.asBitmap()
.centerCrop()
.into(500, 500)
.get()

//值得注意的是:上面的調用只能在異步線程當中,如果在main Thread當中調用.get(),會阻塞主線

十一、轉換器
1.默認的轉換器
      Glide兩個默認的轉換器,fitCenter和CenterCrop,其他的轉換器詳見https://github.com/wasabeef/glide-transformations,可以將圖片轉為各種形狀,例如圓形,圓角型等等
用法:

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

      甚至可以在兩幅圖片進行類型轉換的時候進行transformed

Glide.with(yourFragment)
.load(yourUrl)
.asBitmap()
.toBytes()
.centerCrop()
.into(new SimpleTarget<byte[]>(...) { ... });

2.自定義轉換器
方法:
第一步、編寫轉換器類
繼承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方法鏈當中用.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.自定義轉換器的尺寸
      在上面使用過程當中沒有設置尺寸值,那么轉換器轉換的圖片尺寸怎么確定呢,Glide實際上已經足夠智能根據view的尺寸來確定轉換圖片的尺寸了,如果需要自定義尺寸,而不是用view和target當中的尺寸,那么可以使用override(int,int)設置相關的寬和高
4. Bitmap 再利用
      為了減少垃圾收集,可以通過BitmapPool接口去釋放不需要的Bitmaps,當然也可以對里面的bitmap進行再利用,典型地,在一次轉換中,可以從pool當中得到一個bitmap,將Bitmap回設給Canvas
然后使用Matrix、Paint在Canvas上面繪制原始的Bitmap,或者通過一個Shader來轉換一個image
4.1 不要手動地去釋放一個轉換的bitmap資源,也不要將transform()之后的Bitmap重新放置到BitmapPool當中去

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

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com