首页 > 解决方案 > Glide - load audio cover art using custom MediaLoader and MetadataRetriever

问题描述

I'm following this example to generate thumbnail from local audio files and to show them in a RecyclerView using Glide v4.

but as you can see in the link, the example is using glide 3, I tried to make codes compatible with Glide 4 but I keep getting below exception:

com.bumptech.glide.Registry$NoModelLoaderAvailableException: Failed to find any ModelLoaders for model: com.symphonyrecords.mediacomp.design.glideUtil.audioCoverLoader.AudioCoverModel@7a3c7c9f

Can you help me to find where is the problem?

Inside my Adapter

@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;
    }


}

AudioCoverModule.java

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());
    }

}

AudioCoverLoader.java

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() {

        }
    }

}

AudioCoverFetcher.java

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;
    }

}

标签: androidandroid-glide

解决方案


使用@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());
    }

}

推荐阅读