【Android - 框架】之Glide的使用


一、Glide簡介:

  Glide是Google官方推薦的一個圖片加載和緩存的開源庫,它不僅能實現平滑的圖片列表滾動效果,還支持遠程圖片的獲取、大小調整和展示,並且可以加載GIF圖片。Glide相比與UIF、Volley、Picasso、Fresco等其他框架的優點是輕量和穩定。

 

二、Glide的配置:

  使用Glide首先需要導入Glide的依賴,在build.gradle文件中添加:

compile 'com.github.bumptech.glide:glide:3.7.0'

  如果Glide需要從網絡中加載圖片,則還需要在Manifest文件中添加網絡訪問權限:

<uses-permission android:name="android.permission.INTERNET" />

  Glide為我們提供了一個GlideModule接口,其中提供了一系列Glide配置的抽象方法,我們可以創建一個類實現這個接口,並在實現的方法中設置Glide的一些配置項,如自定義緩存大小和位置、自定義內存和圖片池大小、自定義圖片格式等。一個GlideModule的實現類樣板如下:

public class GlideConfig implements GlideModule {
    int diskSize = 1024 * 1024 * 100;
    int memorySize = (int) (Runtime.getRuntime().maxMemory()) / 8;  // 取1/8最大內存作為最大緩存

    @Override
    public void applyOptions(Context context, GlideBuilder builder) {
        // 定義緩存大小和位置
        builder.setDiskCache(new InternalCacheDiskCacheFactory(context, diskSize));  // 內存中
        // builder.setDiskCache(new ExternalCacheDiskCacheFactory(context, "cache", diskSize)); // sd卡中

        // 默認內存和圖片池大小
        // MemorySizeCalculator calculator = new MemorySizeCalculator(context);
        // int defaultMemoryCacheSize = calculator.getMemoryCacheSize(); // 默認內存大小
        // int defaultBitmapPoolSize = calculator.getBitmapPoolSize(); // 默認圖片池大小
        // builder.setMemoryCache(new LruResourceCache(defaultMemoryCacheSize));
        // builder.setBitmapPool(new LruBitmapPool(defaultBitmapPoolSize));

        // 自定義內存和圖片池大小
        builder.setMemoryCache(new LruResourceCache(memorySize)); // 自定義內存大小
        builder.setBitmapPool(new LruBitmapPool(memorySize)); // 自定義圖片池大小

        // 定義圖片格式
        // builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
        builder.setDecodeFormat(DecodeFormat.PREFER_RGB_565); // 默認
    }

    @Override
    public void registerComponents(Context context, Glide glide) {
    }
}

  GlideConfig類完成之后,我們需要在Manifest文件中注冊這個類,便於Glide找到這個類並進行初始化配置。在Manifest的<application>標簽下添加一個<meta-data>標簽,在其中注冊這個類:

        <!-- 注冊Glide的配置文件,以便Glide能夠找到 -->
        <meta-data
            android:name="com.example.itgungnir.testglide.GlideConfig"
            android:value="GlideModule" />

  到此為止,Glide的基礎配置就完成了。

 

三、Glide的使用:

  Glide中的常用方法如下:

 .with() 圖片加載的環境:1,Context對象。2,Activity對象。3,FragmentActivity對象。4,Fragment對象
 .load() 加載資源:1,drawable資源。2,本地File文件。3,uri。4,網絡圖片url。5,byte數組(可以直接加載GIF圖片)
 .placeholder() 圖片占位符
 .error() 圖片加載失敗時顯示
 .crossFade() 顯示圖片時執行淡入淡出的動畫默認300ms
 .dontAnimate() 不執行顯示圖片時的動畫
 .override() 設置圖片的大小
 .centerCrop() 和 fitCenter() 圖片的顯示方式
 .animate() view動畫 2個重構方法
 .transform() bitmap轉換
 .bitmapTransform() bitmap轉換。比如旋轉,放大縮小,高斯模糊等(當用了轉換后你就不能使用.centerCrop()或.fitCenter()了。)
 .priority(Priority.HIGH) 當前線程的優先級
 .signature(new StringSignature(“ssss”))
 .thumbnail(0.1f) 縮略圖,3個重構方法:優先顯示原始圖片的百分比(10%)
 .listener() 異常監聽
 .into() 圖片加載完成后進行的處理:1,ImageView對象。2,寬高值。3,Target對象

  我們用以下兩個地址來完成Glide框架的測試,兩個地址都是網絡圖片的URL地址,一個是靜態圖片的地址,另一個是GIF圖片的地址:

    private static final String IMAGE_STATIC_URL = "http://download.pchome.net/wallpaper/pic-2532-1.jpg"; // 靜態圖片
    private static final String IMAGE_GIF_URL = "http://img1.gamedog.cn/2013/06/22/43-1306220944560.gif"; // GIF圖片

