GLIDE 的 一些用法

               

什么?加载网路图片没有url?只给我文件id?

最近公司项目换了七牛来存储用户文件。
于是获取图片方面,服务器那边不再给我完整的url,只给我个fidfile id,
我要拿着这个fid去做个http请求,才能获取到个带token的url,只有这个带token的url才能正确获取到图片。

我现在用的图片加载框架是Glide,很赞,Google都用它。Glide基础用法参考->这里

那就是说,我现在要加载一个网络图片,要做两次http请求:
先用http请求获取url再用Glide加载这个url(第二次请求)
由于Android不允许UI线程访问网络,所以我必须开一个线程来获取那个url,而Glide加载和处理图片时,也会开线程。
于是多线程异步问题来了,如果用在ListView等地方,那么十有八九出现图片加载错乱的情况(真出现了)。

当然,可以通过加一堆判断来规避这个问题,但总感觉不怎么爽。
如果可以修改Glide加载图片的过程,把第一次请求url的操作塞进去,
然后像加载普通url那样,直接用我们的fid加载图片,就爽了。

初战铩羽而归

于是果断翻翻Glide项目的wiki,看看能不能干些什么。
然后我翻到这页:

https://github.com/bumptech/glide/wiki/Downloading-custom-sizes-with-Glide

public class MyUrlLoader extends BaseGlideUrlLoader<MyDataModel> {
    @Override
    protected String getUrl(MyDataModel
model, int width, intheight) {
        // Construct the url for thecorrect size here.
        return
model.buildUrl(width, height);
    }
}

蛤蛤,貌似有戏,我在这个getUrl()回调里面做次请求,返回获取到的url不就行了么,剩下就交给Glide处理,赞。

当然,凡事没这么简单了。谁知道这getUrl()回调运行在UI线程中,而在Android 3.0以上,UI线程中不允许进行网络操作。
这方案没戏。

高人指点

好吧,这下好了,刚燃起的希望,一下子又熄灭了。
想起了刚开始用Glide的时候,发过issue,这次也发个issue好了。

这次@TWiStErRob大神依旧给力,很快就给了解决方案,虽然只有文字描述。

You have to write a model loader. Create a wrapper class forinteger and maybe add in the token as well.
https://github.com/bumptech/glide/wiki/Downloading-custom-sizes-with-Glide
Your
 model loader cancreate a fetcher that makes one request for the token and one request for theimage, and return the second’s stream.
Or you can make the token request separately inside BaseGlideUrlLoader.getUrl(see wiki), then return the URL and let
 Glide take care of the rest “as usual”.

简单来说,大神说了两个方案:

1.       全完实现ModelLoaderDataFetcher

2.       我上面说的那个失败了的getUrl()请求url的方案。

其实第二种方案属于第一种的特殊情况,BaseGlideUrlLoader就是ModelLoader的子类,已经实现好从url拉数据的细节。

这样看的话,其实我一开始的方向就是对的,遗憾的是没钻进去研究更底端层次的,懒啊。

于是参考了Glide中,部分已经实现好的ModelLoader和DataFetcher的子类,自己试着写了下,真成功了。下面说说细节。

搞掂

模拟案例

这里模拟了个DEMO,放在github上:

https://github.com/licheedev/Custom-Glide-ModelLoader-Demo

当然,我不可能把公司的接口公布出去,于是用一种很坑爹的方式,去模拟用fid获取url的接口。
因为我这个案例的关键的地方是两次请求
于是我放了个静态json在七牛上,

{
  "prefix":"http://7xlwmc.com1.z0.glb.clouddn.com/"
}

其实就是一个完整url的前缀,当然也没有token,每次加载一个fid的时候,都会"多此一举"地拉这个json回来解析,
然后把prefix拼上fid,就是一个可用的url:
比如这个http://7xlwmc.com1.z0.glb.clouddn.com/SAMPLE_IMG_008.jpg

这就完成了一次请求。

细节

下面代码的写法参考了Glide自带的HttpGlideUrlLoaderHttpUrlFetcher

ImageFidLoader

ModelLoader的作用只有一个——实现getResourceFetcher()方法,返回一个DataFetcher对象。
ModelLoaderFactory的用法可以看下面的配置引用页。

public class ImageFidLoader implementsModelLoader<ImageFid,InputStream> {

    private final ModelCache<ImageFid,ImageFid> mModelCache;

