天天看點

Android Glide加載圖檔、網絡監聽、設定資源監聽

Glide加載圖檔、加載進度監聽

  • ​​前言​​
  • ​​正文​​
  • ​​一、項目配置​​
  • ​​二、顯示網絡圖檔​​
  • ​​三、添加設定資源監聽​​
  • ​​四、添加設定資源監聽​​
  • ​​五、添加加載進度條​​
  • ​​六、封裝工具類​​
  • ​​七、源碼​​
  • ​​總結​​

前言

  在日常開發中使用url加載圖檔是常見的。這也是Glide圖檔加載架構這麼受歡迎的原因。當然本文如果隻是簡單的加載一個圖檔出來那就完全沒有必要了,自然要搞點花裡胡哨的事情才行。補充知識:Glide (音譯:哥來德)

正文

  再搞事情之前首先建立一個項目,就命名為GlideDemo吧。

Android Glide加載圖檔、網絡監聽、設定資源監聽

一、項目配置

建立好之後,在app子產品下build.gradle的dependencies閉包中添加如下依賴:

//glide
    //glide
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'      

然後Sync同步一下。

之後在res下建立一個xml檔案夾,檔案夾下建立一個network_config.xml檔案,裡面的代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true"      

為什麼要加這個呢?因為在Android9.0以後通路網絡預設使用密文位址,也就是https通路,加上這個就可以通路http了,當然你還需要在AndroidManifest.xml中配置才行。

Android Glide加載圖檔、網絡監聽、設定資源監聽

同時,别忘了添加網絡通路權限,否則你是無法加載網絡url圖檔的。

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

下面進入activity_main.xml中,修改布局如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/iv_bg"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#000"
        android:scaleType="centerCrop"      

二、顯示網絡圖檔

這裡我隻是增加了一個圖檔控件,用于顯示網絡圖檔。

下面進入到MianActivity。

//網絡圖檔URL
    private String imgUrl = "http://cn.bing.com/th?id=OHR.LargestCave_ZH-CN2069899703_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp";
    //圖檔控件
    private ImageView ivBg;      

網絡圖檔是使用必應的圖檔,然後在onCreate中進行配置顯示。

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //綁定id
        ivBg = findViewById(R.id.iv_bg);
        //顯示圖檔
        Glide.with(this).load(imgUrl).into(ivBg);
    }      

下面運作一下,你可以選擇模拟器或者真機。

Android Glide加載圖檔、網絡監聽、設定資源監聽

嗯,這就加載出來了,我相信你平常也是這麼來使用Glide的。

三、添加設定資源監聽

但如果你的圖檔很大,網絡又不是很好的情況下,就會讓使用者有一種不好的體驗,比如,當你在地鐵站裡浏覽資訊時,此時網絡環境很差,你加載圖檔沒有反應,而使用者也無法感覺,此時就會認為你的軟體有問題,是以你應該告訴使用者目前的圖檔加載情況。

加載狀态監聽

private static final String TAG = "MainActivity";      

然後将

Glide.with(this).load(imgUrl).into(ivBg);      

改成

//顯示圖檔
        Glide.with(this).load(imgUrl).into(new ImageViewTarget<Drawable>(ivBg) {
            //圖檔開始加載
            @Override
            public void onLoadStarted(@Nullable Drawable placeholder) {
                super.onLoadStarted(placeholder);
                Log.d(TAG,"圖檔開始加載");
            }

            @Override
            public void onLoadFailed(@Nullable Drawable errorDrawable) {
                super.onLoadFailed(errorDrawable);
                Log.d(TAG,"圖檔加載失敗");
            }

            //圖檔加載完成
            @Override
            public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
                super.onResourceReady(resource, transition);
                // 圖檔加載完成
                ivBg.setImageDrawable(resource);
                Log.d(TAG,"圖檔加載完成");
            }

            @Override
            protected void setResource(@Nullable Drawable resource) {
                Log.d(TAG,"設定資源");
            }
        });      

