Android Glide-使用自定义MediaLoader和MetadataRetriever加载音频封面艺术
下面的示例是从本地音频文件生成缩略图,并使用Glide v4在RecyclerView中显示它们 但正如您在链接中所看到的,示例是使用glide 3,我试图使代码与glide 4兼容,但我一直得到以下例外: com.bumptech.glide.Registry$NoModelLoaderAvailableException:未能找到模型的任何ModelLoader:com.symphonyrecords.mediacomp.design.glideUtil.audioCoverLoader。AudioCoverModel@7a3c7c9f 你能帮我找出问题出在哪里吗 在我的适配器内部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
@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());
}
}