1. 程式人生 > >Android開發中使用Glide V4 中Generated API特性

Android開發中使用Glide V4 中Generated API特性

Android Glide4 非同步圖片框架

實戰專案案例

Google在2013年釋出了網路文字和圖片非同步載入的Volley框架,而在2014年的Google IO app中推舉Glide框架來載入圖片。這說明,Glide比起Volley中ImageRequst更具備優勢,節省記憶體和節省寬頻資料。

這裡,Volley框架和Glide框架用載入同樣的網路資源,進行比較了一番。

RecyclerView中使用Volley的NetWorkImageView的記憶體情況:

這裡寫圖片描述

RecyclerView中ImageView使用Glide的記憶體情況:

這裡寫圖片描述

使用Glide v4中的Generated API 開發

前期配置,在專案中Gradle中引入庫的依賴

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support:design:25.3.1'
    compile 'com.android.support:recyclerview-v7:25.3.1'

    //Glide框架引入
compile 'com.github.bumptech.glide:glide:4.0.0-RC0' annotationProcessor 'com.github.bumptech.glide:compiler:4.0.0-RC0' }

自定義AppGlideModule

為運用程式定義一個帶有@GlideModule註解的AppGlideModule,運用程式會使用和AppGlideMoudle同一個包下的GlideApp類。通過GlideApp.with()方式使用Glide的Generated API。

