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并不能证明

  你就会用了。可以说现在我还是迷迷糊糊的,但是至少我比当初的我有小许了解了要怎么做,要做什么。接下来

  继续加油了,这里只是简单了解,以后碰到了再另外写一篇。

 

posted @ 2017-11-22 22:35  Jason_Jan  阅读(1395)  评论(0编辑  收藏  举报