Android图片加载框架的封装(Glide封装为例)

  • 前言

       接手之前的项目,发现图片加载用的是glide,但是每处加载的地方都把GlideApp.with()一系列配置写下来,虽然代码也不长,但是这样一来显得不优雅,二来重复代码太多,三来可维护性也差,所以当时就简单地写了个图片加载的封装类,单例对外提供static方法,虽说一定程度上规避了代码重复,但是一个app里图片的样式好几种,每加一个又得写一个对外方法,久而久之,这个封装类必定变得越来越臃肿;再者,如果某些特殊需求需要切换另外的图片加载框架,那也是挺灾难的情况。所以本篇文章尝试解决这样的问题,在此之前我看到有人写了快速开发框架MVPArms,看到里面图片加载的封装就挺好的,学习了下,在这里做下梳理。以下是大概的封装思路:

封装思路.png

  • 实战

       如上文所说,目前的封装一个缺点是,图片样式多种,每增加一种样式,都要在ImageLoader里增加一个方法,在方法里更改配置,比如placeHolder,transition等,所以首先考虑的就是把配置分割出去,单独写一个类,外部自由定制,如果配置项比较多,这时候就可以用上构建者模式,更好的做法也可以写过基类,因为每个图片的加载,肯定涉及到图片的url,图片加载的目标对象(比如ImageView)等,这里就可以提到一个基类里:

public class ImageConfig {
    protected String url;
    protected ImageView imageView;
    protected int placeholder;//占位符

    public String getUrl() {
        return url;
    }

    public ImageView getImageView() {
        return imageView;
    }

    public int getPlaceholder() {
        return placeholder;
    }
}

       不同的图片加载框架,不同的配置类,就可以继承ImageConfig进行扩展,比如图片的圆角,模糊度,背景色,(顺便贴上强大的样式扩展库glide-transformations,支持多种样式)

public class ImageConfigImpl extends ImageConfig {
    private int imageRadius;//图片每个圆角的大小
    private int blurValue;//高斯模糊值, 值越大模糊效果越大
  
   //建造者模式来构建配置信息这个对象
    private ImageConfigImpl(Builder builder) {
        this.url = builder.url;
        this.imageView = builder.imageView;
        this.placeholder = builder.placeholder;     
        this.imageRadius = builder.imageRadius;
        this.blurValue = builder.blurValue;
    }

     public int getBlurValue() {
        return blurValue;
    }

     public int getImageRadius() {
        return imageRadius;
    }

     public static Builder builder() {
        return new Builder();
    }

    public static final class Builder {
        private String url;
        private ImageView imageView;
        private int imageRadius;//图片每个圆角的大小
        private int blurValue;//高斯模糊值, 值越大模糊效果越大

        private Builder() {
        }

        public Builder url(String url) {
            this.url = url;
            return this;
        }

        public Builder placeholder(int placeholder) {
            this.placeholder = placeholder;
            return this;
        }

        public Builder imageView(ImageView imageView) {
            this.imageView = imageView;
            return this;
        }

        public Builder imageRadius(int imageRadius) {
            this.imageRadius = imageRadius;
            return this;
        }

        public Builder blurValue(int blurValue) { //blurValue 建议设置为 15
            this.blurValue = blurValue;
            return this;
        }
       //构造出ImageConfigImpl对象
        public ImageConfigImpl build() {
            return new ImageConfigImpl(this);
        }
}

       我们使用到了构建者模式,它有个好处就是,即使你因为需求增加一种样式,直接到Build里添加相应的属性,而不会影响到其它使用方,因为每个使用方都是自己定制这个Buider对象,互不影响。到这边,我们对图片的配置信息已经写好,外部可以进行个性化定制,比如

ImageConfigImpl.builder()
                        .url(data.getAvatarUrl())
                        .imageView(mAvatar)
                        .build()

       这样不同配置还要追加一个方法的缺点已经被我们用构建者模式解决;接下来就是:如果切换了其他的图片加载库怎么办(当然这种情况还是比较少的)
       当我们碰到一个功能,可能会有很多种算法的实现,又想做随时的切换,这时候可以用上策略模式,顾名思义,策略模式就是根据不同的场景采取不同的策略来完成需求。
       首先,我们刚才说碰到一个“功能”,那么先把这个功能写一个接口抽象起来,要求各个策略者实现各自具体的加载方法。

public interface BaseImageLoaderStrategy<T extends ImageConfig> {
  //定义供外部调用的显示图片的方法
    void displayImage(Context contex, T config);
}

       这里我们发现,接口带有继承于ImageConfig的泛型,这个作用也很明显,就是将外部自己构建的ImageConfig实例传给具体的displayImage实现方法,才能拿到你配置的config,比如下面的displayImage实现方法

  • 以Glide为例
public class GlideImageLoaderStrategy implements BaseImageLoaderStrategy<ImageConfigImpl> {

    @Override
    public void displayImage(Context context, ImageConfigImpl config) {
         //这里实现Glide图片加载方法,也就是GlideApp.with(context)...那一串
        //config中拿出用户配置的参数 如 config.getBlurValue()
    }
}
  • Picasso为例
public class PicassoImageLoaderStrategy implements BaseImageLoaderStrategy<PicassoConfigImpl > {

    @Override
    public void displayImage(Context contex, PicassoConfigImpl config) {
         //这里实现Picasso图片加载方法   Picasso.with(context)....那一串
        //PicassoConfigImpl 与ImageConfigImpl 一个意思,省略不写
    }
}

       策略实现类我们已经写好了,现在就是对外暴露我们的图片显示策略,写一个统一类:ImageLoader

public final class ImageLoader {

     private BaseImageLoaderStrategy mStrategy;
     /**
     * 加载图片
     */
    public  void loadImage(Context context,T config) {
        if(this.mStrategy==null){
             throw new 
             NullPointerException("you should invoke setLoadImgStrategy first");
    }
        this.mStrategy.displayImage(context,config);
    }

   //设置上你的策略实现类对象,让它去调自己的displayImage()方法
    public void setLoadImgStrategy(BaseImageLoaderStrategy strategy) {
        this.mStrategy = strategy;
    }

    public BaseImageLoaderStrategy getLoadImgStrategy() {
        return mStrategy;
    }
}

       外部需要显示图片的,都只需要调用ImageLoader的disolayImage方法,注意,必须先注入自己的代理类实例,比如你的GlideImageLoaderStrategy或PicassoImageLoaderStrategy 等,我们来看下调用方是怎么调用的:

mImageLoader.loadImage(itemView.getContext(),
                ImageConfigImpl
                        .builder()
                        .url(data.getAvatarUrl())
                        .imageView(mAvatar)
                        .build());
  • 总结

       以上就是图片加载框架的封装思路,通过构建者模式优化了图片加载配置项的管理,并且调用方构建自己的对象互不干扰;通过策略模式也规避了切换图片框架的风险;这就是java设计模式给代码维护带来的便利,当然,学以致用,才能得心应手。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270