Diycode開源項目 Glide圖片加載分析


1.使用Glide前的准備

1.1.首先要build.gradle中添加

   

  github原地址點擊我。

  參考博客:Glide-開始!

  參考博客:android圖片加載庫Glide的使用介紹。

  參考博客:Google推薦的圖片加載庫Glide介紹。

  所有有關Glide的源頭都是來自於github,首先亮一手,可以自己去看看。

 

1.2.有必要添加混淆

  為了APP的安全,現在一般都要求添加混淆

  

  在github上復制粘貼即可。

 

1.3.最簡單的用法==>對於一個簡單的view

  

  了解這么多就行了。


2.用Module自定義Glide

2.1.Glide Module存在的意義

  Glide Module是一個抽象方法,全局改變Glide行為的一個方法。如果你需要GlideBuilder,它要在你要做的地方

  創建Glide實例。這是要做的一種方法。為了定制Glide,你需要去實現一個GlideModule接口的公共類。

  

  

2.2.需要在AndroidManifest.xml中聲明這個Glide module。

  

 

2.3.然后就可以對這個Module為所欲為了。

  有這些方法可以用的。

  

  實際的項目中是這樣用的。

  

  設置了內存緩存==10M

  設置了磁盤緩存==250M

 

2.4.還可以增加Glide的圖片質量,用的也比較多

  


3.自定義Drawable實現Drawable.Callback

3.1.首先了解一下Drawable

    關於自定義Drawable,可以參考一下這篇文章。

  

  

  

3.2.然后了解一下Drawble.Callback回調接口

 

 

3.3.本項目的源代碼

/*
 * Copyright 2017 GcsSloop
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Last modified 2017-03-11 22:24:02
 *
 * GitHub:  https://github.com/GcsSloop
 * Website: http://www.gcssloop.com
 * Weibo:   http://weibo.com/GcsSloop
 */

package com.gcssloop.diycode.base.glide;

import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.drawable.Drawable;

import com.bumptech.glide.load.resource.drawable.GlideDrawable;

/**
 * 為 {@link GlideImageGetter} 服務
 */
public class UrlDrawable extends Drawable implements Drawable.Callback {

    private GlideDrawable mDrawable;

    @Override
    public void draw(Canvas canvas) {
        if (mDrawable != null) {
            mDrawable.draw(canvas);
        }
    }

    @Override
    public void setAlpha(int alpha) {
        if (mDrawable != null) {
            mDrawable.setAlpha(alpha);
        }
    }

    @Override
    public void setColorFilter(ColorFilter cf) {
        if (mDrawable != null) {
            mDrawable.setColorFilter(cf);
        }
    }

    @Override
    public int getOpacity() {
        if (mDrawable != null) {
            return mDrawable.getOpacity();
        }
        return 0;
    }

    public void setDrawable(GlideDrawable drawable) {
        if (this.mDrawable != null) {
            this.mDrawable.setCallback(null);
        }
        drawable.setCallback(this);
        this.mDrawable = drawable;
    }

    @Override
    public void invalidateDrawable(Drawable who) {
        if (getCallback() != null) {
            getCallback().invalidateDrawable(who);
        }
    }

    @Override
    public void scheduleDrawable(Drawable who, Runnable what, long when) {
        if (getCallback() != null) {
            getCallback().scheduleDrawable(who, what, when);
        }
    }

    @Override
    public void unscheduleDrawable(Drawable who, Runnable what) {
        if (getCallback() != null) {
            getCallback().unscheduleDrawable(who, what);
        }
    }
}
View Code

 

3.4.本項目實現Drawable中4個必須實現的函數

  

  其實這里的主角已經悄悄替換成了Glide中的一個GlideDrawble方法了

  這個UrlDrawable就是起一個替換作用,就是自定義一個Drawable可以完美實現GlideDrawable中的所有方法。

 

3.5.最關鍵的setDrawable函數

  

  僅僅這個函數被外部調用了,所以這里既設置了Callback回調,也將外部傳進來的GlideDrawable完美附上了值。

 

3.6.然后是看一下Drawable.Callback

  這里沒有做什么改變,只是因為GlideDrawable要實現這些回調,只能被動去實現3個復寫的方法。

  


4.用Glide加載網絡圖片,並在textView中顯示