    public ImageFidLoader() {
        this(null);
    }

    publicImageFidLoader(ModelCache<ImageFid, ImageFid> modelCache) {
        mModelCache = modelCache;
    }

    @Override
    public DataFetcher<InputStream>getResourceFetcher(ImageFid
model, int width, int height) {
        ImageFid imageFid =
model;
        //
从缓存中取出ImageFid,ImgeFid已重写equals()hashCode()方法

ImageFidFetcher

DataFetcher的作用是从数据源(图片网络地址、本地路径、res资源id等)中获取到图片的流数据(InputStream),然后交给Glide做处理(缩放、本地缓存等)。

注意loadData()cleanup()getId()cancel()四个回调方法的作用场景。
loadData()中,这里进行了两次请求,一次拿url,一次拿图片数据。

public class ImageFidFetcher implementsDataFetcher<InputStream> {

    //
检查是否取消任务的标识
    private volatile boolean mIsCanceled;
   
    private final ImageFid mImageFid;
    private Call mFetchUrlCall;
    private Call mFetchStreamCall;
    private InputStream mInputStream;

    public ImageFidFetcher(ImageFidimageFid) {
        mImageFid = imageFid;
    }

    /**
     *
在后台线程中调用,用于获取图片的数据流,给Glide处理
     * @param priority
     * @return
     * @throws Exception
     */
    @Override
    public InputStream loadData(Prioritypriority) throws Exception {
        // mImageFid
有可能是来自缓存的,先从此对象获取url
        String url = mImageFid.getUrl();
        if (url == null) {
            if (mIsCanceled) {
                return null;
            }
            //
建立http请求,从网络上获取fid对应的的url
            url = fetchImageUrl();
            if (url == null) {
                return null;
            }
            //
存储获取到的url,以供缓存使用
            mImageFid.setUrl(url);
        }
        if (mIsCanceled) {

CustomGlideModule

配置Glide,注册ModelLoader。
注册完之后,我们就可以直接用Glide去直接加载对应类型的数据(这里的是ImageFid)来获取图片了。

具体参照:

https://github.com/bumptech/glide/wiki/Configuration

https://github.com/bumptech/glide/releases

https://github.com/bumptech/glide/wiki/Downloading-custom-sizes-with-Glide

public class CustomGlideModule implements GlideModule {

    @Override
    public void applyOptions(Contextcontext, GlideBuilder builder) {
        ViewTarget.setTagId(R.id.
glide_tag_id); //设置别的get/set tag id,以免占用View默认的
       builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888); //
设置图片质量为高质量
    }

    @Override
    public voidregisterComponents(Context context,
Glideglide) {
        //
注册我们的ImageFidLoader
       
glide.register(ImageFid.class,InputStream.class, new ImageFidLoader.Factory());
    }
}

 

ItemAdapter

这里展示了怎么直接使用fid来加载图片。跟普通的直接加载URL没什么两样。

如果没有在自定义GlideModule注册ModelLoader,
则每次加载图片,都需要调用using(new MyUrlLoader())注册ModelLoader,
Glide.with(yourFragment).using

public class ItemAdapter extendsArrayAdapter<ImageFid> {

    private finalDrawableRequestBuilder<ImageFid> mGlideBuilder;

    public ItemAdapter(Context context,ImageFid[] images) {
        super(context, 0, images);
        mGlideBuilder =
Glide.with(context)
            .from(ImageFid.class) //
设置数据源类型为我们的ImageFid
            .fitCenter().crossFade()
           .diskCacheStrategy(DiskCacheStrategy.ALL) //
设置本地缓存,缓存源文件和目标图像
           .placeholder(R.mipmap.ic_launcher);
    }

    @Override
    public View getView(int position,View convertView, ViewGroup parent) {
        ViewHolder holder;
        ...
        ImageFid fid = getItem(position);
        //
直接加载fid
       mGlideBuilder.load(fid).into(holder.ivImage);
        ...
        return convertView;
    }

    private static class ViewHolder {
    ...
    }

 

效果

网络加载

加载缓存

总结

首先再次感谢@TWiStErRob大神,这次又帮了我。
还有就是,用好开源项目,有时候还真的要多看点源码,毕竟文档有时候写得不够完整。

           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

猜你喜欢

转载自blog.csdn.net/qq_43668118/article/details/86554423