1、Glide的基本用法:

        Glide.with(MainActivity.this) // 在MainActivity中調用Glide的API
                .load(IMAGE_STATIC_URL) // 加載網絡中的靜態圖片
                .placeholder(R.mipmap.ic_launcher) // 在圖片沒有加載出來或加載失敗時顯示ic_launcher圖片
                .into(iv); // 將圖片加載到一個ImageView對象中

  .with()方法中的參數可以有四種類型;.load()方法中的參數可以有五種類型,這里就不多說了,在上面都有,這里重點說一下.into()方法。.into()方法中的參數有三種類型:

  可以是一個ImageView對象,表示圖片加載完成之后直接放到ImageView中進行展示,如上面的代碼。

  可以是一個寬度值和一個高度值,指定期望得到的圖片的寬高值,返回一個GlideDrawable對象。這個方法必須在子線程中進行,具體原因有待研究。貼上代碼:

        final Handler glideHanlder = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                if (msg.what == 1) {
                    GlideDrawable glideDrawable = (GlideDrawable) msg.obj;
                    iv.setImageDrawable(glideDrawable);
                }
            }
        };
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    GlideDrawable glideDrawable = Glide.with(MainActivity.this) // 在MainActivity中調用Glide的API
                            .load(IMAGE_STATIC_URL) // 加載網絡中的靜態圖片
                            .placeholder(R.mipmap.ic_launcher) // 在圖片沒有加載出來或加載失敗時顯示ic_launcher圖片
                            .into(200, 400) // 設置期望得到的圖片的寬高值
                            .get(); // 獲取到GlideDrawable對象
                    Message msg = Message.obtain();
                    msg.what = 1;
                    msg.obj = glideDrawable;
                    glideHanlder.sendMessage(msg);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
        }).start();

  也可以是一個Target接口、Target接口的子類或實現類,可以有如下圖所示的選項:

  使用不同的類或接口作為參數,根據回調的方法進行操作即可。這里貼出使用SimpleTarget的代碼:

        Glide.with(MainActivity.this) // 在MainActivity中調用Glide的API
                .load(IMAGE_STATIC_URL) // 加載網絡中的靜態圖片
                .into(new SimpleTarget<GlideDrawable>() { // 圖片加載回調的Target實現類
                    @Override
                    public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
                        // 圖片加載成功時回調的方法
                        iv.setImageDrawable(resource);
                    }
                });

 

2、其他方法解釋:

.asBitmap()和.asGif()

  如果調用了.asBitmap()方法,則.load()中的參數指向的可以是一個靜態圖片也可以是GIF圖片,如果是一張GIF圖片,則加載之后只會展示GIF圖片的第一幀

  如果調用的.asGif()方法,則.load()方法中的參數指向的必須是一個GIF圖片,如果是一張靜態圖片,則圖片加載完成之后展示的只是圖片占位符(如果沒有設置圖片占位符,則什么也不展示)

  這兩個方法中只能調用一個,調用了其中一個方法之后,代碼提示就不會提示另一個了。代碼:

        Glide.with(MainActivity.this) // 在MainActivity中調用Glide的API
                .load(IMAGE_STATIC_URL) // 加載網絡中的靜態圖片
                .asBitmap() // 將圖片固定成靜態圖片
                .placeholder(R.mipmap.ic_launcher) // 圖片占位符
                .into(iv); // 圖片加載完成后直接放到ImageView對象iv中進行展示

