Diycode开源项目 Glide图片加载分析
1.使用Glide前的准备
1.1.首先要build.gradle中添加
所有有关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
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); } } }
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; } } }
4.4.实现了Html.ImageGetter接口中的方法
这里用到了之前定义的UrlDrawable方法了。
将urlDrawable和textView挂钩了,利用了一个ImageGetterViewTarget类完成转换作用。
这里同时也是实现Glide加载图片的关键,利用Glide.with().load().into()方法即可加载图片。
4.5.实现了Drawable.Callback接口中的方法
这里没做什么事情,就是将textView刷新一下。这样图片才能显示出来。
4.6.然后看一下构造函数
这里就是一个提供给外部调用的一个构造函数。
将某个上下文的textView获取到。
首先clear一下。
然后将这个textView设置一个Tag。
怎么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图片加载
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并不能证明
你就会用了。可以说现在我还是迷迷糊糊的,但是至少我比当初的我有小许了解了要怎么做,要做什么。接下来
继续加油了,这里只是简单了解,以后碰到了再另外写一篇。