@GlideModule
public final class
CustomAppGlideModule extends AppGlideModule{
/** * 通過GlideBuilder設定預設的結構(Engine,BitmapPool ,ArrayPool,MemoryCache等等). * @param context * @param builder */ @Override public void applyOptions(Context context, GlideBuilder builder) { //重新設定記憶體限制 builder.setMemoryCache(new LruResourceCache(10*1024*1024)); } /** * 為App註冊一個自定義的String型別的BaseGlideUrlLoader * * @param context * @param registry */ @Override public void registerComponents(Context context, Registry registry) { registry.append(String.class, InputStream.class,new CustomBaseGlideUrlLoader.Factory()); } /** * 清單解析的開啟 * * 這裡不開啟,避免新增相同的modules兩次 * @return */ @Override public boolean isManifestParsingEnabled() { return false; } }

注意點

  1. 必需帶有@GlideModule註解。
  2. isManifestParsingEnabled() 返回false,關閉解析AndroidManifest,不需要再配置GlideModule.

自定義BaseGlideUrlLoader

根據帶有圖片尺寸的URl,來獲取合適比例的圖片資源。通過指定String型別的Model, BaseGliUrlLOader中getgetURL()來覆蓋原本的帶有http或者htpps的URL. 這裡處理方式來源於,Google IO App.

public class CustomBaseGlideUrlLoader extends BaseGlideUrlLoader<String> {

    private static final ModelCache<String, GlideUrl> urlCache =
            new ModelCache<>(150);
    /**
     * Url的匹配規則
     */
    private static final Pattern PATTERN = Pattern.compile("__w-((?:-?\\d+)+)__");

    public CustomBaseGlideUrlLoader(ModelLoader<GlideUrl, InputStream> concreteLoader,ModelCache<String, GlideUrl> modelCache) {
        super(concreteLoader,modelCache);
    }

    /**
     * If the URL contains a special variable width indicator (eg "__w-200-400-800__")
     * we get the buckets from the URL (200, 400 and 800 in the example) and replace
     * the URL with the best bucket for the requested width (the bucket immediately
     * larger than the requested width).
     *
     * 控制載入的圖片的大小
     */
    @Override
    protected String getUrl(String model, int width, int height, Options options) {
        Matcher m = PATTERN.matcher(model);
        int bestBucket = 0;
        if (m.find()) {
            String[] found = m.group(1).split("-");
            for (String bucketStr : found) {
                bestBucket = Integer.parseInt(bucketStr);
                if (bestBucket >= width) {
                    // the best bucket is the first immediately bigger than the requested width
                    break;
                }
            }
            if (bestBucket > 0) {
                model = m.replaceFirst("w"+bestBucket);
            }
        }
        return model;
    }

    @Override
    public boolean handles(String s) {
        return true;
    }

    /**
     * 工廠來構建CustormBaseGlideUrlLoader物件
     */
    public static class Factory implements ModelLoaderFactory<String,InputStream>{
        @Override
        public ModelLoader<String, InputStream> build(MultiModelLoaderFactory multiFactory) {
            return new CustomBaseGlideUrlLoader(multiFactory.build(GlideUrl.class,InputStream.class),urlCache);
        }

        @Override
        public void teardown() {

        }
    }
}

ProGuard Rules中新增混淆規則

根據上面的自定義,保持AppGlideModule子類和GlideModule實現類不被混淆。

#Glide的混淆規則
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.AppGlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
    **[] $VALUES;
    public *;
}

使用許可權 : 聯網許可權,讀寫許可權,AndroidManifest.xml中自行配置。

確保GlideApp類正常引用

當配置完以上步驟後,發覺不能使用GlideApp類。

解決方式:在AndroidStudio中Build–>Make Project

–>將會出現build/generated/source中,便可以使用GlideApp

使用GlideApp類用於各種場景

1. 單個ImageView載入影象資源

Url:https://www.baidu.com/img/bd_logo1.png

Uri:content://media/external/images/1

Resource Id :R.drawable.image或者R.mipmap.ic_launcher

當然,還有其他的影象資源。

載入本地圖片

    /**
     * 載入本地圖片,這裡是mipmap資料夾下的資源
     */
    private void loadLocalImage() {
        RequestBuilder<Drawable> drawableRequestBuilder = GlideApp.with(this).load(R.mipmap.ic_launcher);
        drawableRequestBuilder.into(this.local_iv);
    }

載入網路圖片

    /**
     * 從遠端網路上載入圖片
     */
    private void loadRemoteImage() {
        GlideApp.with(this).asBitmap()
        .load(ImageResouce.imageResource[0])
        .error(R.mipmap.ic_launcher)//佔位圖片
        .placeholder(R.mipmap.ic_launcher)//異常圖片
        .into(this.remote_iv);
    }

預先下載,本地快取中載入

    /**
     * 預先載入資源
     */
    private void startPreload() {
        GlideApp.with(this).asBitmap()
                .load(ImageResouce.imageResource[1])
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .preload();
    }

    /**
     * 預先下載原始圖片資源後,本地載入
     */
    private void loadPreloadImage() {
        GlideApp.with(this).asBitmap().load(ImageResouce.imageResource[1]).diskCacheStrategy(DiskCacheStrategy.ALL).into(this.preload_iv);
    }

error 和placeholder的處理

    .error(R.mipmap.ic_launcher) //異常圖片
    .placeholder(R.mipmap.ic_launcher) //佔位圖片
    .fallback(R.mipmap.ic_launcher); //當url為空時,回撥顯示的圖片

2. RecyclerView(或者ListView,GridView)中載入圖片資源

Glide單一要求是任何重複使用的View Target,呼叫Clear()API明確清除先前的載入,以防載入到舊資料。

@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {

        ImageView imageView=holder.getImageView();
         String url=imageList.get(position);

        if(TextUtils.isEmpty(url)){
            //清空舊資料的引用
            GlideApp.with(context).clear(imageView);
            //當資源為空時候,設定預設圖片
            imageView.setImageResource(R.mipmap.ic_launcher);
        }else{//開啟一個圖片載入
            loadImage(url,imageView);
        }
}
    /**
     * 載入圖片
     * @param url
     * @param imageView
     */
public void loadImage(String url,ImageView imageView){

       RequestBuilder<Bitmap> bitmapRequestBuilder= GlideApp.with(context)
               .asBitmap()//指定Bitmap型別的RequestBuilder
               .load(url)//網路URL
               .error(R.mipmap.ic_launcher)//異常圖片
               .placeholder(R.mipmap.ic_launcher)//佔位圖片
               .fallback(R.mipmap.ic_launcher);//當url為空時,顯示圖片

        bitmapRequestBuilder.into(imageView);
}

3. 自定義Circle Transformation 實現圓角圖片

Glide擁有兩個預設的轉換(transformation):

  • Fit center:類似Android’s ScaleType.FIT_CENTER
  • Center crop:類似Android’s ScaleType.CENTER_CROP

這裡繼承BitmapTransformation,複寫transform()

public class CircleTransform extends BitmapTransformation{

    public CircleTransform(Context context){
        super(context);
    }
    /**
     *  重寫 生成圓角圖片
     * @param pool
     * @param toTransform
     * @param outWidth
     * @param outHeight
     * @return
     */
    @Override
    protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
        return circleCrop(pool,toTransform);
    }

    private static Bitmap circleCrop(BitmapPool pool, Bitmap source) {
        if (source == null) return null;

        int size = Math.min(source.getWidth(), source.getHeight());
        int x = (source.getWidth() - size) / 2;
        int y = (source.getHeight() - size) / 2;

        Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);

        Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);
        if (result == null) {
            result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
        }

        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        //畫布中背景圖片與繪製圖片交集部分
        paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
        paint.setAntiAlias(true);
        float r = size / 2f;
        canvas.drawCircle(r, r, r, paint);
        return result;
    }

    @Override
    public void updateDiskCacheKey(MessageDigest messageDigest) {
    }
}