.override()

  這個方法可以設置圖片加載之后展示的寬度值和高度值,前提是目標ImageView的寬度和高度都設置為wrap_content。代碼:

        Glide.with(MainActivity.this) // 在MainActivity中調用Glide的API
                .load(IMAGE_STATIC_URL) // 加載網絡中的靜態圖片
                .override(666, 666) // 設置加載之后的圖片顯示的寬度和高度
                .placeholder(R.mipmap.ic_launcher) // 圖片占位符
                .into(iv); // 圖片加載完成后直接放到ImageView對象iv中進行展示

.thumbnail()

  設置這個方法之后,可以先加載這張圖片的sizeMultiplier倍的縮略圖到目標ImageView中,然后再慢慢加載完整的圖片。sizeMultiplier值的范圍是0~1。代碼:

        Glide.with(MainActivity.this) // 在MainActivity中調用Glide的API
                .load(IMAGE_STATIC_URL) // 加載網絡中的靜態圖片
                .thumbnail(0.1f) // 先加載一定比例的縮略圖
                .placeholder(R.mipmap.ic_launcher) // 圖片占位符
                .into(iv); // 圖片加載完成后直接放到ImageView對象iv中進行展示

.animate()

  加載圖片時展示的動畫,可以是Animator類型的屬性動畫,也可以是int類型的動畫資源。這個動畫只在第一次加載的時候會展示,以后都會從緩存中獲取圖片,因此也就不會展示動畫了。代碼:

        Glide.with(MainActivity.this) // 在MainActivity中調用Glide的API
                .load(IMAGE_STATIC_URL) // 加載網絡中的靜態圖片
                .animate(android.R.anim.slide_in_left) // 圖片加載完成后的動畫效果(從左側滑入)
                .into(iv); // 圖片加載完成后直接放到ImageView對象iv中進行展示

.centerCrop()和.fitCenter()

  如果調用了.centerCrop()方法,則顯示圖片的時候短的一邊填充容器,長的一邊跟隨縮放

  如果調用了.fitCenter()方法,則顯示圖片的時候長的一邊填充容器,短的一邊跟隨縮放

  這兩個方法可以都調用,如果都調用,則最終顯示的效果是后調用的方法展示的效果。代碼:

        Glide.with(MainActivity.this) // 在MainActivity中調用Glide的API
                .load(IMAGE_STATIC_URL) // 加載網絡中的靜態圖片
                .fitCenter() // 長的一邊填充容器
                .centerCrop() // 短的一邊填充容器
                .into(iv); // 圖片加載完成后直接放到ImageView對象iv中進行展示

.bitmapTransform()

  .bitmapTransform()方法中傳入的參數是一組Transformation類型的對象,即轉換器,可以是任意多個。要想使用Glide為我們提供的轉換器,我們需要先在build.gradle文件中導入Glide的Transformations的依賴:

compile 'jp.wasabeef:glide-transformations:1.0.6'

  這個依賴中為我們提供了很多的轉換器,如下:

圓形:CropCircleTransformation
方形:CropSquareTransformation
圓角:RoundedCornersTransformation
顏色覆蓋:ColorFilterTransformation
置灰:GrayscaleTransformation
毛玻璃:BlurTransformation

  使用轉換器的時候直接new就可以了,但是需要傳入一個BitmapPool的對象,我們可以直接傳入一個new的LruBitmapPool。例如,我們想得到一個圓形圖片的轉換器,就可以編寫如下代碼:

        LruBitmapPool pool = new LruBitmapPool((int) (Runtime.getRuntime().maxMemory()) / 8);
        Glide.with(MainActivity.this) // 在MainActivity中調用Glide的API
                .load(IMAGE_STATIC_URL) // 加載網絡中的靜態圖片
                .fitCenter() // 長的一邊填充容器
                .centerCrop() // 短的一邊填充容器
                .bitmapTransform(new CropCircleTransformation(pool)) // 轉換器
                .into(iv); // 圖片加載完成后直接放到ImageView對象iv中進行展示