這裡使用了ImageViewTarget,它裡面傳入ImageView,這裡預設是要你實作一個方法,那就是setResource,不過要是想實作這個狀态的監聽,則還需要實作onLoadStarted、onLoadFailed、onResourceReady這三個方法。現在我在上面列印了日志,下面重新運作一下,待圖檔加載出來之後,看一下日志。

Android Glide加載圖檔、網絡監聽、設定資源監聽

這裡可以看到,這是正常加載的情況,下面你可以把網絡關掉,然後解除安裝剛才安裝的應用,重新安裝。

你會發現關閉網絡之後圖檔确實沒有加載出來,但是日志也沒有看到有失敗的字樣。

這裡你就要多重考慮一下了,因為加載網絡圖檔實際上是分為兩步的,第一步請求網絡資源,第二步緩存資源顯示出來,剛才把網絡關閉了,那麼我們就應該對網絡請求增加監聽才對。

四、添加設定資源監聽

改動代碼如下所示。

//顯示圖檔
        Glide.with(this)
                .load(imgUrl)
                .listener(new RequestListener<Drawable>() {
                    @Override
                    public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
                        Log.d(TAG,"網絡通路失敗,請檢查是否開始網絡或者增加http的通路許可");
                        return false;
                    }

                    @Override
                    public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
                        Log.d(TAG,"網絡通路成功,可以顯示圖檔");
                        return false;
                    }
                })
                .into(new ImageViewTarget<Drawable>(ivBg) {
                    //圖檔開始加載
                    @Override
                    public void onLoadStarted(@Nullable Drawable placeholder) {
                        super.onLoadStarted(placeholder);
                        Log.d(TAG, "圖檔開始加載");
                    }

                    @Override
                    public void onLoadFailed(@Nullable Drawable errorDrawable) {
                        super.onLoadFailed(errorDrawable);
                        Log.d(TAG, "圖檔加載失敗");
                    }

                    //圖檔加載完成
                    @Override
                    public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
                        super.onResourceReady(resource, transition);
                        // 圖檔加載完成
                        ivBg.setImageDrawable(resource);
                        Log.d(TAG, "圖檔加載完成");
                    }

                    @Override
                    protected void setResource(@Nullable Drawable resource) {
                        Log.d(TAG, "設定資源");
                    }
                });      

可以看到我又增加了一個listener,裡面有對網絡通路的傳回,成功和失敗,網絡狀态不好的情況下才會失敗,像剛才我們沒有開始網絡就根本不會發起網絡請求,自然不會有請求的傳回。

下面開啟網絡,運作試一下。

Android Glide加載圖檔、網絡監聽、設定資源監聽

這樣你就完成了加載網絡圖檔是網絡狀态的監聽。

五、添加加載進度條

如果你還想加上一點變化的話可以這樣,修改activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/iv_bg"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#000"
        android:scaleType="centerCrop" />

    <ProgressBar
        android:id="@+id/progressBar"
        android:visibility="gone"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</RelativeLayout>      

這裡我修改了根布局為RelativeLayout ,然後加上了一個ProgressBar,它預設是隐藏的,下面回到MainActivity中。

//進度條
    private ProgressBar progressBar;      

然後在onCreate中

= findViewById(R.id.progressBar);      

然後在圖檔設定資源時,開始時顯示加載進度條,完成時隐藏進度條然後顯示圖檔。

Android Glide加載圖檔、網絡監聽、設定資源監聽

運作的效果就像下面這樣。

Android Glide加載圖檔、網絡監聽、設定資源監聽

當然這個加載速度取決于你的網速,快的話就是一閃而過。

現在你回頭看這個Glide的加載,如果要同時滿足網絡加載和圖檔資源設定的監聽,代碼量就會比較多,如果我一個頁面有多個地方要加載網絡圖檔呢?我總不能寫這麼多重複的代碼吧。是以我們可以寫一個工具類來幫助我們做這一步。

