今天,簡單講講Android里Glide的簡單使用。
Android框架系列:
一.android EventBus的簡單使用
二.android Glide簡單使用
對於Glide這個加載圖片的框架,很多人都在用,我之前使用的是ImageLoader,最近查資料時,發現Glide才是Google推薦的加載圖片框架,功能非常強大,而且還有Google專人維護,要知道,ImageLoader已經沒人維護了,除了問題可沒人解答。所以有必要整理一下Glide的使用。
Glide是谷歌為我們推薦的一個圖片加載庫。為什么要選擇使用Glide呢?
1、代碼有人維護,不至於出現問題,項目組都搞不定的時候問題無法解決。(ImageLoader已沒人維護了)
2、代碼簡潔,可讀性很好。(Fresco是一個非常優秀的庫,但是配置稍顯麻煩,同時代碼風格讀起來有些生疏)
3、功能強大(400多k的包,包含很多功能,例如:像加載Gif圖片就是Picasso做不到的)
下面我們就來介紹下Glide的用法:
Glide的基本使用
導入庫
compile 'com.github.bumptech.glide:glide:3.7.0'
添加代碼混淆(可加可不加)
-keep public class * implements com.bumptech.glide.module.GlideModule -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** { **[] $VALUES; public *; }
for DexGuard only
-keepresourcexmlelements manifest/application/meta-data@value=GlideModule
這個別忘了,不要粗心哦,很容易忘得,最簡單的問題,往往需要最簡單的搞定啦。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.INTERNET" /> 簡單使用例子 // For a simple view: @Override public void onCreate(Bundle savedInstanceState) { ... ImageView imageView = (ImageView) findViewById(R.id.my_image_view); Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView); } // For a simple image list: @Override public View getView(int position, View recycled, ViewGroup container) { final ImageView myImageView; if (recycled == null) { myImageView = (ImageView) inflater.inflate(R.layout.my_image_view, container, false); } else { myImageView = (ImageView) recycled; } String url = myUrls.get(position); Glide .with(myFragment) .load(url) .centerCrop() .placeholder(R.drawable.loading_spinner) .crossFade() .into(myImageView); return myImageView; }
Glide使用詳解
加載網絡圖片
Glide.with(context).load(internetUrl).into(targetImageView);
從文件加載圖片
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"Test.jpg"); Glide.with(context).load(file).into(imageViewFile);
從資源id加載圖片
int resourceId = R.mipmap.ic_launcher; Glide.with(context).load(resourceId).into(imageViewResource);
從uri加載圖片
Glide.with(context).load(uri).into(imageViewUri);
播放本地mp4,只能是本地(獲取MP4視頻的縮略圖)
String filePath = "/storage/emulated/0/Pictures/example_video.mp4"; Glide.with( context ).load( Uri.fromFile( **new **File( filePath ) ) ).into( imageViewGifAsBitmap );
加載Gif圖片
String gifUrl = "xxxxx"; Glide.with( context ).load( gifUrl ).into( imageViewGif );
用bitMap播放Gif.asBitmap()
Glide.with( context ).load( gifUrl ).asBitmap().into( imageViewGifAsBitmap );
強制轉化為Gif.asGif()
Glide.with( context ).load( gifUrl ).asGif().error( R.drawable.full_cake ).into( imageViewGif );
設置默認占位圖.placeholder()
設置加載失敗的圖片.error()
Glide.with( context ).load( gifUrl ).placeholder( R.drawable.cupcake ).error( R.drawable.full_cake ).into( imageViewGif ); .fallback()
除了上面兩種‘異常情況’,還有一種情形就是打開手機的通訊錄的時候,可以看到你給有些喜歡的人設置了照片,然而有些可憐的人並沒給有,總不能在那里留下一片空白吧,這個時候相當於傳遞了Null,傳遞null時,這個callback方法就會被調用。
Glide.with(context) .load( null)//加載空指針的時候 .fallback( R.drawable.wuyanzu) .into( imageViewNoFade );
設置加載動畫
其實這個是默認的,但是你還是可以寫出來,漸顯動畫
1、.crossFade() :Glide提供淡如淡出
Glide.with(context).load().placeholder(R.mipmap.ic_launcher) .error(R.mipmap.future_studio_launcher).crossFade().into(imageViewFade);
這里還有一個.fadeFade(int duration),設置動畫時間。如果你不想要動畫可以加上.dontAnimate()
2、.animate(android.R.anim.slide_in_left):Android系統提供,從左到右滑出加載動畫
調整圖片大小.resize(int ,int )
單位是像素,裁剪你的圖片大小。其實Glide已經會自動根據你ImageView裁剪照片來放在緩存中了。但是不想適應ImageView大小的時候,可以調用這個方法.override()為ImageView指定大小。
Glide.with(context).load(image).override(600, 200) .into(imageViewResize);
裁剪圖片.fitCenter()和.CenterCrop()
Glide清楚在合適的ImageView中加載合適的Image.當需要裁剪大小時,有個.centerCrop方法,這個方法的裁剪會讓你的ImageView周圍不會留白,還有一個.fitCenter()方法,表示讓你的Image完全顯示,尺寸不對時,周圍會留白。
設置縮略圖.thumbnail()
.thumbnail()方法的目的就是讓用戶先看到一個低解析度的圖,點開后,再加載一個高解析度的圖。
//表示為原圖的十分之一 Glide.with( context ).load(image).thumbnail( 0.1f ).into( imageView2 );
一種更高級的縮略圖加載方式:
當縮略圖也需要通過網絡加載全部解析度的時候。
private void loadImageThumbnailRequest() { DrawableRequestBuilder<String> thumbnailRequest = Glide.with( context ).load( eatFoodyImages[2] ); Glide.with( context ).load( UsageExampleGifAndVideos.gifUrl ).thumbnail( thumbnailRequest ).into( imageView3 ); }
設置圖片顯示效果(圓角、圓形、高斯模糊、蒙板、裁剪等等).bitmapTransform()
Glide.with(this).load(R.mipmap.ic_image_sample) //模糊 .bitmapTransform(new BlurTransformation(this)) //圓角 .bitmapTransform(new RoundedCornersTransformation(this, 24, 0, RoundedCornersTransformation.CornerType.ALL)) //遮蓋 .bitmapTransform(new MaskTransformation(this, R.mipmap.ic_launcher)) //灰度 .bitmapTransform(new GrayscaleTransformation(this)) //圓形 .bitmapTransform(new CropCircleTransformation(this)) .into(mResultIv);
除此之外還有實現諸如馬賽克、明暗度等更多濾鏡處理:
ToonFilterTransformation
SepiaFilterTransformation
ContrastFilterTransformation
InvertFilterTransformation
PixelationFilterTransformation
SketchFilterTransformation
SwirlFilterTransformation
BrightnessFilterTransformation
KuwaharaFilterTransformation
VignetteFilterTransformation
Glide的緩存
用過手機的都知道,當划上划下一個ListView的時候,第二次都比第一次快,就是因為為GlideView對資源進行了緩存,而且封裝的很好,甚至不需要自己去設定緩存大小,Glide會智能地自己給我們根據設備設置緩存大小。
緩存是為了減少或者杜絕多的網絡請求。為了避免緩存,Glide用了內存緩存和‘外存緩存機制’,並且 提供了相應的方法,完全封裝,不需要處理細節。Glide會自動緩存到內存,除非調用.skipMemoryCache( true )。盡管調用了這個,Glide還是會緩存到外存,還有一種情形,就是有一張圖片,但是這張圖變化非常快,這個時候可能並不想緩存到外存中,就使用.diskCacheStrategy( DiskCacheStrategy.NONE )。如果你兩種都不需要,可以兩個方法組合着一起使用。
自定義外存緩存機制
Glide默認會緩存Image的很多個版本,比如原圖,如果你的imageView大小的緩存。.diskCacheStrategy()有以下幾種緩存策略:
DiskCacheStrategy.NONE 什么都不緩存
DiskCacheStrategy.SOURCE 只緩存最高解析圖的image
DiskCacheStrategy.RESULT 緩存最后一次那個image,比如有可能你對image做了轉化
DiskCacheStrategy.ALL image的所有版本都會緩存
Glide.with( context ).load( image ).diskCacheStrategy( DiskCacheStrategy.SOURCE ).into( imageViewFile );
修改緩存大小、位置、加載圖片質量
和指定HttpClent為OkHttp一樣,只不過我們需要配置一些信息在applyOptions()函數里面
public class GlideConfigModule implements GlideModule { @Override public void applyOptions(Context context, GlideBuilder builder) { // 指定位置在packageName/cache/glide_cache,大小為MAX_CACHE_DISK_SIZE的磁盤緩存 builder.setDiskCache(new InternalCacheDiskCacheFactory(context, "glide_cache", ConfigConstants.MAX_CACHE_DISK_SIZE)); //指定內存緩存大小 builder.setMemoryCache(new LruResourceCache(ConfigConstants.MAX_CACHE_MEMORY_SIZE)); //全部的內存緩存用來作為圖片緩存 builder.setBitmapPool(new LruBitmapPool(ConfigConstants.MAX_CACHE_MEMORY_SIZE)); builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);//和Picasso配置一樣 } @Override public void registerComponents(Context context, Glide glide) { } }
<meta-data android:name="com.example.imageloadpk.adapter.config.GlideConfigModule" android:value="GlideModule"/>
一般的圖片加載框架設置了磁盤緩存和內存緩存就行了,但是Glide還設置了一個圖片緩存。
圖片緩存 <= 內存緩存
builder.setDiskCache(new InternalCacheDiskCacheFactory(context, "glide_cache", ConfigConstants.MAX_CACHE_DISK_SIZE)); //指定內存緩存大小 builder.setMemoryCache(new LruResourceCache(ConfigConstants.MAX_CACHE_MEMORY_SIZE)); //全部的內存緩存用來作為圖片緩存 builder.setBitmapPool(new LruBitmapPool(ConfigConstants.MAX_CACHE_MEMORY_SIZE));
這里Glide不僅可以緩存圖片,還可以緩存其他文件譬如視頻之類,也就是說可以把他作為我們的緩存工具來使用,當然緩存方式還是使用LRU。這樣我們就不必再去重新集成LruCache和DiskLruCache,再去申請空間,配置。直接可以復用Glide的。
使用緩存也加載動畫
但是,動畫默認是在圖片沒有緩存的情況下才加載,想想也是合理的,如果圖片已近下載到本地加載速度將會非常快,這個時候使用動畫過渡反而礙事。要讓從緩存中圖片呈現也加載動畫不能通過這種方式實現,可以用監聽器來做。
private RequestListener<String, GlideBitmapDrawable> mAnimationRequestListener = new RequestListener<String, GlideBitmapDrawable>() { @Override public boolean onException(Exception e, String model, Target<GlideBitmapDrawable> target, boolean isFirstResource) { return false; } @Override public boolean onResourceReady(GlideBitmapDrawable resource, String model, Target<GlideBitmapDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) { dissProgress(); if (isFromMemoryCache) { //如果是從緩存加載,設置動畫效果 mIvShow.setAnimation(AnimationUtils.loadAnimation(mContext, R.anim.scale)); } //返回true表示攔截不再傳遞,false表示事件會傳遞下去 return false; } };
請求優先級.priority()
加載圖片肯定也是有先后順序,Glide提供了.priority()這個方法,它接收以下幾個參數:
- Priority.LOW
- Priority.NORMAL
- Priority.HIGH
- Priority.IMMEDIATE
但是Glide並不一定會按照你的順序來,只是盡量按照你的順序來。(比如給一張很大的圖片最高的優先權,但是它並不一定比低優先級的圖先加載出來,這個時候只有使用縮略圖了)
Glide.with(mContext).load(Url.IMAGE_URL_TROCHILIDAE) .priority(Priority.HIGH).into(mIvTonyRight);
利用callback在非標准情況下加載圖片
上面所有的情況都是加載圖片到ImageView中,但是並不是所有的情況都是這樣。譬如加載的控件類型不是ImageView,是個自定義的布局。或者加載為Background的形式。
可以使用SimpleTarget類型,這里指定他的大小為500*100,加載為背景圖片
.into(new SimpleTarget<Drawable>(500, 100) { @Override public void onResourceReady(Drawable resource, GlideAnimation<? super Drawable> glideAnimation) { mBtnClear.setBackground(resource); }
同理下載圖片原理是一樣
.into(new SimpleTarget<Bitmap>() { @Override public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) { //toSave Log.d(TAG, "onResourceReady: save successful"); } });
Glide中的回調:Targets
從上面的介紹,已經可以看出Glide內部封裝了所有的細節,什么網絡請求,什么緩存機制,當所有都就緒過后,自動切換回UI線程,更新ImageView。Targets就是Glide中的回調,當異步線程中所有的工作做完過后返回結果。說白了就是,當請求圖片完成后,需要回調的方法。
SimpleTarget
private SimpleTarget target = new SimpleTarget<Bitmap>() { @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()//強制Glide返回一個Bitmap .into( target ); }
注意事項:
1、上面這段代碼不要寫成匿名內部類的機制,原因就是java的自動垃圾回收機制可能在圖片還沒有加載好的時候就已經把你的Target回收了。
2、注意.with()里面的參數,Glide的請求是和傳進去的Context共存亡的,如果傳一個Activity進去,當Activity GC過后,你的請求也就GC了,但是如果這樣傳:.with(context.getApplicationContext() ).當你的Activity GC過后,請求還是會繼續,回調還是會繼續。
有size的Target
如果傳給into().的是一個ImageView,但是圖片的size比ImageView的Size打,Glide為了節省時間,會加載小的那個size的Image。但是這對Target並不適用,以為這里並不知道SIze。但是如果知道image應該多大,可以傳遞給Target.就像下面這樣:
private SimpleTarget target2 = new SimpleTarget<Bitmap>( 250, 250 ) { @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
適用於想Glide加載到自定義View中去,
public class FutureStudioView extends FrameLayout { ImageView iv; TextView tv; public void nitialize(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 ); } }
還有notificationTarget 和AppWidget作為擴展自行研究嘍。
監聽器配置.listener()
Glide.with(getContext()).load(url) .listener(mRequestListener)//配置監聽器 .placeholder(Drawables.sPlaceholderDrawable) .error(Drawables.sErrorDrawable) .into(mImageView); private RequestListener<String, GlideDrawable> mRequestListener = new RequestListener<String, GlideDrawable>() { @Override public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) { //顯示錯誤信息 Log.w(TAG, "onException: ", e); //打印請求URL Log.d(TAG, "onException: " + model); //打印請求是否還在進行 Log.d(TAG, "onException: " + target.getRequest().isRunning()); return false; } @Override public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) { return false; } };
這里的onException捕獲異常,如果返回true表示我們自己處理掉了異常,false表示交給Glide去處理,因為我們定義了.error()那么就顯示error里面的內容。
這里onResourceReady表示是否准備資源顯示,返回true表示用戶自己已經設置好資源,包括截取操作,動畫操作之類的,准備好顯示。false表示交給Glide
如此修改后,就能夠看到圖片加載日志了,方便我們調試
替換掉自帶的HttpClient
只需兩步
Step1:
導入需要替換的HttpClient,可以選擇Volley也可以選擇OkHttp,我們使用Okhttp,在Module的build.gradle文件中配置
dependencies {
compile 'com.github.bumptech.glide:okhttp3-integration:1.4.0@aar'
compile 'com.squareup.okhttp3:okhttp:3.3.1'
or
compile 'com.github.bumptech.glide:volley-integration:1.4.0@aar'
compile 'com.mcxiaoke.volley:library:1.0.8'
}
這個版本具體選擇多少,可以在https://github.com/bumptech/glide/wiki/Integration-Libraries這里查詢到
Step2:
在AndroidMainfest.xml文件中寫入
這個版本具體選擇多少,可以在https://github.com/bumptech/glide/wiki/Integration-Libraries這里查詢到
Step2:
在AndroidMainfest.xml文件中寫入
<meta-data android:name="com.bumptech.glide.integration.okhttp3.OkHttpGlideModule" android:value="GlideModule"/>
你可能會有和我一樣的疑問,Glide可以通過在配置清單里面配置
能不能寫幾個meta-data標簽,一個標簽里面配置一點參數
經過測試,發現這樣做也是可以的。但是如果是同一種配置信息,比如你集成了OkHttp,又寫一個標簽集成Volley,最后一個會把前面的覆蓋掉。
注意事項
1、前面我們已經學習到asGif()可以加載gif圖,asBitmap()可以加載靜態gif圖即gif圖的第一幀,如果非gif圖用asGif()方法加載呢?這時候會報錯。。Glide默認可以自動識別圖片格式,加載gif圖,所以在不確定圖片格式的情況下,不要直接寫asGif哦。
2、You cannot start a load for a destroyed activity這樣的異常如何處理?
記住不要再非主線程里面使用Glide加載圖片,如果真的使用了,請把context參數換成getApplicationContext。希望可以幫你避免這個問題。
3、為什么有的圖片第一次加載的時候只顯示占位圖,第二次才顯示正常的圖片呢?
.如果你剛好使用了這個圓形Imageview庫或者其他的一些自定義的圓形Imageview,而你又剛好設置了占位的話,那么,你就會遇到第一個問題。如何解決呢?
方案一: 不設置占位;
方案二:使用Glide的Transformation API自定義圓形Bitmap的轉換。這里是一個已有的例子;
方案三:使用下面的代碼加載圖片:
Glide.with(mContext) .load(url) .placeholder(R.drawable.loading_spinner) .into(new SimpleTarget<Bitmap>(width, height) { @Override public void onResourceReady(Bitmap bitmap, GlideAnimation anim) { // setImageBitmap(bitmap) on CircleImageView } };
4、圖片大小拉伸問題
有時候你會發現網絡加載完了之后會有拉伸現象,而你的控件大小明明是自適應的呀,這是為什么呢,請你檢查下你是否設置了占位圖,有的話請去掉就ok了。
簡單總結一下,我這里講了Glide比較全面的用法,有如何加載圖片,Glide的緩沖設置,Glide設置圓角,Glide設置圖片的background,Glide加載GIF圖片等,大家使用的話一般了解加載圖片和圓角圖片就可以了。這里在列舉一下。
//圓形裁剪 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);
android Glide簡單使用就講完了。
結尾
最后小編想說:不論以后選擇什么方向發展,目前重要的是把Android方面的技術學好,畢竟其實對於程序員來說,要學習的知識內容、技術有太多太多,要想不被環境淘汰就只有不斷提升自己,從來都是我們去適應環境,而不是環境來適應我們!
當程序員容易,當一個優秀的程序員是需要不斷學習的,從初級程序員到高級程序員,從初級架構師到資深架構師,或者走向管理,從技術經理到技術總監,每個階段都需要掌握不同的能力。早早確定自己的職業方向,才能在工作和能力提升中甩開同齡人。
想要拿高薪實現技術提升薪水得到質的飛躍。最快捷的方式,就是有人可以帶着你一起分析,這樣學習起來最為高效,所以為了大家能夠順利進階中高級、架構師,我特地為大家准備了一套高手學習的源碼和框架視頻等精品Android架構師教程,保證你學了以后保證薪資上升一個台階。(以下是一小部分,獲取更多其他精講進階架構視頻資料可以關注【我的主頁】或者【簡信我】獲取免費領取方式)
當你有了學習線路,學習哪些內容,也知道以后的路怎么走了,理論看多了總要實踐的。
以下是今天給大家分享的一些獨家干貨:
【Android開發核心知識點筆記】
【Android思維腦圖(技能樹)】
【Android核心高級技術PDF文檔,BAT大廠面試真題解析】
【Android高級架構視頻學習資源】
Android精講視頻領取學習后更加是如虎添翼!進軍BATJ大廠等(備戰)!現在都說互聯網寒冬,其實無非就是你上錯了車,且穿的少(技能),要是你上對車,自身技術能力夠強,公司換掉的代價大,怎么可能會被裁掉,都是淘汰末端的業務Curd而已!現如今市場上初級程序員泛濫,這套教程針對Android開發工程師1-6年的人員、正處於瓶頸期,想要年后突破自己漲薪的,進階Android中高級、架構師對你更是如魚得水,趕快領取吧!
【Android進階學習視頻】、【全套Android面試秘籍】【簡信我學習】查看免費領取方式!
分享不易!喜歡的朋友別忘了關注+點贊!
原文作者:暴走鄰家
原文鏈接:https://blog.csdn.net/bzlj2912009596/article/details/81702367