Glide使用自定義的Transform,最後將圓形Bitmap載入到ImageView上:


    /**
     * 載入圖片
     * @param url
     * @param imageView
     */
    public void loadImage(String url,ImageView imageView){

       RequestBuilder<Bitmap> bitmapRequestBuilder= GlideApp.with(context)
               .asBitmap()//指定Bitmap型別的RequestBuilder
               .load(url)//網路URL
               .error(R.mipmap.ic_launcher)//異常圖片
               .placeholder(R.mipmap.ic_launcher)//佔位圖片
               .fallback(R.mipmap.ic_launcher);//當url為空時,顯示圖片

        RequestOptions requestOptions=new RequestOptions();
        //在RequestOptions中使用Transformations
        requestOptions.transform(new CircleTransform(context));

        //RequestBuilder<Bitmap> 中新增RequestOptions
        bitmapRequestBuilder.apply(requestOptions).into(imageView);
    }

4. 自定義BitmapImageViewTarget實現圓角圖片

自定義一個BitmapImageViewTarget,複寫setResource():

public class CircularBitmapImageViewTarget  extends BitmapImageViewTarget {
    private Context context;
    private ImageView imageView;
    public CircularBitmapImageViewTarget(Context context,ImageView view) {
        super(view);
        this.context=context;
        this.imageView=view;
    }
    /**
     * 重寫 setResource(),生成圓角的圖片
     * @param resource
     */
    @Override
    protected void setResource(Bitmap resource) {
        RoundedBitmapDrawable  bitmapDrawable= RoundedBitmapDrawableFactory.create(this.context.getResources(),resource);
        /**
         *   設定圖片的shape為圓形.
         *
         *   若是需要制定圓角的度數,則呼叫setCornerRadius()。
         */
        bitmapDrawable.setCircular(true);
        this.imageView.setImageDrawable(bitmapDrawable);
    }
}

Glide使用自定義ViewTarget:

    /**
     * 載入圖片
     * @param url
     * @param imageView
     */
    public void loadImage(String url,ImageView imageView){

       RequestBuilder<Bitmap> bitmapRequestBuilder= GlideApp.with(context)
               .asBitmap()//指定Bitmap型別的RequestBuilder
               .load(url)//網路URL
               .error(R.mipmap.ic_launcher)//異常圖片
               .placeholder(R.mipmap.ic_launcher)//佔位圖片
               .fallback(R.mipmap.ic_launcher);//當url為空時,顯示圖片

       //在RequestBuilder<Bitmap> 中使用自定義的ImageViewTarget
       bitmapRequestBuilder.into(new CircularBitmapImageViewTarget(context,imageView));        
    }

專案執行效果如下

這裡寫圖片描述

資源彙總

問題彙總:

  • 在listView或者RecyclerView中使用Glide框架,記憶體劇增或者爆記憶體溢位(OutOfMemoryError):

    這裡寫圖片描述

    原因:在ImageView中scaleType使用了fitxy屬性:

    <ImageView
        android:id="@+id/item_movielist_iv"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:scaleType="fitXY"/>

    將fitXY改動成:fitCenter 或者centerCrop,記憶體情況如下:

    這裡寫圖片描述

  • 解決同一URL遠端圖片,多次按不同大小比例載入多次載入的問題:

    Preload Images,將URL對應的資料來源即原圖儲存下載,下次按比例來本地載入:

    diskCacheStrategy(DiskCacheStrategy.ALL)

相關推薦

Android開發使用Glide V4 Generated API特性

Android Glide4 非同步圖片框架 實戰專案案例 Google在2013年釋出了網路文字和圖片非同步載入的Volley框架,而在2014年的Google IO app中推舉Glide框架來載入圖片。這說明,Glide比起Volley中I

android開發之在activity控制另一個activity的UI更新

第一種方法: 遇到一個問題,需要在一個activity中控制另一個acitivity做一些更新,沒想到傳遞handler的方法,通過以下方式解決。 1.在MyAPP中定義屬性handler package jason.com; import jason.com.MasterAc

android開發post請求引數有陣列引數

用了接近兩天終於完美找到方法!!! 話說,訪問伺服器一般用get請求,在url中拼接引數即可;或者post請求json物件也好呀,這次的介面可神奇了—— post方式訪問+請求引數為字串和陣列(數組裡面暫時只有一個物件)! android主流網路請求框架有:okhttp

Android開發:在onTouchEvent處理任意時間的長按事件

Android提供了GestureDetector類來處理一些常用的手勢操作,比如說 onLongPress,onFling 等。但這裡不使用GestureDetector,而是直接在自定義View

Android開發技巧——去掉TextViewautolink的下劃線

我們知道,在佈局檔案中設定textview的autolink及其型別,這時textivew上會顯示link的顏色,並且文字下面會有一條下劃線,表示可以點選。而在我們在點選textview時,應用將根據我們所設定的型別跳轉到對應的介面。但是有時,我們因介面需求,需要去掉介面上

Android開發時在windows輸入adb shell提示不是內部或外部命令