4.1.要實現的功能預覽。

  

  如上圖,評論中有一張截圖+下方的文字。

  整個評論其實是一個TextView。

  問題是如何實現這個功能呢?

 

4.2.回顧之前的准備

  我自定義了一個GlideModule,並在清單文件中配置好,有這個東西就行了。  

  然后我自定義了一個UrlDrawable,都是為GlideImageGetter做准備的。

  

  這個是那個評論實現圖文混排的關鍵代碼。

  所以我還要定義GlideImageGetter,將content注入這種特殊功能。

 

4.3.然后就來關注一下如何實現GlideImageGetter的吧。

/*
 * Copyright 2017 GcsSloop
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Last modified 2017-03-31 14:20:42
 *
 * GitHub:  https://github.com/GcsSloop
 * Website: http://www.gcssloop.com
 * Weibo:   http://weibo.com/GcsSloop
 */

package com.gcssloop.diycode.base.glide;

import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.Html;
import android.view.View;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.Request;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.ViewTarget;
import com.gcssloop.diycode.R;
import com.gcssloop.diycode_sdk.log.Logger;

import java.util.HashSet;
import java.util.Set;

/**
 * 用 Glide 加載圖片,並在 TextView 中顯示
 */
public final class GlideImageGetter implements Html.ImageGetter, Drawable.Callback {

    private final Context mContext;

    private final TextView mTextView;

    private final Set<ImageGetterViewTarget> mTargets;

    public static GlideImageGetter get(View view) {
        return (GlideImageGetter) view.getTag(R.id.drawable_callback_tag);
    }

    public void clear() {
        GlideImageGetter prev = get(mTextView);
        if (prev == null) return;

        for (ImageGetterViewTarget target : prev.mTargets) {
            Glide.clear(target);
        }
    }

    public GlideImageGetter(Context context, TextView textView) {
        this.mContext = context;
        this.mTextView = textView;

        clear();
        mTargets = new HashSet<>();
        mTextView.setTag(R.id.drawable_callback_tag, this);
    }

    @Override
    public Drawable getDrawable(String url) {
        final UrlDrawable urlDrawable = new UrlDrawable();

        Logger.i("Downloading from: " + url);
        Glide.with(mContext)
                .load(url)
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .into(new ImageGetterViewTarget(mTextView, urlDrawable));


        return urlDrawable;

    }

    @Override
    public void invalidateDrawable(Drawable who) {
        mTextView.invalidate();
    }

    @Override
    public void scheduleDrawable(Drawable who, Runnable what, long when) {

    }

    @Override
    public void unscheduleDrawable(Drawable who, Runnable what) {

    }

    private class ImageGetterViewTarget extends ViewTarget<TextView, GlideDrawable> {

        private final UrlDrawable mDrawable;

        private ImageGetterViewTarget(TextView view, UrlDrawable drawable) {
            super(view);
            mTargets.add(this);
            this.mDrawable = drawable;
        }

        @Override
        public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
            Rect rect;
            if (resource.getIntrinsicWidth() > 100) {
                float width;
                float height;
                Logger.i("Image width is " + resource.getIntrinsicWidth());
                Logger.i("View width is " + view.getWidth());
                if (resource.getIntrinsicWidth() >= getView().getWidth()) {
                    float downScale = (float) resource.getIntrinsicWidth() / getView().getWidth();
                    width = (float) resource.getIntrinsicWidth() / (float) downScale;
                    height = (float) resource.getIntrinsicHeight() / (float) downScale;
                } else {
                    float multiplier = (float) getView().getWidth() / resource.getIntrinsicWidth();
                    width = (float) resource.getIntrinsicWidth() * (float) multiplier;
                    height = (float) resource.getIntrinsicHeight() * (float) multiplier;
                }
                Logger.i("New Image width is " + width);


                rect = new Rect(0, 0, Math.round(width), Math.round(height));
            } else {
                rect = new Rect(0, 0, resource.getIntrinsicWidth() * 2, resource.getIntrinsicHeight() * 2);
            }
            resource.setBounds(rect);

            mDrawable.setBounds(rect);
            mDrawable.setDrawable(resource);


            if (resource.isAnimated()) {
                mDrawable.setCallback(get(getView()));
                resource.setLoopCount(GlideDrawable.LOOP_FOREVER);
                resource.start();
            }

