在Android設(shè)備上,加載網(wǎng)絡(luò)圖片一直是一個(gè)頭疼的問(wèn)題,因?yàn)锳ndroid設(shè)備種類繁多(當(dāng)然最主要的是配置),處理的稍不周到輕則應(yīng)用卡頓,嚴(yán)重者就會(huì)出現(xiàn)OOM的,導(dǎo)致程序掛掉?,F(xiàn)如今網(wǎng)絡(luò)上有很多圖片庫(kù),如 Universal-Image-Loader,Picasso,Fresco,Glide等等。相信列舉出的這幾個(gè)庫(kù)大家都不陌生,這也是目前最火的圖片庫(kù)了。由于個(gè)人的喜好原因(主要是別人介紹說(shuō)Glide庫(kù)比較NB),所以就開(kāi)始研究學(xué)習(xí)Glide。
Glide庫(kù)和Picasso庫(kù)有極大的相似性,編碼風(fēng)格也幾近相同,不過(guò)Glide缺有著更為強(qiáng)大的功能。它在緩存處理方面有著很大的優(yōu)勢(shì)并且支持加載Gif動(dòng)畫(huà)以及本地Video。這個(gè)庫(kù)在谷歌開(kāi)源庫(kù)中也有應(yīng)用。如此好東西,心動(dòng)不如行動(dòng),現(xiàn)在開(kāi)始我們的學(xué)習(xí)之旅吧。
源碼【傳送門(mén)】
配置
使用Glide的第一步是現(xiàn)在我們的builde.gradle
dependencies {
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'com.android.support:support-v4:19.1.0'
}
配置gradle文件后,我們就可以使用Glide了。上代碼
Glide.with(context).load("http://img2./2014/f6/173/d/51.jpg").into(imageView);
看著很簡(jiǎn)單吧,一句話就可以實(shí)現(xiàn)圖片下載和展示。我們看到Glide使用建造者模式加載圖片。
RequestManager with(Context context)
RequestManager with(Activity activity)
RequestManager with(FragmentActivity activity)
我們看到with()可接受三種參數(shù),這也是Glide的亮點(diǎn),它能根據(jù)傳入?yún)?shù)Activity/Fragment的生命周期保持一致,去暫停和執(zhí)行圖片加載,這也節(jié)省了不必要的流量浪費(fèi)。
加載圖片方式
DrawableTypeRequest<String> load(String string)
DrawableTypeRequest<Uri> load(Uri uri)
DrawableTypeRequest<File> load(File file)
DrawableTypeRequest<Integer> load(Integer resourceId)
DrawableTypeRequest<URL> load(URL url)
String參數(shù)加載
Glide.with(this).load("http://img2./2014/f6/173/d/51.jpg").into(imageView);
資源文件加載
int resourceId=R.mipmap.image;
Glide.with(context).load(resourceId).into(imageView);
本地文件加載
File file = new File(Environment.getExternalStorageDirectory() + File.separator + "image", "image.jpg");
Glide.with(this).load(file).into(imageView);
Uri加載
File file = new File(Environment.getExternalStorageDirectory() + File.separator + "image", "image.jpg");
Uri uri = Uri.fromFile(file);
Glide.with(this).load(uri).into(imageView);//uri加載方式
URL方式
該方式在源碼中已經(jīng)標(biāo)記@Deprecated
try {
url=new URL("http://img2./2014/f6/173/d/51.jpg");
} catch (MalformedURLException e) {
e.printStackTrace();
}
Glide.with(this).load(url).into(imageView);//URL加載方式
設(shè)置占位圖片
在上面的處理中,我們之間將加載成功的圖片展示到ImageView,這樣會(huì)不會(huì)看起來(lái)很突兀?是的,Glide為我們提供了設(shè)置占位符,他可以讓我們知道圖片是否加載成功,等
placeholder
我們都知道,圖片加載是不確定的,加載成功需要的時(shí)間也是不確定的,而在加載這段時(shí)間,我們可以通過(guò)placeholder設(shè)置給ImageView一個(gè)占位符,圖片上可以提示正在加載中之類的,當(dāng)然可以任何你要的效果,
Glide.with(context).load("http://img2./2014/f6/173/d/55.jpg").placeholder(R.mipmap.place).into(imageView);
error
當(dāng)然除了加載成功前我們?cè)O(shè)置了占位符,那么如果加載錯(cuò)誤(網(wǎng)絡(luò)原因及url非法原因等導(dǎo)致圖片沒(méi)有加載成功),我們填充一個(gè)圖片到ImageView提示用戶當(dāng)前圖片加載失敗。
Glide.with(context).load("http://img2./2014/f6/173/d/55.jpg").error(R.mipmap.error).into(imageView);
此時(shí)你可能想如何知道圖片加載失敗的具體原因呢?Glide為我們提供了listener()方法,接收RequestListener對(duì)象
//設(shè)置錯(cuò)誤監(jiān)聽(tīng)
RequestListener<String,GlideDrawable> errorListener=new RequestListener<String, GlideDrawable>() {
@Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
Log.e("onException",e.toString()+" model:"+model+" isFirstResource: "+isFirstResource);
imageView.setImageResource(R.mipmap.ic_launcher);
return false;
}
@Override
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
Log.e("onResourceReady","isFromMemoryCache:"+isFromMemoryCache+" model:"+model+" isFirstResource: "+isFirstResource);
return false;
}
} ;
我們看到有兩個(gè)回調(diào)方法,通過(guò)onException是圖片加載異?;卣{(diào),onResourceReady是加載成功的回調(diào)。我們可以測(cè)試不同情況打印的日志
onResourceReady: isFromMemoryCache:false model:http://img2./2014/f6/173/d/51.jpg isFirstResource: true
onResourceReady: isFromMemoryCache:true model:http://img2./2014/f6/173/d/51.jpg isFirstResource: true
onException: java.io.IOException: Request failed 404: Not Found model:http://img2./2014/f6/173/d/511.jpg isFirstResource: true
onException: java.io.FileNotFoundException: No such file or directory model:www.baidu.com isFirstResource: true
onException: java.net.UnknownHostException: Unable to resolve host "img2.": No address associated with hostname model:http://img2./2014/f6/173/d/51.jpg isFirstResource: true
通過(guò)日志我們很容易看出異常的原因,因此,我們可以針對(duì)不同的操作情形,書(shū)寫(xiě)自己的處理給用戶反饋。
crossFade
通過(guò)上面的分析,我們實(shí)現(xiàn)了占位圖填充ImageView,但是我們依然發(fā)現(xiàn)其中有些不足,因?yàn)閳D片的轉(zhuǎn)換并沒(méi)有實(shí)現(xiàn)平滑過(guò)渡效果,實(shí)際新api已經(jīng)默認(rèn)實(shí)現(xiàn)一個(gè)漸入漸出的動(dòng)畫(huà)效果,默認(rèn)是300ms.
Glide.with(context).load("http://img2./2014/f6/173/d/51.jpg").error(R.mipmap.error).placeholder(R.mipmap.place).crossFade().into(imageView);
crossFade()還可以接收一個(gè)int型的參數(shù),用它來(lái)指定動(dòng)畫(huà)執(zhí)行的時(shí)間,例如我們?cè)O(shè)置動(dòng)畫(huà)執(zhí)行的時(shí)間是2s
Glide.with(context).load("http://img2./2014/f6/173/d/51.jpg").error(R.mipmap.error).placeholder(R.mipmap.place).crossFade(2000).into(imageView);
既然我們能添加一個(gè)漸入漸出的動(dòng)畫(huà)效果,那么如果想直接顯示圖片而沒(méi)有任何淡入淡出效果,該作何處理,我們可以使用dontAnimate()方法,這是直接顯示你的圖片,而不是淡入顯示到 ImageView。
圖片調(diào)整
Glide加載圖片大小是自動(dòng)調(diào)整的,他根據(jù)ImageView的尺寸自動(dòng)調(diào)整加載的圖片大小,并且緩存的時(shí)候也是按圖片大小緩存,每種尺寸都會(huì)保留一份緩存,如果圖片不會(huì)自動(dòng)適配到 ImageView,調(diào)用 override(horizontalSize, verticalSize) 。這將在圖片顯示到 ImageView之前重新改變圖片大小
//Glide.with(context).load("http://img2./2014/f6/173/d/51.jpg").dontAnimate().override(400,600).fitCenter().into(imageView);
注意override接收的參數(shù)是像素(px)
縮放
對(duì)于任何圖像操作,調(diào)整大小可能讓圖片失真。但是我們要盡可能的避免發(fā)生這種情況發(fā)生。Glide 提供了兩個(gè)圖形裝換的操作提供了兩個(gè)標(biāo)準(zhǔn)選項(xiàng):centerCrop 和 fitCenter
- centerCrop
這個(gè)方法是裁剪圖片,當(dāng)圖片比ImageView大的時(shí)候,他把把超過(guò)ImageView的部分裁剪掉,盡可能的讓ImageView 完全填充,但圖像可能不會(huì)全部顯示
Glide.with(context).load("http://img2./2014/f6/173/d/51.jpg").centerCrop().into(imageView);
- fitCenter
它會(huì)自適應(yīng)ImageView的大小,并且會(huì)完整的顯示圖片在ImageView中,但是ImageView可能不會(huì)完全填充
加載Gif
加載Gif動(dòng)畫(huà)也是Glide的一大優(yōu)勢(shì),它很簡(jiǎn)單的就能實(shí)現(xiàn)Gif的加載與顯示
加載Gif文件
Glide.with(context).load("http://img1./2015/w4/17/d/64.gif").into(imageView);
是不是很簡(jiǎn)單,依然是一句話就實(shí)現(xiàn)顯示網(wǎng)絡(luò)上Gif功能。Glide還提供了Gif相關(guān)操作的兩個(gè)方法。如果我們想將Gif顯示成圖片的第一幀只需要使用asBitmap()方法即可。如果我們有這個(gè)需求,就是嚴(yán)格顯示成Gif,那么當(dāng)傳入了一個(gè)非Gif 的url時(shí),我們當(dāng)做錯(cuò)誤處理。此時(shí)我們可以使用asGif()方法
Glide.with(context).load("http://img2./2014/f6/173/d/51.jpg").asGif().error(R.mipmap.error).placeholder(R.mipmap.place).into(imageView);
Glide 將會(huì)把這個(gè) load 當(dāng)成失敗處理。這樣做的的好處是,.error() 回調(diào)被調(diào)用并且錯(cuò)誤占位符被顯示,如果url是Gif,那么會(huì)沒(méi)什么變化,這樣就檢查了load參數(shù)是否為Gif.
Glide網(wǎng)絡(luò)加載方式
Glide內(nèi)部默認(rèn)是通過(guò)HttpURLConnection網(wǎng)絡(luò)方式加載圖片的,并且支持OkHttp,Volley
集成OkHttp
在gradle文件加入下面代碼
//自動(dòng)集成okhttp
compile 'com.github.bumptech.glide:okhttp-integration:1.4.0@aar'
compile 'com.squareup.okhttp:okhttp:2.2.0'
集成Volley
//自動(dòng)集成volley
compile 'com.github.bumptech.glide:volley-integration:1.4.0@aar'
compile 'com.mcxiaoke.volley:library:1.0.19'
Gradle 會(huì)自動(dòng)合并必要的 GlideModule 到Android.Manifest。Glide 會(huì)認(rèn)可在 manifest 中的存在,然后使用 所集成的網(wǎng)絡(luò)連接。
自定義動(dòng)畫(huà)
在前面我們已經(jīng)提到過(guò)Glide提供了一個(gè)漸入漸出的動(dòng)畫(huà)效果,當(dāng)然該動(dòng)畫(huà)不是那么酷炫,而且有時(shí)并不能達(dá)到我們想要的效果,不過(guò)Glide給我們提供了animate()方法,我們可以通過(guò)此方法實(shí)現(xiàn)我們自定義的動(dòng)畫(huà)效果。
animate(int animationId)
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas./apk/res/android"
android:fillAfter="false"
android:duration="3000">
<scale
android:duration="@android:integer/config_longAnimTime"
android:fromXScale="0.1"
android:fromYScale="0.1"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1"
android:toYScale="1"/>
<rotate
android:fromDegrees="0"
android:toDegrees="90"
android:pivotX="50%"
android:pivotY="50%"
/>
</set>
上面我們實(shí)現(xiàn)了一個(gè)圖片從小變大并且有一個(gè)旋轉(zhuǎn)效果的動(dòng)畫(huà),當(dāng)然你可以在此文件書(shū)寫(xiě)任何你想要實(shí)現(xiàn)的動(dòng)畫(huà)。
Glide.with(context).load("http://img2./2014/f6/173/d/51.jpg").animate(R.anim.anim).into(imageView);
java文件設(shè)置動(dòng)畫(huà)
我們也可以通過(guò)Animator實(shí)現(xiàn)動(dòng)畫(huà),如下
//java文件設(shè)置動(dòng)畫(huà)
ViewPropertyAnimation.Animator animator=new ViewPropertyAnimation.Animator() {
@Override
public void animate(View view) {
view.setAlpha(0f);
ObjectAnimator fadeAnim = ObjectAnimator.ofFloat( view, "alpha", 0f, 1f );
fadeAnim.setDuration( 2500 );
fadeAnim.start();
}
};
Glide.with(context).load("http://img2./2014/f6/173/d/51.jpg").animate(animator).into(imageView);
Target
Glide不但可以把圖片、視頻劇照、GIF動(dòng)畫(huà)加載到View,還可以加載到自定義的Target實(shí)現(xiàn)中。Target就是使用Glide獲取到資源之后資源作用的目標(biāo),我們通常是用Glide加載完資源后顯示到ImageView中,這個(gè)ImageView就是目標(biāo).
SimpleTarget
//SimpleTarget
SimpleTarget target = new SimpleTarget<Drawable>(){
@Override
public void onResourceReady(Drawable resource, GlideAnimation<? super Drawable> glideAnimation) {
textView.setBackground(resource);
}
};
Glide.with(context)
.load("http://img2./2014/f6/173/d/51.jpg")
.animate(animator)
.into(target);
上面的代碼我們將TextView作為T(mén)arget,將加載的圖片設(shè)為背景,對(duì)于SimpleTarget是接收的泛型數(shù)據(jù),如果我們需要Bitmap對(duì)象,我們將泛型為Bitmap.以及其它我們想要的類型。 我們還可以指定加載的寬和高,如下,設(shè)置寬和高都是100,單位是px
SimpleTarget target = new SimpleTarget<Drawable>(100,100){
@Override
public void onResourceReady(Drawable resource, GlideAnimation<? super Drawable> glideAnimation) {
textView.setBackground(resource);
}
};
ViewTarget
如果你想加載一個(gè)圖片到View中,但是你想觀察或者覆蓋Glide的默認(rèn)行為。你可以覆蓋ViewTarget或者它的子類。 當(dāng)你想讓Glide來(lái)獲取view的的大小,但是由自己來(lái)啟動(dòng)動(dòng)畫(huà)和設(shè)置資源到view中,ViewTarget是個(gè)不錯(cuò)的選擇。如果你要加載一個(gè)圖片到ImageView之外的自定義view中,那么ImageViewTarget或者它的子類就不能滿足你的要求,此時(shí)繼承ViewTarget就特別合適。 你可以靜態(tài)的定義一個(gè)ViewTarget的子類,或者傳遞一個(gè)匿名內(nèi)部類到你的加載調(diào)用里:
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)
轉(zhuǎn)換 transform
在圖片顯示之前,我們可以通過(guò)transform對(duì)圖像做一些處理,達(dá)到我們想要的圖片效果,例如我們改變圖片的大小,范圍,顏色等。Glide提供了兩種基本的圖片轉(zhuǎn)換即:fitCenter 和 centerCrop,前面已介紹過(guò)。這次我們來(lái)了解如何自定義轉(zhuǎn)換效果,例如如果我們想展示一個(gè)圓形圖片或者一個(gè)具有圓角的圖片該如何處理?(圓形頭像) 為了自定義轉(zhuǎn)換,我們需要?jiǎng)?chuàng)建一個(gè)新的類實(shí)現(xiàn)了 Transformation 接口。不過(guò)如果我們只是做圖片的轉(zhuǎn)換可以直接用Glide封裝好的BitmapTransformation抽象類。圖像轉(zhuǎn)換操作只需要在transform里實(shí)現(xiàn)。getId() 方法描述了這個(gè)轉(zhuǎn)換的唯一標(biāo)識(shí)符。Glide 使用該鍵作為緩存系統(tǒng)的一部分,為了避免意外的問(wèn)題,你要確保它是唯一的 接下來(lái)先實(shí)現(xiàn)一個(gè)圓角的圖片
推薦一個(gè)開(kāi)源的轉(zhuǎn)換庫(kù)glide-transformations,它實(shí)現(xiàn)了很多轉(zhuǎn)換,我們只要集成直接使用 glide-transformationsGithub地址
這里寫(xiě)圖片描述
/**
* 將圖像轉(zhuǎn)換為四個(gè)角有弧度的圖像
*/
public class GlideRoundTransform extends BitmapTransformation {
private float radius = 0f;
public GlideRoundTransform(Context context) {
this(context, 100);
}
public GlideRoundTransform(Context context, int dp) {
super(context);
this.radius = Resources.getSystem().getDisplayMetrics().density * dp;
}
@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
return roundCrop(pool, toTransform);
}
private Bitmap roundCrop(BitmapPool pool, Bitmap source) {
if (source == null) return null;
Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
if (result == null) {
result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(result);
Paint paint = new Paint();
paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
paint.setAntiAlias(true);
RectF rectF = new RectF(0f, 0f, source.getWidth(), source.getHeight());
canvas.drawRoundRect(rectF, radius, radius, paint);
Log.e("11aa", radius + "");
return result;
}
@Override
public String getId() {
return getClass().getName() + Math.round(radius);
}
}
Glide.with(context).load("http://img2./2014/f6/173/d/51.jpg").centerCrop().transform(new GlideRoundTransform(this,50)).animate(animator).into(imageView);
當(dāng)然如果我們想實(shí)現(xiàn)成一個(gè)圓形的頭像,只需要在上面基礎(chǔ)上稍微調(diào)整即可。那么如何旋轉(zhuǎn)圖片呢如下
/**
*將圖像做旋轉(zhuǎn)操作
*/
public class GlideRotateTransform extends BitmapTransformation {
private float rotateAngle = 0f;
public GlideRotateTransform(Context context) {
this(context, 90);
}
public GlideRotateTransform(Context context, float rotateAngle) {
super(context);
this.rotateAngle = rotateAngle;
}
@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
Matrix matrix=new Matrix();
matrix.postRotate(rotateAngle);
return Bitmap.createBitmap(toTransform,0,0,toTransform.getWidth(),toTransform.getHeight(),matrix,true);
}
@Override
public String getId() {
return getClass().getName() + rotateAngle;
}
}
Glide.with(context).load("http://img2./2014/f6/173/d/51.jpg").centerCrop().transform(new GlideRotateTransform(this)).animate(animator).into(imageView);
看到這就明白了,其實(shí)自定義轉(zhuǎn)換也很簡(jiǎn)單。需要注意的一點(diǎn)transform()如果多次調(diào)用,后面的效果會(huì)覆蓋前面的,也就是說(shuō)我們只能看到最后一次的轉(zhuǎn)換,所以不要多次調(diào)用,還有centerCrop() 和fitCenter() 也是轉(zhuǎn)換,他是Glide自己實(shí)現(xiàn)的轉(zhuǎn)換。 通過(guò)前面幾句的描述,你可能會(huì)問(wèn)既然transform()或者centerCrop() 和fitCenter() 不能多次調(diào)用,那么我們想實(shí)現(xiàn)多種效果該怎么辦呢?不要驚慌,我們看下transform源碼它就收任意長(zhǎng)的參數(shù)
public DrawableRequestBuilder<ModelType> transform(BitmapTransformation... transformations) {
return bitmapTransform(transformations);
}
現(xiàn)在我們要實(shí)現(xiàn)上面兩個(gè)圓角加旋轉(zhuǎn)的轉(zhuǎn)換只需要將兩個(gè)對(duì)象都以參數(shù)傳遞就可以了
Glide.with(context).load("http://img2./2014/f6/173/d/51.jpg").centerCrop().transform(new GlideRoundTransform(this,50),new GlideRotateTransform(this)).animate(animator).into(imageView);
實(shí)現(xiàn)效果
這里寫(xiě)圖片描述
Notifications加載網(wǎng)絡(luò)圖片
我們發(fā)現(xiàn)現(xiàn)在很多App通知都會(huì)有一個(gè)圖片展示,這更美觀而且更能形象的表達(dá)出通知的內(nèi)容,那么怎么加載網(wǎng)絡(luò)上的圖片到通知欄呢?Glide提供了NotificationTarget來(lái)加載網(wǎng)絡(luò)上的圖片,當(dāng)然我們自己寫(xiě)通知加載網(wǎng)絡(luò)上的圖片也能實(shí)現(xiàn),但是畢竟需要耗很多時(shí)間, 接下來(lái)我們先布局通知UI,如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas./apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/white"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="2dp">
<ImageView
android:id="@+id/notification_icon"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_marginRight="2dp"
android:layout_weight="0"
android:scaleType="centerCrop" />
<TextView
android:layout_gravity="center"
android:id="@+id/notification_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ellipsize="end"
android:singleLine="true"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
創(chuàng)建自定義通知
/**
* 設(shè)置通知欄網(wǎng)絡(luò)圖標(biāo)
*/
private void notificationTarget() {
RemoteViews remoteViews = new RemoteViews(this.getPackageName(), R.layout.notifition);
remoteViews.setImageViewResource(R.id.notification_icon, R.mipmap.ic_launcher);
remoteViews.setTextViewText(R.id.notification_text, "HeadLine");
//build notifition
NotificationCompat.Builder builder = (NotificationCompat.Builder) new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Content Title")
.setContentText("Content Text")
.setContent(remoteViews)
.setPriority(NotificationCompat.PRIORITY_MIN);
final Notification notification=builder.build();
if (Build.VERSION.SDK_INT>=16){
notification.bigContentView=remoteViews;
}
NotificationManager notificationManager=(NotificationManager)this.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID,notification);
NotificationTarget notificationTarget=new NotificationTarget(this,remoteViews,R.id.notification_icon,notification,NOTIFICATION_ID);
Glide.with(this).load(urls[4]).asBitmap().placeholder(R.mipmap.ic_launcher).error(R.mipmap.place).listener(new RequestListener<String, Bitmap>() {
@Override
public boolean onException(Exception e, String model, Target<Bitmap> target, boolean isFirstResource) {
Log.e("TAG",e.toString());
return true;
}
@Override
public boolean onResourceReady(Bitmap resource, String model, Target<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) {
Log.e("TAG","1111111111111111111");
return false;
}
}) .dontAnimate().into(notificationTarget);
}
自定義GlideModule
我們先新建一個(gè)類實(shí)現(xiàn)GlideModule接口 ,在applyOptions方法里利用GlideBuilder 全局改變 Glide 行為的一個(gè)方式,通過(guò)全局GlideModule 配置Glide,用GlideBuilder設(shè)置選項(xiàng),用Glide注冊(cè)ModelLoader等
/**
* Created by xiehui on 2016/8/29.
*/
public class ConfigurationGlide implements GlideModule {
@Override
public void applyOptions(final Context context, GlideBuilder builder) {
//配置
}
@Override
public void registerComponents(Context context, Glide glide) {
}
}
完成自定義類的創(chuàng)建后,需要在清單文件中配置,如果不配置的話,我們自定義的ConfigurationGlide 里實(shí)現(xiàn)的內(nèi)容都不會(huì)生效。
<meta-data android:name="com.example.xh.glidedemo.ConfigurationGlide"
android:value="GlideModule"/>
混淆
因?yàn)橐玫椒瓷涞腉lideModule可以通過(guò)反射實(shí)例化
-keepnames class com.example.xh.glidedemo.ConfigurationGlide
當(dāng)然我們最好的方法是一次性混淆配置
-keep public class * implements com.bumptech.glide.module.GlideModule
Glide 的圖片質(zhì)量
在 Android 中有兩個(gè)主要的方法對(duì)圖片進(jìn)行解碼:ARGB8888(每像素4字節(jié)存儲(chǔ)) 和 RGB565(每像素2字節(jié)存儲(chǔ))。當(dāng)然ARGB8888有更高的圖片質(zhì)量,Glide默認(rèn)使用RGB565進(jìn)行解碼,所以內(nèi)存占用相對(duì)較小,如果我們想要更高的圖片質(zhì)量,可以設(shè)置,如下
builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
內(nèi)存緩存
Glide提供了一個(gè)類MemorySizeCalculator,用于決定內(nèi)存緩存大小以及 bitmap 的緩存池。bitmap 池維護(hù)了你 App 的堆中的圖像分配。正確的 bitmpa 池是非常必要的,因?yàn)樗苊夂芏嗟膱D像重復(fù)回收,這樣可以確保垃圾回收器的管理更加合理。它的默認(rèn)計(jì)算實(shí)現(xiàn)
//內(nèi)存緩存
MemorySizeCalculator memorySizeCalculator = new MemorySizeCalculator(context);
int defaultMemoryCacheSize = memorySizeCalculator.getMemoryCacheSize();
int defalutBitmapPoolSize = memorySizeCalculator.getBitmapPoolSize();
此時(shí)我們可以根據(jù)默認(rèn)的大小去調(diào)整自己想要的大小
builder.setMemoryCache(new LruResourceCache((int) (defalutBitmapPoolSize * 1.2)));//內(nèi)部
builder.setBitmapPool(new LruBitmapPool((int) (defalutBitmapPoolSize * 1.2)));
磁盤(pán)緩存
Glide圖片緩存有兩種情況,一種是內(nèi)部磁盤(pán)緩存另一種是外部磁盤(pán)緩存。我們可以通過(guò) builder.setDiskCache()設(shè)置,并且Glide已經(jīng)封裝好了兩個(gè)類實(shí)現(xiàn)外部和內(nèi)部磁盤(pán)緩存,分別是InternalCacheDiskCacheFactory和ExternalCacheDiskCacheFactory,通過(guò)源碼發(fā)現(xiàn)磁盤(pán)緩存默認(rèn)是250M,路徑名image_manager_disk_cache如下
//DiskCache接口內(nèi)部Factory接口聲明
/** 250 MB of cache. */
int DEFAULT_DISK_CACHE_SIZE = 250 * 1024 * 1024;
String DEFAULT_DISK_CACHE_DIR = "image_manager_disk_cache";
設(shè)置磁盤(pán)緩存大小100M
//磁盤(pán)緩存100M
builder.setDiskCache(new InternalCacheDiskCacheFactory(context, 1024 * 1024 * 100));//內(nèi)部磁盤(pán)緩存
builder.setDiskCache(new ExternalCacheDiskCacheFactory(context, 100 * 1024 * 1024));//磁盤(pán)緩存到外部存儲(chǔ)
上面我們實(shí)現(xiàn)了自定義緩存的大小,但是緩存的路徑是固定的,那么該如何自己定義緩存路徑呢?上代碼
//指定緩存目錄1
String downLoadPath = Environment.getDownloadCacheDirectory().getPath();
builder.setDiskCache(new DiskLruCacheFactory(downLoadPath, defaultMemoryCacheSize));
//指定緩存目錄2
builder.setDiskCache(new DiskCache.Factory() {
@Override
public DiskCache build() {
File cacheLocation = new File(context.getExternalCacheDir(), "cache_dir");
cacheLocation.mkdirs();
return DiskLruCacheWrapper.get(cacheLocation, 1024 * 1024 * 100);
}
});
registerComponents里的實(shí)現(xiàn)參考源碼
本文是自己學(xué)習(xí)的一個(gè)總結(jié)記錄,同時(shí)也希望對(duì)看本文的你有一定幫助,由于水平有限,文中若有錯(cuò)誤的地方歡迎指正!謝謝。
|