一:簡介
在泰國舉行的谷歌開發者論壇上,谷歌為我們介紹了一個名叫 Glide 的圖片加載庫,作者是bumptech。這個庫被廣泛的運用在google的開源項目中,包括2014年google I/O大會上發布的官方app。
https://github.com/bumptech/glide
二:使用
dependencies { compile 'com.github.bumptech.glide:glide:3.7.0' }
如何查看最新版本
http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22glide%22
三:使用方法及簡介
http://mrfu.me/2016/02/27/Glide_Getting_Started/
四、清除緩存
/** * 清除緩存 * @param context */ public void clearCache( final Context context ){ clearMemoryCache( context ); new Thread(new Runnable() { @Override public void run() { clearDiskCache( context ); } }).start(); } /** * 清除內存緩存 * @param context */ public void clearMemoryCache( Context context ){ Glide.get( context ).clearMemory(); } /** * 清除磁盤緩存 * @param context */ public void clearDiskCache( Context context ){ Glide.get( context ).clearDiskCache(); }
五、注意事項
5.1、在使用時需要給app添加聯網權限,沒有權限不會報錯,但是圖片加載不出來,很坑爹。
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
5.2、加載圖片的方法要寫在 UI 線程中,Glide會做異步處理。
六、使用方法總結
6.1 加載網絡圖片
imageView = (ImageView) findViewById( R.id.image ); String url = "http://img5.jpg" ; Glide.with( this ).load( url ).into( imageView ) ;
6.2 加載網絡圖片監聽(下載完成后顯示)
package lib.com.myapplication; import android.graphics.Bitmap; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.widget.ImageView; import com.bumptech.glide.Glide; import com.bumptech.glide.request.animation.GlideAnimation; import com.bumptech.glide.request.target.SimpleTarget; public class MainActivity extends AppCompatActivity { private ImageView imageView ; String url = "http://img5.imgtn.bdimg.com/it/u=2941079711,2736454066&fm=11&gp=0.jpg" ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = (ImageView) findViewById( R.id.image ); Glide.with( this ).load( url ).asBitmap().into( target ) ; } private SimpleTarget target = new SimpleTarget<Bitmap>() { @Override public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) { //圖片加載完成 imageView.setImageBitmap(bitmap); } }; }
特別注意 :.asBitmap() 一定要加,否則可能會出錯
6.3 占位符 placeholder() 方法:在加載開始 -- 加載完成,這段時間顯示的圖片。如果加載失敗,則最終顯示占位符。
imageView = (ImageView) findViewById( R.id.image ); Glide.with( this ).load( url ).placeholder( R.drawable.user ).into( imageView ) ;
6.4 占位符 error() 方法:在加載失敗的情況下,顯示的圖片。
imageView = (ImageView) findViewById( R.id.image ); Glide.with( this ).load( url ).placeholder( R.drawable.user ).error( R.drawable.default_error ).into( imageView ) ;
在加載開始--> 加載完成(失敗),顯示placeholder()圖片; 如果加載失敗,則顯示error() 里面的圖片。
6.5 加載 drawable 里面的圖片
imageView = (ImageView) findViewById( R.id.image ); Glide.with( this ).load( R.drawable.icon ).asBitmap().into( imageView ) ;
6.6 加載 SD 卡里面的一張圖片 1 load( String string)
imageView = (ImageView) findViewById( R.id.image ); //sd卡上的一張圖片 String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/temp.jpg" ; Glide.with( this ).load( path ).into( imageView ) ;
6.7 加載 SD 卡里面的一張圖片 2 load( File file )
imageView = (ImageView) findViewById( R.id.image ); //sd卡上的一張圖片 String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/temp.jpg" ; File file = new File( path ) ; Glide.with( this ).load( file ).into( imageView ) ;
6.8 加載 SD 卡里面的一張圖片 3 load( Uri uri )
//sd卡上的一張圖片 String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/temp.jpg" ; File file = new File( path ) ; Uri uri = Uri.fromFile( file ) ; Glide.with( this ).load( uri ).into( imageView ) ;
6.9 Glide.with() 生命周期控制
- with(Context context). 使用Application上下文,Glide請求將不受Activity/Fragment生命周期控制。
- with(Activity activity). 使用Activity作為上下文,Glide的請求會受到Activity生命周期控制。
- with(FragmentActivity activity).Glide的請求會受到FragmentActivity生命周期控制。
- with(android.app.Fragment fragment).Glide的請求會受到Fragment 生命周期控制。
- with(android.support.v4.app.Fragment fragment).Glide的請求會受到Fragment生命周期控制。
- 請求會在onStop的時候自動暫停,
- 在onStart的時候重新啟動,gif的動畫也會在onStop的時候停止,以免在后台消耗電量。
6.10 加載優先級設置 priority()
枚舉類 Priority 提供了幾種優先級等級 ,
默認的是 : NORMAL
實例:
Glide.with( this).load( url2).priority(Priority.LOW ).into( imageView2 ) ; Glide.with( this).load( url3).priority(Priority.HIGH ).into( imageView3 ) ;
但是這里的優先級只是在加載的過程中起一個參考作用, 並不決定真正的加載順序。
6.11 縮略圖的支持
(一) 先加載原圖的十分之一作為縮略圖,再加載原圖
Glide.with( thi ).load( url ).thumbnail(0.1f).into( imageview ) ;
(二)用本地的圖片作為縮略圖,然后再加載原圖
DrawableRequestBuilder<Integer> thumbnailRequest = Glide .with( ThumbnailActivity.this ) .load(R.mipmap.ic_launcher); Glide.with( ThumbnailActivity.this ).load( ur2 ).thumbnail( thumbnailRequest ).into( imageView2 ) ;
6.12 加載 Gif 動圖
Glide.with( this ).load( url ).into( imageView1 ) ; Glide.with( this ).load( url ).asGif().into( imageView2 ) ;
注意:如果把asGif 換成 asBitmap 則會顯示一張靜態圖。
6.13 加載本地視頻,相當於一張縮略圖
imageView = (ImageView) findViewById( R.id.image_video ); String files = Environment.getExternalStorageDirectory().getAbsolutePath() + "/yueyu.mkv" ; Glide.with( this ).load( files ).into( imageView ) ;
(1)只能加載本地視頻,網絡視頻無法加載。
(2)加載本地視頻顯示只是視頻的第一幀圖像,相當於一張縮略圖。不能播放視頻。
6.14 加載動畫
- .crossFade() 淡入淡出 , 也是默認動畫
- .crossFade( int duration ) 定義淡入淡出的時間間隔
- .dontAnimate() 不使用任何動畫
6.15 glide 內存緩存
glide 默認啟用內存緩存,如果想要禁止內存緩存 ,使用 .skipMemoryCache( true )
七、自定義 GlideModule
自定義 GlideModule 的好處:
1、可以全局的改變 glide 的加載策略
2、可以自定義磁盤緩存目錄
3、可以設置圖片加載的質量
7.1 首先定義一個類實現 GlideModule
public class SimpleGlideModule implements GlideModule { @Override public void applyOptions(Context context, GlideBuilder builder) { } @Override public void registerComponents(Context context, Glide glide) { } }
可以看到重寫了兩個方法,applyOptions() , registerComponents() . 兩個方法都沒有返回值 。我們着重於第一個方法,重點研究 GlideBuilder 。
7.2 然后在 AndroidManifest.xml 去申明你寫的 SimpleGlideModule
<meta-data android:name="app.zuil.com.glidedemo.util.SimpleGlideModule" android:value="GlideModule" />
name是:包名 + 類名
7.3 GlideBuilder
- .setMemoryCache(MemoryCache memoryCache)
- .setBitmapPool(BitmapPool bitmapPool)
- .setDiskCache(DiskCache.Factory diskCacheFactory)
- .setDiskCacheService(ExecutorService service)
- .setResizeService(ExecutorService service)
- .setDecodeFormat(DecodeFormat decodeFormat)
可以看到 setBitmapPool() 是設置bitmap池的 ; setDecodeFormat() 是設置解碼方式的 ; setDiskCache() 是設置磁盤緩存的 ;
7.4 DecodeFormat
Android里有兩個方法去解析圖片:ARGB8888
和RGB565
。第一個為每個像素采用4 byte表示,后面一個則用2 byte表示。ARG8888
有更高的圖片質量,並且能夠存儲一個alpha通道。Glide默認使用低質量的RGB565
。你可以通過使用Glide module方法改變解析格式。
最后一個完整的自定義glideModule
public class SimpleGlideModule implements GlideModule { @Override public void applyOptions(Context context, GlideBuilder builder) { //定義緩存大小為100M int diskCacheSize = 100 * 1024 * 1024; //自定義緩存 路徑 和 緩存大小 String diskCachePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/glideCache" ; //提高圖片質量 builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888); //自定義磁盤緩存:這種緩存只有自己的app才能訪問到 // builder.setDiskCache( new InternalCacheDiskCacheFactory( context , diskCacheSize )) ; // builder.setDiskCache( new InternalCacheDiskCacheFactory( context , diskCachePath , diskCacheSize )) ; //自定義磁盤緩存:這種緩存存在SD卡上,所有的應用都可以訪問到 builder.setDiskCache(new DiskLruCacheFactory( diskCachePath , diskCacheSize )); } @Override public void registerComponents(Context context, Glide glide) { } }
八、緩存管理
7.1、默認緩存目錄和緩存大小
在Glide源碼中有一個DiskCache接口,里面的Factory類定義了默認的磁盤緩存大小為:250 M , 緩存路徑在:image_manager_disk_cache 目錄下
在模擬器上可以查看緩存目錄的位置,有些真機看不到這個目錄,有可能數據庫沒有刷新的原因:
7.2、緩存模式
源碼中有枚舉類 DiskCacheStrategy 定義了四種緩存類型
- DiskCacheStrategy.SOURCE 緩存原圖
- DiskCacheStrategy.RESULT 緩存和imageview大小匹配的圖
- DiskCacheStrategy.ALL 既緩存原圖,有緩存和imageview大小匹配的圖
- DiskCacheStrategy.NONE 不做任何緩存
通過查看源碼我們發現,Glide默認緩存策略是: DiskCacheStrategy.RESULT
7.3 四種緩存模式對比
比如:網絡圖片我們叫做 big1.jpg 寬高:3000 x 2000 大小:2.15 M 。
http://o7rvuansr.bkt.clouddn.com/big1.jpg
客戶端的 imageview 大小:300 x 300
<ImageView android:id="@+id/image" android:layout_width="300dp" android:layout_height="300dp" />
(1) DiskCacheStrategy.SOURCE : 只會緩存一張圖片,大小:2M
Glide.with( Activity2.this).load( url ).diskCacheStrategy( DiskCacheStrategy.SOURCE ).into( imageView ) ;
(2) DiskCacheStrategy.RESULT : 只緩存了一張圖片,大小:14 KB
Glide.with( Activity2.this).load( url ).diskCacheStrategy( DiskCacheStrategy.RESULT ).into( imageView ) ;
(3) DiskCacheStrategy.ALL : 緩存了兩張圖片, 一張大小:2 M , 一張大小:14 KB
Glide.with( Activity2.this).load( url ).diskCacheStrategy(DiskCacheStrategy.ALL ).into( imageView ) ;
(4) DiskCacheStrategy.NONE : 沒有緩存圖片
Glide.with( Activity2.this).load( url ).diskCacheStrategy(DiskCacheStrategy.NONE ).into( imageView ) ;
7.4、 緩存場景測試
兩個imageView ,一個 100 x 100 , 一個 300 x300 ; 先加載第一張,再加載第二張
- 測試一 : 兩張圖片都在 DiskCacheStrategy.SOURCE 的情況下:
//加載第一張圖 findViewById( R.id.bt1 ).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Glide.with( Activity2.this).load( url ).diskCacheStrategy( DiskCacheStrategy.SOURCE ).into( imageView1 ) ; } }); //加載第二張圖 findViewById( R.id.bt2 ).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Glide.with( Activity2.this).load( url ).diskCacheStrategy( DiskCacheStrategy.SOURCE ).into( imageView2 ) ; } });
通過測試發現,在加載第一張圖片的時候,緩存了2M 的原始圖,在加載第二張的時候,就不會再請求網絡,直接從緩存中加載。
- 測試二:第一張圖在 DiskCacheStrategy.SOURCE ,第二張在DiskCacheStrategy.RESULT 情況下
//加載第一張圖 findViewById( R.id.bt1 ).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Glide.with( Activity2.this).load( url ).diskCacheStrategy( DiskCacheStrategy.SOURCE ).into( imageView1 ) ; } }); //加載第二張圖 findViewById( R.id.bt2 ).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Glide.with( Activity2.this).load( url ).diskCacheStrategy( DiskCacheStrategy.RESULT ).into( imageView2 ) ; } });
通過測試發現,加載第一張圖片的情況下,緩存了2M 的原始圖。在加載第二張圖片的時候,又請求網絡,下載了 14 KB 的緩存。這說明,即使本地存在緩存,緩存策略不一樣,緩存就不會被重用。
- 測試三:兩張圖都在 DiskCacheStrategy.RESULT 情況下 ,第一個Imageview大小: 100 x100 , 第二個imageview大小:300 x 300
(1)先加載 100 x 100 , 加載出來后,緩存了 2 kB 的圖片 ,然后加載 300 x 300 ,又重新請求網絡,緩存了 14 KB 的圖片 。緩存沒有復用。
(2)先加載 300 x 300 , 加載出來后,緩存了 14 KB的圖片。然后加載 100 x 100 ,又重新請求網絡,緩存了 2 KB 的圖片,緩存沒有復用。
//加載第一張圖 findViewById( R.id.bt1 ).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Glide.with( Activity2.this).load( url ).diskCacheStrategy( DiskCacheStrategy.RESULT ).into( imageView1 ) ; } }); //加載第二張圖 findViewById( R.id.bt2 ).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Glide.with( Activity2.this).load( url ).diskCacheStrategy( DiskCacheStrategy.RESULT ).into( imageView2 ) ; } });
- 測試四:imageView1 寬高:100 x 100 ; imageView2 寬高:300 x 300 ; imageView3 寬高:600 x 600
//加載第二張圖 findViewById( R.id.bt1 ).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Glide.with( Activity2.this).load( url ).into( imageView1 ) ; } }); //加載第二張圖 findViewById( R.id.bt2 ).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Glide.with( Activity2.this).load( url ).diskCacheStrategy( DiskCacheStrategy.ALL ).into( imageView2 ) ; } }); //加載第三張圖 findViewById( R.id.bt3 ).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Glide.with( Activity2.this).load( url ).into( imageView3 ) ; } });
先加載 imageView2 ,請求網絡, 緩存策略是 DiskCacheStrategy.ALL , 緩存了兩張圖 , 一張是 2 M , 一張是14 kB 。
再加載 imageView1 , 請求網絡,緩存策略是 DiskCacheStrategy.RESULT ,緩存了一張圖,2 kB 。可見 imageview2 的緩存對image1不起作用。
最后加載 imageView3 , 請求網絡,緩存策略是 DiskCacheStrategy.RESULT , 緩存了一張圖, 47 KB , 可見 imageview1 和 imageview2的緩存對imageView3 不起作用
- 測試五:SimpleTarget 的使用 , imageview 大小:300 x 300 ; 網絡圖片 寬高:3000 x 2000 大小:2 .15 M ;
(1) 這種情況的緩存 2 M
Glide.with( Activity2.this).load( url ).diskCacheStrategy( DiskCacheStrategy.SOURCE ).into( imageView2 ) ;
(2)這種情況的緩存 14 KB
Glide.with( Activity2.this).load( url ).diskCacheStrategy( DiskCacheStrategy.RESULT ).into( imageView2 ) ;
(3)這種情況的緩存 777 KB
package app.zuil.com.glidedemo; import android.graphics.Bitmap; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.ImageView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.request.animation.GlideAnimation; import com.bumptech.glide.request.target.SimpleTarget; public class Activity2 extends AppCompatActivity { String url = "http://o7rvuansr.bkt.clouddn.com/big1.jpg" ; ImageView imageView2 ; private SimpleTarget target ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity1); imageView2 = (ImageView) findViewById( R.id.image2 ); //加載第二張圖 findViewById( R.id.bt2 ).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Glide.with( Activity2.this).load( url ).asBitmap().diskCacheStrategy( DiskCacheStrategy.RESULT ).into( target ) ; } }); target = new SimpleTarget<Bitmap>() { @Override public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) { //圖片加載完成 imageView2.setImageBitmap( bitmap ); } }; } }
(4)這種緩存 67 KB
package app.zuil.com.glidedemo; import android.graphics.Bitmap; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.request.animation.GlideAnimation; import com.bumptech.glide.request.target.SimpleTarget; public class Activity2 extends AppCompatActivity { String url = "http://o7rvuansr.bkt.clouddn.com/big1.jpg" ; ImageView imageView2 ; private static int width ; private static int height ; private SimpleTarget target ; private ViewGroup.LayoutParams params ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity1); imageView2 = (ImageView) findViewById( R.id.image2 ); params = imageView2.getLayoutParams() ; //測量圖片的寬高 width = params.width ; height = params.height ; //加載第二張圖 findViewById( R.id.bt2 ).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Glide.with( Activity2.this).load( url ).asBitmap().diskCacheStrategy( DiskCacheStrategy.RESULT ).into( target ) ; } }); target = new SimpleTarget<Bitmap>( width , height ) { @Override public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) { //圖片加載完成 imageView2.setImageBitmap(bitmap); } }; } }
- 測試六:以上的測試都是在兩個imageView 大小不一樣的情況下。現在來測試 兩個imageview大小相同的時候。 imageview1 , 寬高: 400 x 400 ; imageview2 , 寬高:400 x 400
Glide.with( Activity2.this).load( url ).diskCacheStrategy( DiskCacheStrategy.ALL ).into( imageView1 ) ; Glide.with( Activity2.this).load( url ).into( imageView2 ) ;
(1)分析 imageView1 , 采用 DiskCacheStrategy.ALL ; imageView2 , 采用默認的緩存策略,也就是 DiskCacheStrategy.RESULT 。
(2)先加載 imageview1 , 緩存了2個文件,一個是2 M , 一個事 22 KB ; 再加載 imageview2 , 發現沒有請求網絡 , 直接使用了imageview1 的緩存。
(3)先加載 imageview2 ,緩存了1個文件,22 KB ; 然后再加載 imageview1 ,發現沒有請求網絡,直接使用imageview2 的緩存。而且在緩存文件夾中一直只有1個22 KB 緩存,這時候我們就發現,即使 imageview1 的緩存模式是 DiskCacheStrategy.ALL ,在這里似乎緩存原圖的功能失效了。
- 測試七: imageview1 , 寬高: 400 x 400 ; imageview2 , 寬高:400 x 400
Glide.with( Activity2.this).load( url ).diskCacheStrategy( DiskCacheStrategy.SOURCE ).into( imageView1 ) ; Glide.with( Activity2.this).load( url ).into( imageView2 ) ;
(1)先加載 imageview1 , 緩存了 1個文件 , 2M ; 然后再加載 imageview2 , 發現沒有請求網絡,直接使用 imageview1 的緩存。兩個圖片完全加載出來,緩存文件夾 一共只有 1個文件 , 2M ;
(2) 先加載 Imageview2 , 緩存了 1個文件 , 22 KB ; 然后再加載 imageview1 , 發現沒有請求網咯, 直接用 imageview2 的緩存。兩個圖片完全加載出來,緩存文件夾一共只有 1 個文件 , 22 KB 。
博客中的代碼示例都在 https://github.com/zyj1609wz/GlideDemo