Glide加载加密文件

最近把项目图片加载库切换到了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并注册.

  1. 自定义GlideModule,由于我的数据的存储路径是可以直接拿到的,因此我的modelClass类型为String类型,也可以定义为其他类型 比如Picture等等
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());
  }
}
  1. 在清单文件中注册我们自定义GlideModule
data
    android:name="xxx.glide.CustomGlideModule"
        android:value="GlideModule" />
  1. 自定义的加密文件加载类,用于加载加密文件,这样自定义的数据加载类我们不需要管理缓存问题,Glide会为我们处理好.
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;
  }
}
  1. 图片加载器,重载getResourceFetcher方法,返回我们刚刚定义好的图片加载类.
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() {

    }
  }
}
  1. 最后我们可以这样使用了
Glide.with(mActivity)
        .from(String.class) // 设置数据源类型为我们的ImageFid
        .fitCenter()
        .diskCacheStrategy(DiskCacheStrategy.RESULT) // 设置本地缓存,缓存源文件和目标图像
        .placeholder(R.drawable.ic_default_image)
        .load(pictures.get(position).getFilePath())
        .into(photoView);
注意缓存策略如果对数据保密要求严格的话请设置为NONE

你可能感兴趣的:(Android)