            getView().setText(getView().getText());
            getView().invalidate();
        }

        private Request request;

        @Override
        public Request getRequest() {
            return request;
        }

        @Override
        public void setRequest(Request request) {
            this.request = request;
        }
    }
}
View Code

 

4.4.實現了Html.ImageGetter接口中的方法

  

  這里用到了之前定義的UrlDrawable方法了。

  將urlDrawable和textView掛鈎了,利用了一個ImageGetterViewTarget類完成轉換作用。

  這里同時也是實現Glide加載圖片的關鍵,利用Glide.with().load().into()方法即可加載圖片。

  

 

4.5.實現了Drawable.Callback接口中的方法

  

  這里沒做什么事情,就是將textView刷新一下。這樣圖片才能顯示出來。

 

4.6.然后看一下構造函數

  

  這里就是一個提供給外部調用的一個構造函數。

  將某個上下文的textView獲取到。

  首先clear一下。

  然后將這個textView設置一個Tag。

  設置標簽的作用==>用於區分很多相似的View。

  

  怎么clear?

  先get一下。get這個textView,獲取一個GlideImageGetter,然后將其中clear。

  循環遍歷GlideImageGetter中的ImageGetterViewTarget,利用Glide.clear(target)來清除。

  怎么get?

  

  返回一個GlideImageGetter,從一個資源文件:

  

  得到一個view,強制轉換成GlideImageGetter。

 

4.7.內部類ImageGetterViewTarget

  繼承了ViewTarget<TextView,GlideDrawable>

  作用:將textView和GlideDrawable掛鈎,轉換的效果。

  注意:這個ViewTarget是第三方庫自己提供的一個類

  

  4.7.1.構造函數

      

     存放到大佬GlideImageGetter來統一管理,所以在GlideImageGetter用到了一個集合Set。

  

  4.7.2.然后是一個定義一個成員變量Request

     

 

  4.7.3.最后是最難的一個復寫的函數onResourceReady

     

    這個就是整個聯系過程了。

    定義了邊界和縮放。

     

4.8.推薦一篇基於Glide圖片加載框架==支持textView圖文並茂

  文章地址:http://www.jianshu.com/p/037ae1dfb442

  實現效果:

  

 

4.9.關於Android圖片加載

  參考文章:Android大神之作。

   

 

  


5.總計一下

5.1.textView使用Glide加載html圖片的總流程,首先由一個實現了Html.ImageGetter接口的一個ImageGetter類。

  這個Getter類要求實現getGrawable,然后這里面是一個Glide.with.load.into加載圖片到一個自定義的

  ImageGetterViewTarget,這個類是ImageGetter中的內部類,主要處理將textView和GlideDrawable

  產生聯系,主要聯系方法是onResourceReady,主要處理了一些邊界和縮放,好讓圖片正確顯示。

 

5.2.這里有一個UrlDrawable是一個輔助,輔助GlideImageGetter大佬將textView和UrlDrawable產生必要的聯系。

  其實UrlDrawable里面的最關鍵的變量就是一個GlideDrawable,其實UrlDrawable就是起到一個過渡作用。將

  textView通過UrlDrawable得到一個GlideDrawable。這樣才能處理圖片的一些邊界以及縮放了。

 

5.3.所以這里對第三方庫Glide有了更加深入的理解。如果要自定義Glide加載方式,必須要有一個自定義Module。

  注意這個Module一定要在清單中配置,否則也沒有用的。然后是最重要的GlideImageGetter,這是一個自定義

  類來獲取圖片的,通過Html來獲取其中元素。所以這里發現內部類ImageGetterViewTarget和UrlDrawable

  都是輔助,ImageGetterViewTarget重要的函數是onResourceRead來完成邊界和縮放,UrlDrawable是提供

  一個將GlideDrawable封裝起來的一個類,方便調用。

 

5.4.Glide是一個非常強大的圖片加載第三方庫。很多功能都值得去探索,單純會將圖片加載到imageView並不能證明

  你就會用了。可以說現在我還是迷迷糊糊的,但是至少我比當初的我有小許了解了要怎么做,要做什么。接下來

  繼續加油了,這里只是簡單了解,以后碰到了再另外寫一篇。

 


免責聲明!

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



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