在android開發中,有時候要用到入adb shell命令, 用於電腦cmd終端連線android手機。然而很多人在使用過程中,遇到在cmd中輸入adb shell提示不是內部或外部命令等現象。 這個問題一般有兩種可能:   1.就是沒有配置環境變數, 這個只需要

Android開發技巧】Fragment獲取Context物件的兩種方法

我們在使用Fragment的時候經常需要傳遞Context型別的引數,【Android用的比較多的就是下面幾個導航按鈕,點選切換fragment(之前Android studio2.0以前是可以new fragment(context)時傳遞Context,但後來升級了studio2.1.2之後,new

Android開發之在xml設定自定義屬性

xml中設定自定義屬性 分三步: 1. 在專案中的values檔案中建立attrs檔案 <?xml version="1.0" encoding="utf-8"?> <resourc

Android開發,在Fragment,隱藏或關閉軟鍵盤(虛擬鍵盤)的方法

網上可以搜到各種方法,實際測試中,我的開發用機中,僅僅下面這個方法有效,記錄一下。   //隱藏虛擬鍵盤      public static void HideKeyboard(View v) 

Android開發:在ListView使用RadioGroup時出現混亂選中現象

重寫Adapter的getView方法(); 設定每個item中RadioGroup的監聽器(viewHolder.answerRg.setOnCheckedChangeListener()),每RadioGroup中有四個radiobutton表示A,B,C,D。

Android開發之--從app跳轉到淘寶店鋪

首先、一個工具類   方法,檢測該包名下的應用是否存在 public static boolean checkPackage(Context context ,String packageName) { if (packageName == null || "".

android開發 在JNI函式引用Java類,將cxx複雜資料轉換成jobjectArray,實現從JNI到Java的資料傳輸

引言: JNI是Java可以呼叫高效的c++程式碼,但是在JNI函式中傳遞複雜資料型別十分的繁瑣,一般情況下需要jobject作為中轉,一維陣列int[],float[]以及二維陣列String[]可以實現方便的引數傳入/傳出。其他複雜的二、三維陣列理論上可以

Android 隨手記:Android開發在一個Activity關閉另一個Activity

比如有ActivityA, ActivityB,在ActivityB中關閉ActivityA 解決方案: 1. 在 ActivityA 裡面設定一個靜態的變數instance,初始化為this

Android開發實用API介面(一)

1、Throwable介面中的getStackTrace()方法(或者Thread類的getStackTrace()方法),根據這個方法可以得到函式的逐層呼叫地址,其返回值為StackTraceElement[]; 2、StackTraceElement類,其中四個方法getClassName(),g

Android應用開發如何使用隱藏的API

        Android應用中有時為了實現某些特殊的功能或效果,往往需要使用一些谷歌隱藏的API(加有@hide標記的public類、方法或常量),例如PolicyManager。         使用Android隱藏的API主要有兩種辦法:1.利用Java反射機制

Android開發,使用WIFI API時的兩個陷阱(第一篇,共二篇)

一、版本適配問題。在Android6.0上,APP無法更新系統儲存過的、不是由當前APP建立的WIFI配置。 1、現象:     在測試過程中,發現了一個bug。場景是:在Android6.0的機器上,連線一個系統儲存過的wifi,輸入了正確的密碼後,卻始終

android 開發常用的第三方庫(圖片載入篇——Glide

目錄 目錄 1. 簡介 介紹:Glide,是Android中一個圖片載入開源庫Google的開源專案 主要作用:實現圖片載入 2. 功能特點 2.1 功能列表 功能列表 從上面可以看出,Glide不僅實現了圖片非同步載入的功能,還解決了Android中載入圖片時需要解決的一些常見問題 接下來,我會對

Android開發有用工具之--Log工具類

util lena 日誌 日誌信息 stat 們的 常常 我們 imp 在開發的過程中。我們常常會使用Log來輸出日誌,幫助我們來調試程序 可是有時候並不能全然滿足我們的須要 ,比方我想知道這個日誌信息是來自於哪一個包 哪一個類 所以我們封裝一個這個Log類。方便我們的

在混合app開發過程使用百度地圖api的出現坐標偏差的解決

百度 api call cordova overlay forum gpo ext ddr 在項目中使用ngCordova的$cordovaGeolocation模塊獲取當前位置經緯度,當展示在百度地圖中時發現有誤差(我的測試誤差為1.7公裏左右),查資料發現百度地圖經緯度

Android學習探索之Java 8 在Android 開發的應用

相關 概念 容易 並不是 min etc bstr trac flavor 前言: Java 8推出已經將近2年多了,引入很多革命性變化,加入了函數式編程的特征,使基於行為的編程成為可能,同時減化了各種設計模式的實現方式,是Java有史以來最重要的更新。但是Androi