云课堂android端,目前使用的图片加载库是UniversalImageLoader(简称UIL)。在5.4.0迭代版本中,因首页又增长了几个页面,发现启动app后,内存暴增,在排查问题后发现,是图片加载库的使用方式存在问题,以及该加载库对内存并不友好。所以在对比Glide后,发下启动app后,内存有很大改善,决定使用Glide。所以须要将原有的图片加载库替换成新的。这套新的方案,须要在将来的几年中使用,而且可以灵活替换图片加载库。java
在工程中发现原来使用UIL尽管被封装在EduImageLoaderUtil
类中,包括UIL的初始配置以及默认选项。但仍是有些UIL包内的类如ImageLoadingListener
、DisplayImageOptions
暴露在公用方法中,在外部调用的时候传入。这个严重影响了封装性,不方便后期替换图片加载库。android
下面是类图:api
下面是代码实现:缓存
类ImageLoaderManager
因为图片库在一个应用中只会选择一种实现方案,因此这里的ImageLoader管理类,简单处理,配有一个默认的实现,一个默认的全局配置,一个默认的图片加载配置。提供了接口去修改默认的。网络
package com.netease.framework.imagemodule; import com.netease.framework.annotation.NonNull; import com.netease.framework.imagemodule.glide.GlideImageLoader; /** * ImageLoader管理类,默认的ImageLoader实现是GlideImageLoader。 * 提供一些注入接口,来修改默认实现以及默认配置 * Created by hzchenboning on 2017/10/8. */ public class ImageLoaderManager { private static ImageLoader sImageLoader = new GlideImageLoader(); //默认的ImageLoader实现,Glide private static DisplayImageConfig sDefaultDisPlayImageConfig = new DisplayImageConfig.Builder().build(); private static GlobalImageConfig sGlobalImageConfig = new GlobalImageConfig.Builder().build(); public static ImageLoader getImageLoader() { return sImageLoader; } public static @NonNull GlobalImageConfig getGlobalImageConfig() { return sGlobalImageConfig; } public static @NonNull DisplayImageConfig getDefaultDisPlayImageConfig() { return sDefaultDisPlayImageConfig; } /** * 修改默认的ImageLoader实现类 * @param imageLoader */ public static void setImageLoader(@NonNull ImageLoader imageLoader) { sImageLoader = imageLoader; } /** * 修改默认的每次图片加载配置项 * @param sDefaultDisPlayImageConfig */ public static void setDefaultDisPlayImageConfig(@NonNull DisplayImageConfig sDefaultDisPlayImageConfig) { ImageLoaderManager.sDefaultDisPlayImageConfig = sDefaultDisPlayImageConfig; } /** * 修改默认的全局配置项 * @param sGlobalImageConfig */ public static void setGlobalImageConfig(@NonNull GlobalImageConfig sGlobalImageConfig) { ImageLoaderManager.sGlobalImageConfig = sGlobalImageConfig; } }
类ImageLoader
app
import android.content.Context; import android.graphics.Bitmap; import android.widget.ImageView; /** * 图片加载器对外提供的服务接口 * Created by hzchenboning on 17/9/28. */ public interface ImageLoader { /** * 展现图片 */ void displayImage(Context context, String imageUrl, ImageView imageView); /** * 展现指定尺寸 */ void displayImage(Context context, String imageUrl, ImageView imageView, int width, int height); /** * 根据配置展现图片 */ void displayImage(Context context, String imageUrl, ImageView imageView, DisplayImageConfig config); /** * 根据配置展现指定大小图片 */ void displayImage(Context context, String imageUrl, ImageView imageView, DisplayImageConfig config, int width, int height); /** * 展现图片,而且监听图片加载回调 */ <R> void displayImage(Context context, String imageUrl, ImageView imageView, ResourceListener<R> listener); /** * 根据配置展现图片,而且监听图片加载回调 */ <R> void displayImage(Context context, String imageUrl, ImageView imageView, DisplayImageConfig config, ResourceListener<R> listener); /** * 展现高斯模糊图片 * @param radius 高斯模糊半径(像素),不包含中心点的像素,取值范围[1, 50] * @param sigma 高斯模糊标准差 */ void displayBlurImage(Context context, String imageUrl, ImageView imageView, int radius, int sigma); /** * 展现圆形图片 * 圆形的半径为图片的Math.min(width, height)/2 */ void displayCircleImage(Context context, String imageUrl, ImageView imageView); /** * 下载图片 */ <R> void loadImage(Context context, String imageUrl, ResourceListener<R> resourceListener); /** * 根据配置下载图片 */ <R> void loadImage(Context context, String imageUrl, DisplayImageConfig config, ResourceListener<R> resourceListener); /** * 从缓存中(内存、磁盘)获取图片 */ Bitmap getBitmapFromCache(String url); interface ResourceListener<R> { void onResourceReady(R resouce); } }
类DisplayImageConfig
ide
import com.netease.edu.framework.R; /** * 每次图片加载的配置项 * Created by hzchenboning on 17/10/9. */ public class DisplayImageConfig { int imageResOnLoading; int imageResOnFail; Priority priority; boolean cacheOnDisk; boolean cacheOnMemory; boolean needThumbnail; float thumbnail; BitmapTransformation transformation; private DisplayImageConfig(Builder builder) { this.imageResOnLoading = builder.imageResOnLoading; this.imageResOnFail = builder.imageResOnFail; this.priority = builder.priority; this.cacheOnDisk = builder.cacheOnDisk; this.cacheOnMemory = builder.cacheOnMemory; this.needThumbnail = builder.needThumbnail; this.thumbnail = builder.thumbnail; this.transformation = builder.transformation; } public int getImageResOnLoading() { return imageResOnLoading; } public int getImageResOnFail() { return imageResOnFail; } public Priority getPriority() { return priority; } public boolean isCacheOnDisk() { return cacheOnDisk; } public boolean isCacheOnMemory() { return cacheOnMemory; } public boolean isNeedThumbnail() { return needThumbnail; } public float getThumbnail() { return thumbnail; } public static class Builder { int imageResOnLoading = R.drawable.default_img;//加载中显示的图片 int imageResOnFail = R.drawable.default_img;//加载失败后显示的图片 Priority priority = Priority.NORMAL;//加载优先级 boolean cacheOnDisk = true; boolean cacheOnMemory = true; boolean needThumbnail = true;//是否先显示缩略图 float thumbnail = 0.1f;//缩略图为原图的十分之一 BitmapTransformation transformation = BitmapTransformation.none; public Builder setImageResOnLoading(int imageResOnLoading) { this.imageResOnLoading = imageResOnLoading; return this; } public Builder setImageResOnFail(int imageResOnFail) { this.imageResOnFail = imageResOnFail; return this; } public Builder setPriority(Priority priority) { this.priority = priority; return this; } public Builder setCacheOnDisk(boolean cacheOnDisk) { this.cacheOnDisk = cacheOnDisk; return this; } public Builder setCacheOnMemory(boolean cacheOnMemory) { this.cacheOnMemory = cacheOnMemory; return this; } public Builder setNeedThumbnail(boolean needThumbnail) { this.needThumbnail = needThumbnail; return this; } public Builder setThumbnail(float thumbnail) { this.thumbnail = thumbnail; return this; } public Builder setTransformation(BitmapTransformation transformation) { this.transformation = transformation; return this; } public DisplayImageConfig build() { return new DisplayImageConfig(this); } } public enum Priority { IMMEDIATE, //0ms LOW, //300ms NORMAL, //100ms HIGH //50ms } /** * 每一个新增的转换,须要增长对应的描述 * 新增的命名就按照circleCrop、roundCrop */ public enum BitmapTransformation { none, //(无变化) } }
类GlobalImageConfig
ui
import android.support.annotation.IntDef; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * 全局的图片加载配置 * Created by hzchenboning on 17/10/9. */ public class GlobalImageConfig { //--------- 如下是接口及常量 ------------- @Retention(RetentionPolicy.SOURCE) @IntDef({HIGH_IMAGE_QUALITY, NORMAL_IMAGE_QUALITY, LOW_IMAGE_QUALITY}) private @interface ImageQualityMode {} public static final int HIGH_IMAGE_QUALITY = 100; public static final int NORMAL_IMAGE_QUALITY = 80; public static final int LOW_IMAGE_QUALITY = 50; //磁盘缓存文件 250MB private static final String DEFAULT_DISK_CACHE_DIR = "image_manager_disk_cache"; private static final int DEFAULT_DISK_CACHE_SIZE = 250 * 1024 * 1024; //--------- 以上是接口及常量 ------------- public static boolean NEED_ADJUST_IMAGE_QUALITY = false; private static int sImageQuality = HIGH_IMAGE_QUALITY; private final boolean useExternalDiskCacheDir; private final String cacheFolderName; private final int diskCacheSize; private final int memoryCacheSize; public GlobalImageConfig(boolean useExternalDiskCacheDir, String cacheFolderName, int diskCacheSize, int memoryCacheSize) { this.useExternalDiskCacheDir = useExternalDiskCacheDir; this.cacheFolderName = cacheFolderName; this.diskCacheSize = diskCacheSize; this.memoryCacheSize = memoryCacheSize; } public static int getImageQuality() { return sImageQuality; } public static void setImageQuality(@ImageQualityMode int quality) { sImageQuality = quality; } public boolean isUseExternalDiskCacheDir() { return useExternalDiskCacheDir; } public String getCacheFolderName() { return cacheFolderName; } public int getDiskCacheSize() { return diskCacheSize; } public int getMemoryCacheSize() { return memoryCacheSize; } public static class Builder { boolean useExternalDiskCacheDir = true; // 默认使用外部存储卡,false的话使用内部 String cacheFolderName = DEFAULT_DISK_CACHE_DIR; int diskCacheSize = DEFAULT_DISK_CACHE_SIZE; int memoryCacheSize = 0;//若是为0,交给第三方去计算最合适的大小 public Builder setUseExternalDiskCacheDir(boolean useExternalDiskCacheDir) { this.useExternalDiskCacheDir = useExternalDiskCacheDir; return this; } public Builder setCacheFolderName(String cacheFolderName) { this.cacheFolderName = cacheFolderName; return this; } public Builder setDiskCacheSize(int diskCacheSize) { this.diskCacheSize = diskCacheSize; return this; } public Builder setMemoryCacheSize(int memoryCacheSize) { this.memoryCacheSize = memoryCacheSize; return this; } public GlobalImageConfig build() { return new GlobalImageConfig(useExternalDiskCacheDir, cacheFolderName, diskCacheSize, memoryCacheSize); } } }
本文来自网易云社区,经做者陈柏宁受权发布。this
原文地址:应用图片加载服务与第三方实现库的解耦url
更多网易研发、产品、运营经验分享请访问网易云社区。