六、封裝工具類

建立一個GlideUtil類。

在裡面寫入如下代碼。

/**
 * Glide工具類
 * @author llw
 */
public class GlideUtil {
    //上下文
    private static Context context;


    public static void init(Context context) {
        GlideUtil.context = context;
    }

    /**
     * 顯示網絡Url圖檔
     * @param url
     * @param imageView
     */
    public static void loadImg(String url, ImageView imageView) {
        Glide.with(context).load(url).into(imageView);
    }

    /**
     * 顯示資源圖檔
     * @param recourseId 資源圖檔
     * @param imageView
     */
    public static void loadImg(Integer recourseId, ImageView imageView) {
        Glide.with(context).load(recourseId).into(imageView);
    }

    /**
     * 顯示bitmap圖檔
     * @param bitmap
     * @param imageView
     */
    public static void loadImg(Bitmap bitmap, ImageView imageView) {
        Glide.with(context).load(bitmap).into(imageView);
    }

    /**
     * 顯示drawable圖檔
     * @param drawable
     * @param imageView
     */
    public static void loadImg(Drawable drawable, ImageView imageView) {
        Glide.with(context).load(drawable).into(imageView);
    }
}      

目前這個代碼很簡單,通過init方法擷取上下文,然後通過多參數方法來顯示圖檔,當然這個可以根據實際需求來進行增減,這樣寫其實就減少了一步操作,可以在程式初始化的時候擷取應用的上下文即可,你應該知道是什麼了,沒錯就是Application,你如果不自己寫則會使用預設的,但日常開發中都會自己自定義一個Application,在裡面完成一些應用的初始化配置,比如資料庫的建立,一個資源庫的初始化。

下面建立一個MyApplication,然後內建Application,重寫onCreate方法,在裡面通過GildeUtil的init方法擷取上下文。

/**
 * 自定義應用
 * @author llw
 */
public class MyApplication extends Application {
    
    @Override
    public void onCreate() {
        super.onCreate();
        GlideUtil.init(this);
    }
}      

然後你還需要到AndroidManifest.xml的application标簽下進行配置,如下圖所示:

Android Glide加載圖檔、網絡監聽、設定資源監聽

下面你就可以使用這個工具類來加載圖檔了。

修改MainActivity中onCreate中的代碼。

//顯示圖檔
    loadImg(imgUrl, ivBg);      
Android Glide加載圖檔、網絡監聽、設定資源監聽

然後你可以運作了,雖然這種封裝方式并不是很高明,但是起碼代碼很簡潔不是嗎。它可以讓你選擇不同的圖檔資源類型,根據需求選擇。

Android Glide加載圖檔、網絡監聽、設定資源監聽

當然這隻是普通的顯示,如果我在知道網絡請求的情況呢?

在GlideUtil中添加

private static final String TAG = "GlideUtil";      
//圖檔加載網絡監聽
    private static RequestListener<Drawable> requestListener = new RequestListener<Drawable>() {
        @Override
        public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
            Log.d(TAG,"網絡通路失敗,請檢查是否開始網絡或者增加http的通路許可");
            return false;
        }

        @Override
        public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
            Log.d(TAG,"網絡通路成功,可以顯示圖檔");
            return false;
        }
    };      

然後增加一個方法。

/**
     * 顯示網絡Url圖檔 附帶加載網絡監聽
     * @param url
     * @param imageView
     */
    public static void loadImgListener(String url, ImageView imageView) {
        Glide.with(context)
                .load(url)
                .listener(requestListener)
                .into(imageView);
    }      

然後在MainActivity中修改代碼。

Android Glide加載圖檔、網絡監聽、設定資源監聽

下面運作一下,然後看日志是否有列印。

Android Glide加載圖檔、網絡監聽、設定資源監聽

這樣就可以了。那如果我也要知道這個設定圖檔資源的監聽呢?依葫蘆畫瓢就行了。

在GlideUtil中增加一個方法。

