# Glide的使用
>Glide是我使用最久,也是最喜歡的一款第三方圖片加載框架,以前只是使用,也沒有做系統性的總結,現在開始重新整理一遍這些優秀的第三方框架。
[Glide官方地址:](https://github.com/bumptech/glide)
## Glide的相關方法:
- load():加載資源,String/Uri/File/Integer/URL/byte[]/T,或者 loadFromMediaStore(Uri uri)
- placeholder(resourceId/drawable): 設置資源加載過程中的佔位Drawable。
- error():load失敗時顯示的Drawable。
- override() :調整圖片大小
- centerCrop():圖片裁剪,ImageView 可能會完全填充,但圖像可能不會完整顯示。
- fitCenter(): 圖像裁剪,圖像將會完全顯示,但可能不會填滿整個 ImageView。
- animate(): 指定加載動畫。
- crossFade()/crossFade(int duration):imageView改變時的動畫,version 3.6.1後默認開啟300毫秒
- dontAnimate():移除所有的動畫。
- transform():圖片轉換。
- bitmapTransform(): bitmap轉換,不可以和(centerCrop() 或 fitCenter())共用。
- priority(Priority priority):當前線程的優先級,Priority.IMMEDIATE,Priority.HIGH,Priority.NORMAL(default),Priority.LOW
- thumbnail(): 縮略圖.
- listener():異常監聽
- preload(int width, int height): 預加載resource到緩存中(單位為pixel)
- fallback(Drawable drawable):設置model為空時顯示的Drawable。
- using() :為單個的請求指定一個 model
- asGif():Gif 檢查,如果是圖片且加了判斷,則會顯示error佔位圖,否則會顯示圖片
- asBitmap():bitmap轉化,如果是gif,則會顯示第一幀
- .skipMemoryCache(true) 禁止緩存
- .diskCacheStrategy(DiskCacheStrategy.NONE)禁止磁盤緩存
>Glide 可以以load(File)的形式播放本地視頻,但是如果需要播放網絡視屏,則要用VideoView
---
# 緩存策略
一張圖片變化特別快的時候,應該禁止緩存
```
.skipMemoryCache(true)
```
即使關閉內存緩存,請求圖片將會仍然被存儲在設備的磁盤緩存中,如果一張圖片變化很快,仍需要禁止磁盤緩存
```
.diskCacheStrategy(DiskCacheStrategy.NONE)
```
Glide 緩存了原始圖像,全分辨率圖像和另外小版本的圖像,因此禁用磁盤緩存是用枚舉來控制的
```
DiskCacheStrategy.NONE //什麼都不緩存,就像剛討論的那樣
DiskCacheStrategy.SOURCE //僅僅只緩存原來的全分辨率的圖像。在我們上面的例子中,將會只有一個 1000x1000 像素的圖片
DiskCacheStrategy.RESULT //僅僅緩存最終的圖像,即,降低分辨率後的(或者是轉換後的)
DiskCacheStrategy.ALL //緩存所有版本的圖像(默認行為)
```
## 自定義緩存
磁盤緩存,用類DiskLruCacheWrapper來設置目錄
```
builder.setDiskCache(new DiskCache.Factory() {
@Override
public DiskCache build() {
// 自己的緩存目錄
File imgFile = new File(Environment.getExternalStorageDirectory()+"/Android/data/package-name");
return DiskLruCacheWrapper.get(imgFile,DiskCache.Factory.DEFAULT_DISK_CACHE_SIZE);
}
});
```
內存緩存,用類Memory Cache 來設置大小
```
MemorySizeCalculator calculator = new MemorySizeCalculator(context);
builder.setMemoryCache(new LruResourceCache(calculator.getMemoryCacheSize()));
```
## Bitmap Pool
重複使用及銷燬策略。設置方法:GlideBuilder.setBitmapPool()
默認採用的是LruBitmapPool,使用了LRU算法。
```
MemorySizeCalculator calculator = new MemorySizeCalculator(context);
int defaultBitmapPoolSize = calculator.getBitmapPoolSize();
int customBitmapPoolSize = (int) (1.2 * defaultBitmapPoolSize);
builder.setBitmapPool( new LruBitmapPool( customBitmapPoolSize );
```
## Bitmap Format
Bitmap Format用於設置全局缺省首選Bitmap規格,設置方法:GlideBuilder.setDecodeFormat()
默認採用RGB_565(比ARGB_8888節省一半的內存),但不支持透明度。
# 優先級
會發現優先級高的先 顯示出來,即使圖片比較大。
```
//優先加載
Glide
.with(context)
.load(heroImageUrl)
.priority(Priority.HIGH)
.into(imageViewHero);
//後加載
Glide
.with(context)
.load(itemImageUrl)
.priority(Priority.LOW)
.into(imageViewItem);
```
先顯示縮略圖,後顯示原圖
```
//用原圖的1/10作為縮略圖
Glide
.with(this)
.load("http://inthecheesefactory.com/uploads/source/nestedfragment/fragments.png")
.thumbnail(0.1f)
.into(iv_0);
//用其它圖片作為縮略圖
DrawableRequestBuilder
.with(this)
.load(R.drawable.news);
Glide.with(this)
.load("http://inthecheesefactory.com/uploads/source/nestedfragment/fragments.png")
.thumbnail(thumbnailRequest)
.into(iv_0);
```
# 圖片處理
裁剪、模糊、濾鏡等。可以使用 **wasabeef/glide-transformations** ,
實現Transformation 接口,或者使用抽象類BitmapTransformation,
通過transform()或bitmapTransform()來處理圖片
//圓形裁剪
Glide.with(this)
.load("http://inthecheesefactory.com/uploads/source/nestedfragment/fragments.png")
.bitmapTransform(new CropCircleTransformation(this))
.into(iv_0);
//圓角處理
Glide.with(this)
.load("http://inthecheesefactory.com/uploads/source/nestedfragment/fragments.png")
.bitmapTransform(new RoundedCornersTransformation(this,30,0, RoundedCornersTransformation.CornerType.ALL))
.into(iv_0);
//灰度處理
Glide.with(this)
.load("http://inthecheesefactory.com/uploads/source/nestedfragment/fragments.png")
.bitmapTransform(new GrayscaleTransformation(this))
.into(iv_0);
//模糊處理
Glide.with(this).load(R.drawable.demo)
.bitmapTransform(new BlurTransformation(context))
.into((ImageView) findViewById(R.id.image));
//其它變換...
## 自定義轉換
```
public class BlurTransformation extends BitmapTransformation {
public BlurTransformation(Context context) {
super( context );
}
@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
return null; // todo
}
@Override
public String getId() {
return null; // todo
}
}
```
其中getId() :描述了這個轉換的唯一標識符,將作為緩存系統的一部分
可以使用單種轉換和多種轉換,如多種轉換:
```
Glide
.with( context )
.load( eatFoodyImages[1] )
.transform( new GreyscaleTransformation( context ), new BlurTransformation( context ) )
.into( imageView2 );
```
# 回調 Target
SimpleTarget
target 泛型:Bitmap,GlideDrawable,GifDrawable
```
private SimpleTarget target = new SimpleTarget
@Override
public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {
// do something with the bitmap
// for demonstration purposes, let's just set it to an ImageView
imageView1.setImageBitmap( bitmap );
}
};
private void loadImageSimpleTarget() {
Glide
.with( context ) // could be an issue!
.load( eatFoodyImages[0] )
.asBitmap()
.into( target );
}
```
## Target生命週期
with( context ):關係到生命週期。如果請求需要在 activity 生命週期之外去做時,需要使用:
```
private void loadImageSimpleTargetApplicationContext() {
Glide
.with( context.getApplicationContext() ) // safer!
.load( eatFoodyImages[1]
.asBitmap()
.into( target2 );
}
```
## Target 指定尺寸
使用ImageView 作為參數給 .into()的時候,Glide 會用 ImageView 的大小去限制圖像的大小
但是target並沒有已知的大小,如果知道圖片大小則應指出,減少內存消耗。
```
private SimpleTarget target2 = new SimpleTarget
@Override
public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {
imageView2.setImageBitmap( bitmap );
}
};
private void loadImageSimpleTargetApplicationContext() {
Glide
.with( context.getApplicationContext() ) // safer!
.load( eatFoodyImages[1] )
.asBitmap()
.into( target2 );
}
```
## ViewTarget
常用於自定以控件中,比如自定義控件中組合了ImageView控件,如下
public class FutureStudioView extends FrameLayout {
ImageView iv;
TextView tv;
```
public void initialize(Context context) {
inflate( context, R.layout.custom_view_futurestudio, this );
iv = (ImageView) findViewById( R.id.custom_view_image );
tv = (TextView) findViewById( R.id.custom_view_text );
}
public FutureStudioView(Context context, AttributeSet attrs) {
super( context, attrs );
initialize( context );
}
public FutureStudioView(Context context, AttributeSet attrs, int defStyleAttr) {
super( context, attrs, defStyleAttr );
initialize( context );
}
public void setImage(Drawable drawable) {
iv = (ImageView) findViewById( R.id.custom_view_image );
iv.setImageDrawable( drawable );
}
}
```
使用如下方法給自定義控件中的ImageView設置圖片
```
private void loadImageViewTarget() {
FutureStudioView customView = (FutureStudioView) findViewById( R.id.custom_view );
//傳遞了參數 customView
viewTarget = new ViewTarget
@Override
public void onResourceReady(GlideDrawable resource, GlideAnimation super GlideDrawable> glideAnimation) {
//調用了FutureStudioView的setImage方法
this.view.setImage( resource.getCurrent() );
}
};
Glide
.with( context.getApplicationContext() ) // safer!
.load( eatFoodyImages[2] )
.into( viewTarget );
}
```
## NotificationTarget
用於加載圖片到通知欄和應用小部件中的
# 動畫
animate() :可以加載資源文件animate.xml文件
或者 屬性動畫:
- ViewPropertyAnimation
- ViewAnimation
- NoAnimation
- DrawableCrossFadeViewAnimation
```
ViewPropertyAnimation.Animator animationObject = new ViewPropertyAnimation.Animator() {
@Override
public void animate(View view) {
// if it's a custom view class, cast it here
// then find subviews and do the animations
// here, we just use the entire view for the fade animation
view.setAlpha( 0f );
ObjectAnimator fadeAnim = ObjectAnimator.ofFloat( view, "alpha", 0f, 1f );
fadeAnim.setDuration( 2500 );
fadeAnim.start();
}
};
Glide
.with( context )
.load( eatFoodyImages[1] )
.animate( animationObject )
.into( imageView2 );
```
# Glide module
Glide module 是一個抽象方法,全局改變 Glide 行為的一個方式。
前面單策略的定義中都用到了GlideBuilder類
如果你需要訪問 GlideBuilder,你需要去實現一個 GlideModule 接口的公共類
```
public class FileGlideModule implements GlideModule{
@Override
public void applyOptions(final Context context, GlideBuilder builder) {
//builder 內的所有方法你都可以設置。
// builder.setDiskCache(new InternalCacheDiskCacheFactory(context));
builder.setDiskCache(new ExternalCacheDiskCacheFactory(context));
/* builder.setDiskCache(new DiskCache.Factory() {
@Override
public DiskCache build() {
File imgFile = new File(Environment.getExternalStorageDirectory()+"/Android/data/com.leying365");
return DiskLruCacheWrapper.get(imgFile,DiskCache.Factory.DEFAULT_DISK_CACHE_SIZE);
}
});*/
MemorySizeCalculator calculator = new MemorySizeCalculator(context);
builder.setMemoryCache(new LruResourceCache(calculator.getMemoryCacheSize()));
builder.setBitmapPool(new LruBitmapPool(calculator.getBitmapPoolSize()));
builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
}
@Override
public void registerComponents(Context context, Glide glide) {
}
}
```
最終通過
常用方法:
- setMemoryCache(MemoryCache memoryCache)
- setBitmapPool(BitmapPool bitmapPool)
- setDiskCache(DiskCache.Factory diskCacheFactory)
- setDiskCacheService(ExecutorService service)
- setResizeService(ExecutorService service)
- setDecodeFormat(DecodeFormat decodeFormat)
# 網絡庫
Glide 使用ModeLoader 接口來 集成網絡庫,Glide提供了兩種網絡庫 的實現,分別為OkHttp 和 Volley。
在build.gradle中添加如下依賴,glide會默認使用OKhttp來做所有的網絡連接
```
dependencies {
// your other dependencies
// ...
// Glide
compile 'com.github.bumptech.glide:glide:3.7.0'
// Glide's OkHttp Integration
compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.2.0'
}
```
上面會將必要的GlideModule 到你的 Android.Manifest中。
## 緩存與失效機制
Glide 通過 url、viewwidth、viewheight、屏幕的分辨率等以一種散列算法生成一個獨有、安全的文件名作為key保存到disk上.因為其是通過一個散列算法來實現的,因此很難定位文件的緩存,幸好Glide提供了signature()方法允許將一個附加的數據加入到緩存key當中,可以用來保證緩存的及時性.
系統默認實現了MediaStoreSignature,StringSignature.
```
Glide.with(fragment)
.load(mediaStoreUri)
.signature(new MediaStoreSignature(mimeType, dateModified, orientation))
.into(view);
```
當然也可以自己來實現Signature
```
public class MSignature implements Key {
@Override
public boolean equals(Object o) {
//...
}
@Override
public int hashCode() {
//...
}
@Override
public void updateDiskCacheKey(MessageDigest messageDigest) {
messageDigest.update(ByteBuffer.allocate(Integer.SIZE)
.putInt(signature).array());
}
}
```
極端情況,不緩存可以用diskCacheStrategy(DiskCacheStrategy.NONE.)來實現
# 圖片下載
Glide除了提供into方法來加載圖片外,也提供了downloadOnly方法來實現圖片下載.
```
FutureTarget
.load(yourUrl)
.downloadOnly(500, 500);
File cacheFile = future.get();
```
下載之後可以通過如下方式來加載圖片
```
Glide.with(yourFragment)
.load(yourUrl)
//DiskCacheStrategy.ALL或者DiskCacheStrategy.SOURCE可以保證程序會先去讀緩存文件
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(yourView);
```
如果想獲取一張圖片的Bitmap,可以使用如下方式
//此方法需要try/catch處理,並且最好在子線程中,否則會阻塞主線程
```
Bitmap myBitmap = Glide.with(applicationContext)
.load(yourUrl)
.asBitmap()
.centerCrop()
//設置大小
.into(500, 500)
.get()
```
# 圖片模糊處理
使用Glide加載圖片,將模糊圖片設置為背景,代碼如下:
```
Glide.with(this).load(mImageCover)
.asBitmap()
.into(new SimpleTarget
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public void onResourceReady(Bitmap resource, GlideAnimation super Bitmap> glideAnimation) {
blur(resource,ivCover,24);
ivCover.setImageBitmap(resource);
}
});
```
//blur方法,將圖片模糊處理添加到背景中
```
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
private void blur(Bitmap bkg, View view, float radius) {
/*view.getMeasuredWidth(),
view.getMeasuredHeight(),*/
Bitmap overlay = Bitmap.createBitmap(
bkg.getWidth(),
bkg.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(overlay);
canvas.drawBitmap(bkg, -view.getLeft(),
-view.getTop(), null);
RenderScript rs = RenderScript.create(this);
Allocation overlayAlloc = Allocation.createFromBitmap(
rs, overlay);
ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(
rs, overlayAlloc.getElement());
blur.setInput(overlayAlloc);
blur.setRadius(radius);
blur.forEach(overlayAlloc);
overlayAlloc.copyTo(overlay);
view.setBackground(new BitmapDrawable(
getResources(), overlay));
rs.destroy();
}
```
//圖片模糊類,使用方法如下:
```
/*BlurBuilder builder = new BlurBuilder();
Bitmap bitmap = builder.blur(this, bmp);
image.setImageBitmap(bitmap);*/
public class BlurBuilder {
private static final float BITMAP_SCALE = 0.2f;
private static final float BLUR_RADIUS = 8.75f;
public static Bitmap blur(Context context, Bitmap image) {
int width = Math.round(image.getWidth() * BITMAP_SCALE);
int height = Math.round(image.getHeight() * BITMAP_SCALE);
Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false);
Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);
RenderScript rs = RenderScript.create(context);
ScriptIntrinsicBlur theIntrinsic = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
theIntrinsic.setRadius(BLUR_RADIUS);
theIntrinsic.setInput(tmpIn);
theIntrinsic.forEach(tmpOut);
tmpOut.copyTo(outputBitmap);
return outputBitmap;
}
}
```
裁剪、模糊、濾鏡等。可以使用 **wasabeef/glide-transformations**
閱讀更多 aserbao 的文章