首页 > 解决方案 > Glide 4.X:DataFetcher - 尝试从 ZIP 文件加载图片

问题描述

我必须解密图像并将其加载到 ImageViewGlide的约束条件下,不要将解密的图像保存在磁盘上。据我所知Glide,有机会使用DataFetcher. 作为DataFetcher用法示例,我想先从zip文件中加载图像。

A 已阅读编写自定义 ModelLoader并在作者的存储库的基础上创建了自己的存储库,并尝试重写代码以用于在方法内解压缩单个图片zip文件DataFetcher.loadData并将其加载到ImageView.

public class FileDataFetcher implements DataFetcher<InputStream> {
    private final FileEnveloper fileEnveloper;

    FileDataFetcher(FileEnveloper fileEnveloper) {
        this.fileEnveloper = fileEnveloper;
    }

    @Override
    public void loadData(@NonNull Priority priority, DataCallback<? super InputStream> callback) {
        try {
            unzip(); //Works fine!

            FileInputStream fin = new FileInputStream(fileEnveloper.getFile());
            ZipInputStream zin = new ZipInputStream(fin);
            callback.onDataReady(zin);
        } catch (IOException e) {
            e.printStackTrace();
            callback.onLoadFailed(e);
        }
    }

    @Override
    public void cleanup() {
        // Intentionally empty only because we're not opening an InputStream or another I/O resource!
    }

    @Override
    public void cancel() {
        // Intentionally empty.
    }

    @NonNull
    @Override
    public Class<InputStream> getDataClass() {
        return InputStream.class;
    }

    @NonNull
    @Override
    public DataSource getDataSource() {
        return DataSource.LOCAL;
    }

    private void unzip() throws IOException {
        String location = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator ;
        FileInputStream fin = new FileInputStream(fileEnveloper.getFile());
        ZipInputStream zin = new ZipInputStream(fin);
        ZipEntry ze;
        while ((ze = zin.getNextEntry()) != null) {
            if (ze.isDirectory()) {
                File dir = new File(location + ze.getName());
                if (!dir.exists() || !dir.isDirectory())
                    dir.mkdirs();
            } else {
                FileOutputStream fout = new FileOutputStream(location + ze.getName());
                byte[] buffer = new byte[1024];
                int read = 0;
                while ((read = zin.read(buffer)) != -1) {
                    fout.write(buffer, 0, read);
                }
                zin.closeEntry();
                fout.close();
            }
        }
        zin.close();
    }
}

方法unzip()工作正常,所需的解压缩图片出现在磁盘上,但callback.onDataReady(zin)会导致堆栈跟踪:

2019-12-22 13:57:22.605 28803-28803/judds.github.com.base64modelloaderexample W/Glide: Load failed for judds.github.com.base64modelloaderexample.FileEnveloper@2d3a6e1c with size [720x1257]
class com.bumptech.glide.load.engine.GlideException: Failed to load resource
  Cause (1 of 1): class com.bumptech.glide.load.engine.GlideException: Failed LoadPath{ZipInputStream->Object->Drawable}, LOCAL
    Cause (1 of 3): class com.bumptech.glide.load.engine.GlideException: Failed DecodePath{ZipInputStream->GifDrawable->Drawable}
    Cause (2 of 3): class com.bumptech.glide.load.engine.GlideException: Failed DecodePath{ZipInputStream->Bitmap->Drawable}
    Cause (3 of 3): class com.bumptech.glide.load.engine.GlideException: Failed DecodePath{ZipInputStream->BitmapDrawable->Drawable}

我想原因不在于withGlide的错误用法,而在于ZipInputStreamwith的错误用法Glide。有人知道应该怎么做吗?

标签: androidzipandroid-glidezipinputstreamappglidemodule

解决方案


为了让它工作(对于zip-archive 中的单个文件),我们必须ZipInputStream在初始位置设置zin.getNextEntry()如下:

@Override
public void loadData(@NonNull Priority priority, DataCallback<? super InputStream> callback) {
    try {
        unzip(); //Works fine!

        FileInputStream fin = new FileInputStream(fileEnveloper.getFile());
        ZipInputStream zin = new ZipInputStream(fin);
        zin.getNextEntry();//Essential!!!
        callback.onDataReady(zin);
    } catch (IOException e) {
        e.printStackTrace();
        callback.onLoadFailed(e);
    }
}

推荐阅读