/**
     * 擷取ImageViewTarget
     *
     * @param imageView
     * @return
     */
    private static ImageViewTarget<Drawable> getImageViewTarget(final ImageView imageView) {
        ImageViewTarget<Drawable> imageViewTarget = new ImageViewTarget<Drawable>(imageView) {
            @Override
            public void onLoadStarted(@Nullable Drawable placeholder) {
                super.onLoadStarted(placeholder);
                Log.d(TAG, "開始加載圖檔");
            }

            @Override
            public void onLoadFailed(@Nullable Drawable errorDrawable) {
                super.onLoadFailed(errorDrawable);
                Log.d(TAG, "加載圖檔失敗");
            }

            @Override
            public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
                super.onResourceReady(resource, transition);
                // 圖檔加載完成
                imageView.setImageDrawable(resource);
                Log.d(TAG, "加載圖檔完成");
            }


            @Override
            protected void setResource(@Nullable Drawable resource) {

            }
        };
        return imageViewTarget;
    }      

然後修改loadImgListener方法。

Android Glide加載圖檔、網絡監聽、設定資源監聽

再運作一下,看日志。

Android Glide加載圖檔、網絡監聽、設定資源監聽

當然這種寫法還是不夠人性化,可能你隻需要其中一個,或者都需要,或者都不需要,那如果要滿足這個需求就還需要改動一下這個loadImgListener方法。

改動如下:

/**
     * 顯示網絡Url圖檔 附帶加載網絡監聽和設定資源監聽
     * @param url  網絡圖檔url
     * @param imageView 圖檔控件
     * @param needNetListener 是否需要網絡監聽
     * @param needResourceListener 是否需要設定資源監聽
     */
    public static void loadImgListener(String url, ImageView imageView,
                                       boolean needNetListener, boolean needResourceListener) {
        if (needResourceListener) {
            Glide.with(context)
                    .load(url)
                    .listener(needNetListener ? requestListener : null)
                    .into(getImageViewTarget(imageView));
        } else {
            Glide.with(context)
                    .load(url)
                    .listener(needNetListener ? requestListener : null)
                    .into(imageView);
        }
    }      

這裡我增加了兩個參數,用于控制是否需要網絡監聽和設定圖檔資源監聽,然後改動一下MainActvity中的代碼調用。

Android Glide加載圖檔、網絡監聽、設定資源監聽

下面運作一下,你會發現日志都會列印。

Android Glide加載圖檔、網絡監聽、設定資源監聽

然後都設定為false,這時候是不會有日志列印的,我就不截圖了。

Android Glide加載圖檔、網絡監聽、設定資源監聽

下面設定一個為true一個為false。

Android Glide加載圖檔、網絡監聽、設定資源監聽

運作看看。

Android Glide加載圖檔、網絡監聽、設定資源監聽

OK,到這一步是不是就沒有問題了呢?

那麼還有一個問題,就是如果我要顯示加載進度條呢?

那麼我們可以自定義一個這樣的彈窗,

首先你需要一個加載圖檔。如果圖檔是黑色背景的話,那麼使用白色的加載圖示無疑是很好的選擇。

圖示名稱:icon_loading.png

Android Glide加載圖檔、網絡監聽、設定資源監聽

這個圖示可以從我的源碼裡面去拿,或者自己從網絡上下載下傳。

"loading_dialog" parent="android:style/Theme.Dialog">
        <item name="android:windowFrame">@null</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowBackground">#000</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowContentOverlay">@null</item>
    </style>      

在styles.xml中設定彈窗樣式

Android Glide加載圖檔、網絡監聽、設定資源監聽

然後新增一個動畫樣式代碼。

首先在res下建立一個anim檔案夾,然後建立一個loading_animation.xml檔案,裡面的代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<set android:shareInterpolator="false" xmlns:android="http://schemas.android.com/apk/res/android">
    <rotate
        android:interpolator="@android:anim/linear_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:fromDegrees="0"
        android:toDegrees="+360"
        android:duration="1500"
        android:startOffset="-1"
        android:repeatMode="restart"
        android:repeatCount="-1"/>
