最近把项目图片加载库切换到了Glide,本地图片使用的是Facebook的conceal进行加密. 接下来就悲剧了,Glide 只能加载File,byte[],url,等类型的数据,但是conceal 只能的到解密数据流, 所以必须将InputStream解析成byte[]才能被Glide加载.
解析字节流在UI线程(当然你也可以将它放到非UI线程)中执行,每次刷新数据(如选中操作,上下滑动等)都会导致所有图片的数据重新从文件系统(加载-解密-解析-显示)整个过程,导致用户界面卡顿.
代码如下 :
InputStream inputStream = new FileInputStream(file);
// 得到字节流,由于这一段在UI线程中所以卡顿很严重,而且每次刷新数据都会重新加载-解密-解析-显示
byte[] data = input2byte(crypto.getCipherInputStream(inputStream, entity));
// 加载字节流到ImageView
Glide.with(Context).load(data).into(image);
// 将输入流解析成字节数组
public static final byte[] input2byte(InputStream inStream)
throws IOException {
ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
byte[] buff = new byte[100];
int rc = 0;
while ((rc = inStream.read(buff, 0, 100)) > 0) {
swapStream.write(buff, 0, rc);
}
byte[] in2b = swapStream.toByteArray();
return in2b;
}
怎么样才能做到像Glide加载普通文件一样,只需要一次加载解析,其他情况在缓存中查找呢? 查找了相关资料发现Glide 还能够加载ModelType类型数据,ModelType类型的加载需要自定义GlideModule并在清单文件中注册,首先来定义我们的GlideModule并注册.
public class CustomGlideModule implements GlideModule {
@Override public void applyOptions(Context context, GlideBuilder builder) {
// 设置别的get/set tag id,以免占用View默认的
ViewTarget.setTagId(R.id.glide_tag_id);
// 图片质量低,够用就行
builder.setDecodeFormat(DecodeFormat.PREFER_RGB_565);
}
@Override public void registerComponents(Context context, Glide glide) {
// 注册我们的ImageLoader,定义modelClass类型为String因为加密文件的路径能够直接拿到,也可以定义为其他类型 比如Picture等等
// 第三个参数是我们的Loader(加载器)的工厂方法,决定我们使用什么加载器来加载文件
glide.register(String.class, InputStream.class, new ImageLoader.Factory());
}
}
data
android:name="xxx.glide.CustomGlideModule"
android:value="GlideModule" />
public class ImageDataFetcher implements DataFetcher<InputStream> {
private volatile boolean mIsCanceled;
private final String mFilePath;
private InputStream mInputStream;
public ImageDataFetcher(String filePath) {
mFilePath = filePath;
}
/**
* 这个方法是在非UI线程中执行,我们利用此方法来加载我们的加密数据
*
* @param priority
* @throws Exception
*/
@Override public InputStream loadData(Priority priority) throws Exception {
if (mIsCanceled) {
return null;
}
mInputStream = fetchStream(mFilePath);
return mInputStream;
}
/**
* 返回解密后的数据流
*
* @param file 文件名
* @return inputStream
*/
private InputStream fetchStream(String file) {
InputStream inputStream = new FileInputStream(new File(file));
// 返回解密数据流
return crypto.getCipherInputStream(inputStream, entity);
}
/**
* 处理完成之后清理工作
*/
@Override public void cleanup() {
if (mInputStream != null) {
try {
mInputStream.close();
} catch (IOException e) {
Log.e("Glide", "Glide", e);
} finally {
mInputStream = null;
}
}
}
/**
* 该文件的唯一ID
*/
@Override public String getId() {
return mFilePath;
}
/**
* 在UI线程中调用,取消加载任务
*/
@Override public void cancel() {
mIsCanceled = true;
}
}
public class ImageLoader implements ModelLoader<String, InputStream> {
public ImageLoader() {
}
@Override
public DataFetcher getResourceFetcher(String model, int width, int height) {
return new ImageDataFetcher(model);
}
/**
* ModelLoader工厂,在向Glide注册自定义ModelLoader时使用到
*/
public static class Factory implements ModelLoaderFactory<String, InputStream> {
@Override
public ModelLoader build(Context context, GenericLoaderFactory factories) {
// 返回ImageLoader对象
return new ImageLoader();
}
@Override public void teardown() {
}
}
}
Glide.with(mActivity)
.from(String.class) // 设置数据源类型为我们的ImageFid
.fitCenter()
.diskCacheStrategy(DiskCacheStrategy.RESULT) // 设置本地缓存,缓存源文件和目标图像
.placeholder(R.drawable.ic_default_image)
.load(pictures.get(position).getFilePath())
.into(photoView);