android - 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;
}
}
解决方案
使用@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());
}
}
推荐阅读
- c# - 尝试计算 X/0 时创建“警告”
- traefik - 带有 Traefik 的 VueJS 路由器历史模式
- linux - 如何找到两个文件之间的差异
- python - ValueError:检查目标时出错:预期 time_distributed_7 有 4 个维度,但得到了形状为 (500、18、64) 的数组
- c++ - C ++中常量属性的初始化构造函数错误
- mysql - 教义 - 删除所有实体
- python - Scraping multiple pages with python
- sql - 数据库建模与使用 SQL 指令手动创建数据库(为项目创建数据库)
- python - 用于读取的 csv 容器
- c++ - 具有嵌套结构的模板化类型别名