</set>      

下面增加一個彈窗,在layout下建立loading_dialog.xml,布局代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/dialog_view"
    android:orientation="vertical"
    android:layout_width="120dp"
    android:layout_height="120dp"
    android:gravity="center"
    android:padding="10dp">

    <ImageView
        android:id="@+id/iv_loading"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:src="@mipmap/icon_loading" />

    <TextView
        android:visibility="gone"
        android:id="@+id/tv_loading_tx"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:maxLines="1"
        android:text="玩命加載中..."
        android:textColor="#FFF"
        android:textSize="14sp"      

這裡我把文字隐藏了。下面自定義一個加載彈窗,建立一個LoadingDialog類,繼承Dialog。裡面的代碼如下:

/**
 * 自定義加載彈窗
 * @author llw
 */
public class LoadingDialog extends Dialog {

    TextView tvLoadingTx;
    ImageView ivLoading;

    public LoadingDialog(Context context) {
        this(context, R.style.loading_dialog, "玩命加載中...");

    }

    public LoadingDialog(Context context, String string) {
        this(context, R.style.loading_dialog, string);
    }

    protected LoadingDialog(Context context, int theme, String string) {
        super(context, theme);
        setCanceledOnTouchOutside(true);//點選其他區域時   true  關閉彈窗  false  不關閉彈窗
        setContentView(R.layout.loading_dialog);//加載布局
        tvLoadingTx = findViewById(R.id.tv_loading_tx);
        tvLoadingTx.setText(string);
        ivLoading = findViewById(R.id.iv_loading);
        // 加載動畫
        Animation hyperspaceJumpAnimation = AnimationUtils.loadAnimation(
                context, R.anim.loading_animation);
        // 使用ImageView顯示動畫
        ivLoading.startAnimation(hyperspaceJumpAnimation);

        getWindow().getAttributes().gravity = Gravity.CENTER;//居中顯示
        getWindow().getAttributes().dimAmount = 0.5f;//背景透明度  取值範圍 0 ~ 1
    }

    //關閉彈窗
    @Override
    public void dismiss() {
        super.dismiss();
    }      

然後最後一步就是在GlideUtil中去使用了,可以新寫一個方法。

//加載彈窗
    private static LoadingDialog loadingDialog;      

新增loadImgListenerNeedDialog方法。

/**
     * 顯示網絡Url圖檔 附帶加載網絡監聽和設定資源監聽 顯示加載彈窗
     * @param context 顯示在哪個Activity/Fragment上
     * @param url  網絡圖檔url
     * @param imageView 圖檔控件
     * @param needNetListener 是否需要網絡監聽
     * @param needResourceListener 是否需要設定資源監聽
     */
    public static void loadImgListenerNeedDialog(Context context,String url, ImageView imageView,
                                       boolean needNetListener, boolean needResourceListener) {
        loadingDialog = new LoadingDialog(context);
        if (needResourceListener) {
            Glide.with(context)
                    .load(url)
                    .listener(needNetListener ? requestListener : null)
                    .into(getImageViewTarget(imageView));
        } else {
            Glide.with(context)
                    .load(url)
                    .listener(needNetListener ? requestListener : null)
                    .into(imageView);
        }
    }      

然後在getImageViewTarget中顯示,這裡因為,需要或者不需要彈窗的監聽都是會調用getImageViewTarget,是以對彈窗進行顯示和隐藏式,判斷是否為空,避免程式空指針崩潰。

Android Glide加載圖檔、網絡監聽、設定資源監聽

下面進入MainActivity中調用這個方法。

//顯示圖檔并監聽網絡加載情況
        loadImgListenerNeedDialog(this,imgUrl,ivBg,false,true);      

運作一下:

Android Glide加載圖檔、網絡監聽、設定資源監聽

七、源碼

總結