Android Glide-使用自定义MediaLoader和MetadataRetriever加载音频封面艺术

Android Glide-使用自定义MediaLoader和MetadataRetriever加载音频封面艺术,android,android-glide,Android,Android Glide,下面的示例是从本地音频文件生成缩略图,并使用Glide v4在RecyclerView中显示它们 但正如您在链接中所看到的,示例是使用glide 3,我试图使代码与glide 4兼容,但我一直得到以下例外: com.bumptech.glide.Registry$NoModelLoaderAvailableException:未能找到模型的任何ModelLoader:com.symphonyrecords.mediacomp.design.glideUtil.audioCoverLoader。A

下面的示例是从本地音频文件生成缩略图,并使用Glide v4在RecyclerView中显示它们

但正如您在链接中所看到的,示例是使用glide 3,我试图使代码与glide 4兼容,但我一直得到以下例外:

com.bumptech.glide.Registry$NoModelLoaderAvailableException:未能找到模型的任何ModelLoader:com.symphonyrecords.mediacomp.design.glideUtil.audioCoverLoader。AudioCoverModel@7a3c7c9f

你能帮我找出问题出在哪里吗

在我的适配器内部

@Override
public void onBindViewHolder(@NonNull MediaViewHolder holder, int position) {
    MediaModel media = mMediaListData.get(position);
    String mediaPath = media.getMediaPath();
    try {
        Glide.with(context)
                .load(new AudioCoverModel(mediaPath))
                .myCustomTransform()
                .apply(requestOptions)
                .into(holder.mediaCover);
    } catch (Throwable e) {
        e.printStackTrace();
    }
}
AudioCoverModel.java

public class AudioCoverModel {

    public String mediaPath;

    public AudioCoverModel(String path) {
        this.mediaPath = path;
    }

    @Override
    public int hashCode() {
        return Math.abs((mediaPath.getBytes().length + mediaPath.hashCode()));
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;

        if (obj == null || obj.getClass() != this.getClass()) return false;

        AudioCoverModel compare = (AudioCoverModel) obj;

        try {
            return (compare.mediaPath.equals(this.mediaPath) && compare.mediaPath.getBytes().length == this.mediaPath.getBytes().length);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }


}
public class AudioCoverModule extends AppGlideModule {


    @Override
    public boolean isManifestParsingEnabled() {
        return false;
    }

    @Override
    public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
        super.applyOptions(context, builder);
    }

    @Override
    public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
        registry.append(AudioCoverModel.class, InputStream.class, new AudioCoverLoader.Factory());
    }

}
class AudioCoverLoader implements ModelLoader<AudioCoverModel, InputStream> {

    @NonNull
    @Override
    public LoadData<InputStream> buildLoadData(@NonNull AudioCoverModel AudioCoverModel, int width, int height, @NonNull Options options) {
        return new LoadData<>(new ObjectKey(AudioCoverModel), new AudioCoverFetcher(AudioCoverModel));
    }

    @Override
    public boolean handles(@NonNull AudioCoverModel AudioCoverModel) {
        return true;
    }

    static class Factory implements ModelLoaderFactory<AudioCoverModel, InputStream> {
        @NonNull
        @Override
        public ModelLoader<AudioCoverModel, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {
            return new AudioCoverLoader();
        }

        @Override
        public void teardown() {

        }
    }

}
public class AudioCoverFetcher implements DataFetcher<InputStream> {

    private final AudioCoverModel model;
    private FileInputStream stream;

    AudioCoverFetcher(AudioCoverModel model) {
        this.model = model;
    }

    @Override
    public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        try {
            retriever.setDataSource(model.mediaPath);
            byte[] picture = retriever.getEmbeddedPicture();
            if (null != picture) {
                callback.onDataReady(new ByteArrayInputStream(picture));
            } else {
                callback.onDataReady(fallback(model.mediaPath));
            }
        } finally {
            retriever.release();
        }

    }

    @Override
    public void cleanup() {
        try {
            if (null != stream) {
                stream.close();
            }
        } catch (IOException ignore) { }
    }

    @Override
    public void cancel() {
        // cannot cancel
    }


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

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


    public static final String[] FALLBACKS = {"cover.jpg", "album.jpg", "folder.jpg"};

    private InputStream fallback(String path) {
        File parent = new File(path).getParentFile();
        for (String fallback : FALLBACKS) {
            // TODO make it smarter by enumerating folder contents and filtering for files
            // example algorithm for that: http://askubuntu.com/questions/123612/how-do-i-set-album-artwork
            File cover = new File(parent, fallback);
            if (cover.exists()) {
                try {
                    return stream = new FileInputStream(cover);
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

}
AudioCoverModule.java

public class AudioCoverModel {

    public String mediaPath;

    public AudioCoverModel(String path) {
        this.mediaPath = path;
    }

    @Override
    public int hashCode() {
        return Math.abs((mediaPath.getBytes().length + mediaPath.hashCode()));
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;

        if (obj == null || obj.getClass() != this.getClass()) return false;

        AudioCoverModel compare = (AudioCoverModel) obj;

        try {
            return (compare.mediaPath.equals(this.mediaPath) && compare.mediaPath.getBytes().length == this.mediaPath.getBytes().length);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }


}
public class AudioCoverModule extends AppGlideModule {


    @Override
    public boolean isManifestParsingEnabled() {
        return false;
    }

    @Override
    public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
        super.applyOptions(context, builder);
    }

    @Override
    public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
        registry.append(AudioCoverModel.class, InputStream.class, new AudioCoverLoader.Factory());
    }

}
class AudioCoverLoader implements ModelLoader<AudioCoverModel, InputStream> {

    @NonNull
    @Override
    public LoadData<InputStream> buildLoadData(@NonNull AudioCoverModel AudioCoverModel, int width, int height, @NonNull Options options) {
        return new LoadData<>(new ObjectKey(AudioCoverModel), new AudioCoverFetcher(AudioCoverModel));
    }

    @Override
    public boolean handles(@NonNull AudioCoverModel AudioCoverModel) {
        return true;
    }

    static class Factory implements ModelLoaderFactory<AudioCoverModel, InputStream> {
        @NonNull
        @Override
        public ModelLoader<AudioCoverModel, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {
            return new AudioCoverLoader();
        }

        @Override
        public void teardown() {

        }
    }

}
public class AudioCoverFetcher implements DataFetcher<InputStream> {

    private final AudioCoverModel model;
    private FileInputStream stream;

    AudioCoverFetcher(AudioCoverModel model) {
        this.model = model;
    }

    @Override
    public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        try {
            retriever.setDataSource(model.mediaPath);
            byte[] picture = retriever.getEmbeddedPicture();
            if (null != picture) {
                callback.onDataReady(new ByteArrayInputStream(picture));
            } else {
                callback.onDataReady(fallback(model.mediaPath));
            }
        } finally {
            retriever.release();
        }

    }

    @Override
    public void cleanup() {
        try {
            if (null != stream) {
                stream.close();
            }
        } catch (IOException ignore) { }
    }

    @Override
    public void cancel() {
        // cannot cancel
    }


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

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


    public static final String[] FALLBACKS = {"cover.jpg", "album.jpg", "folder.jpg"};

    private InputStream fallback(String path) {
        File parent = new File(path).getParentFile();
        for (String fallback : FALLBACKS) {
            // TODO make it smarter by enumerating folder contents and filtering for files
            // example algorithm for that: http://askubuntu.com/questions/123612/how-do-i-set-album-artwork
            File cover = new File(parent, fallback);
            if (cover.exists()) {
                try {
                    return stream = new FileInputStream(cover);
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

}
AudioCoverLoader.java

public class AudioCoverModel {

    public String mediaPath;

    public AudioCoverModel(String path) {
        this.mediaPath = path;
    }

    @Override
    public int hashCode() {
        return Math.abs((mediaPath.getBytes().length + mediaPath.hashCode()));
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;

        if (obj == null || obj.getClass() != this.getClass()) return false;

        AudioCoverModel compare = (AudioCoverModel) obj;

        try {
            return (compare.mediaPath.equals(this.mediaPath) && compare.mediaPath.getBytes().length == this.mediaPath.getBytes().length);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }


}
public class AudioCoverModule extends AppGlideModule {


    @Override
    public boolean isManifestParsingEnabled() {
        return false;
    }

    @Override
    public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
        super.applyOptions(context, builder);
    }

    @Override
    public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
        registry.append(AudioCoverModel.class, InputStream.class, new AudioCoverLoader.Factory());
    }

}
class AudioCoverLoader implements ModelLoader<AudioCoverModel, InputStream> {

    @NonNull
    @Override
    public LoadData<InputStream> buildLoadData(@NonNull AudioCoverModel AudioCoverModel, int width, int height, @NonNull Options options) {
        return new LoadData<>(new ObjectKey(AudioCoverModel), new AudioCoverFetcher(AudioCoverModel));
    }

    @Override
    public boolean handles(@NonNull AudioCoverModel AudioCoverModel) {
        return true;
    }

    static class Factory implements ModelLoaderFactory<AudioCoverModel, InputStream> {
        @NonNull
        @Override
        public ModelLoader<AudioCoverModel, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {
            return new AudioCoverLoader();
        }

        @Override
        public void teardown() {

        }
    }

}
public class AudioCoverFetcher implements DataFetcher<InputStream> {

    private final AudioCoverModel model;
    private FileInputStream stream;

    AudioCoverFetcher(AudioCoverModel model) {
        this.model = model;
    }

    @Override
    public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        try {
            retriever.setDataSource(model.mediaPath);
            byte[] picture = retriever.getEmbeddedPicture();
            if (null != picture) {
                callback.onDataReady(new ByteArrayInputStream(picture));
            } else {
                callback.onDataReady(fallback(model.mediaPath));
            }
        } finally {
            retriever.release();
        }

    }

    @Override
    public void cleanup() {
        try {
            if (null != stream) {
                stream.close();
            }
        } catch (IOException ignore) { }
    }

    @Override
    public void cancel() {
        // cannot cancel
    }


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

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


    public static final String[] FALLBACKS = {"cover.jpg", "album.jpg", "folder.jpg"};

    private InputStream fallback(String path) {
        File parent = new File(path).getParentFile();
        for (String fallback : FALLBACKS) {
            // TODO make it smarter by enumerating folder contents and filtering for files
            // example algorithm for that: http://askubuntu.com/questions/123612/how-do-i-set-album-artwork
            File cover = new File(parent, fallback);
            if (cover.exists()) {
                try {
                    return stream = new FileInputStream(cover);
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

}
类AudioCoverLoader实现ModelLoader{
@非空
@凌驾
public LoadData buildLoadData(@NonNull AudioCoverModel AudioCoverModel,int-width,int-height,@NonNull-Options){
返回新的LoadData(新的ObjectKey(AudioCoverModel)、新的AudioCoverFetcher(AudioCoverModel));
}
@凌驾
公共布尔句柄(@NonNull AudioCoverModel AudioCoverModel){
返回true;
}
静态类工厂实现ModelLoaderFactory{
@非空
@凌驾
公共模型加载程序生成(@NonNull multiveloaderfactory multiFactory){
返回新的AudioCoverLoader();
}
@凌驾
公共无效拆卸(){
}
}
}
AudioCoverFetcher.java

public class AudioCoverModel {

    public String mediaPath;

    public AudioCoverModel(String path) {
        this.mediaPath = path;
    }

    @Override
    public int hashCode() {
        return Math.abs((mediaPath.getBytes().length + mediaPath.hashCode()));
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;

        if (obj == null || obj.getClass() != this.getClass()) return false;

        AudioCoverModel compare = (AudioCoverModel) obj;

        try {
            return (compare.mediaPath.equals(this.mediaPath) && compare.mediaPath.getBytes().length == this.mediaPath.getBytes().length);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }


}
public class AudioCoverModule extends AppGlideModule {


    @Override
    public boolean isManifestParsingEnabled() {
        return false;
    }

    @Override
    public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
        super.applyOptions(context, builder);
    }

    @Override
    public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
        registry.append(AudioCoverModel.class, InputStream.class, new AudioCoverLoader.Factory());
    }

}
class AudioCoverLoader implements ModelLoader<AudioCoverModel, InputStream> {

    @NonNull
    @Override
    public LoadData<InputStream> buildLoadData(@NonNull AudioCoverModel AudioCoverModel, int width, int height, @NonNull Options options) {
        return new LoadData<>(new ObjectKey(AudioCoverModel), new AudioCoverFetcher(AudioCoverModel));
    }

    @Override
    public boolean handles(@NonNull AudioCoverModel AudioCoverModel) {
        return true;
    }

    static class Factory implements ModelLoaderFactory<AudioCoverModel, InputStream> {
        @NonNull
        @Override
        public ModelLoader<AudioCoverModel, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {
            return new AudioCoverLoader();
        }

        @Override
        public void teardown() {

        }
    }

}
public class AudioCoverFetcher implements DataFetcher<InputStream> {

    private final AudioCoverModel model;
    private FileInputStream stream;

    AudioCoverFetcher(AudioCoverModel model) {
        this.model = model;
    }

    @Override
    public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        try {
            retriever.setDataSource(model.mediaPath);
            byte[] picture = retriever.getEmbeddedPicture();
            if (null != picture) {
                callback.onDataReady(new ByteArrayInputStream(picture));
            } else {
                callback.onDataReady(fallback(model.mediaPath));
            }
        } finally {
            retriever.release();
        }

    }

    @Override
    public void cleanup() {
        try {
            if (null != stream) {
                stream.close();
            }
        } catch (IOException ignore) { }
    }

    @Override
    public void cancel() {
        // cannot cancel
    }


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

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


    public static final String[] FALLBACKS = {"cover.jpg", "album.jpg", "folder.jpg"};

    private InputStream fallback(String path) {
        File parent = new File(path).getParentFile();
        for (String fallback : FALLBACKS) {
            // TODO make it smarter by enumerating folder contents and filtering for files
            // example algorithm for that: http://askubuntu.com/questions/123612/how-do-i-set-album-artwork
            File cover = new File(parent, fallback);
            if (cover.exists()) {
                try {
                    return stream = new FileInputStream(cover);
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

}
公共类AudioCoverFetcher实现数据获取程序{
私人最终音频模型;
私有文件输入流;
AudioCoverFetcher(AudioCoverModel型号){
this.model=模型;
}
@凌驾

public void loadData(@NonNull Priority Priority,@NonNull DataCallback用@GlideModule注释注释AudioCoverModule类,然后构建应用程序,否则它将抛出此错误

@GlideModule
public class AudioCoverModule extends AppGlideModule {


    @Override
    public boolean isManifestParsingEnabled() {
        return false;
    }

    @Override
    public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
        super.applyOptions(context, builder);
    }

    @Override
    public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
        registry.append(AudioCoverModel.class, InputStream.class, new AudioCoverLoader.Factory());
    }

}

使用@GlideModule注释对AudioCoverModule类进行注释,然后构建应用程序,否则它将抛出此错误

@GlideModule
public class AudioCoverModule extends AppGlideModule {


    @Override
    public boolean isManifestParsingEnabled() {
        return false;
    }

    @Override
    public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
        super.applyOptions(context, builder);
    }

    @Override
    public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
        registry.append(AudioCoverModel.class, InputStream.class, new AudioCoverLoader.Factory());
    }

}