.resumeRequests()和.pauseRequests()

  這兩個方法是為了保證用戶界面的滑動流暢而設計的。當在ListView中加載圖片的時候,如果用戶滑動ListView的時候繼續加載圖片,就很有可能造成滑動不流暢、卡頓的現象,這是由於Activity需要同時處理滑動事件以及Glide加載圖片。Glide為我們提供了這兩個方法,讓我們可以在ListView等滑動控件滑動的過程中控制Glide停止加載或繼續加載,可以有效的保證界面操作的流暢。

  我們需要在ListView的OnScrollListener中寫這部分的代碼,如下(Adapter中的代碼就不貼出來了):

        // ListView滑動時觸發的事件
        lv.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                switch (scrollState) {
                    case AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
                    case AbsListView.OnScrollListener.SCROLL_STATE_FLING:
                        // 當ListView處於滑動狀態時,停止加載圖片,保證操作界面流暢
                        Glide.with(MainActivity.this).pauseRequests();
                        break;
                    case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
                        // 當ListView處於靜止狀態時,繼續加載圖片
                        Glide.with(MainActivity.this).resumeRequests();
                        break;
                }
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            }
        });

 

四、Glide的原理:

  當Glide調用with()方法時,通過傳入的Context對象獲取一個RequestManager對象。RequestManager類中封裝了一個RequestTracker,RequestTracker中有一個List<Request>集合,用來統一管理Request請求。

  當RequestManager對象調用load()方法時,將參數中的值(String或URL或byte[])封裝成一種ModelType類型的數據存儲到GenericRequestBuilder對象中,並返回一個DrawableRequestBuilder類型的對象(DrawableRequestBuilder是GenericRequestBuilder的子類)。

  當DrawableRequestBuilder對象調用into()方法時,會調用其父類GenericRequestBuilder的obtainRequest()方法,返回一個GenericRequest對象(這個對象是Request接口的一個實現類)。

  GenericRequest對象經過一系列的准備工作之后,調用Engine對象的load()方法開始加載圖片。load()方法的加載流程如下:

     * Check the memory cache and provide the cached resource if present
     * Check the current set of actively used resources and return the active resource if present
     * Check the current set of in progress loads and add the cb to the in progress load if present
     * Start a new load

  正如上面的源碼注釋中介紹的一樣,Glide首先去緩存中尋找圖片(這個緩存就是一個圖片池BitmapPool),如果緩存中有這張圖片,則從緩存資源中取出圖片進行加載;如果緩存中沒有,則從“actively used resources”中找圖片,源碼中的“actively used resources”指的是一個弱引用組成的Map集合,即如果緩存中沒有,就去弱引用中找這張圖片,如果弱引用中有這張圖片則從弱引用中取出來進行加載;如果弱引用中也沒有,則從正在進行的load(Request)中查找有沒有哪個Request正在加載這張圖片,如果有的話就等待這個Request加載完成之后直接拿過來加載;如果還是沒有的話,就只能新開啟一個Request從網絡中獲取了。

  從上面的分析可以看到,Glide加載圖片的方式和三級緩存機制很像,Glide中的緩存BitmapPool就像三級緩存中的強引用LruCache,Glide中也有一個弱引用的集合。唯一不同的是,Glide中對正在進行的請求也做了篩選,保證同一張圖片只建立一個Request進行加載即可。

  這里順便科普一下強引用和弱引用之間的工作流程:強引用是一片固定的空間,使用隊列的形式存儲數據,新來的圖片存到隊尾,這樣可以保證隊尾的永遠都是最新、最后使用的圖片,對頭都是最老、最早使用的圖片。當強引用中的空間存滿的時候,會把對頭的圖片“踢”出來放到弱引用中。我們之所以要使用弱引用,是因為弱引用可以在內存滿了的時候隨時GC,因此通常都會用弱引用作為第二級緩存。

        以上就是對Glide的工作流程的總結,有不對之處還望大家不吝賜教,謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM