在背景中在回收视图中显示封面艺术(来自 id3)



我正在开发一个使用回收视图显示mp3文件的应用程序,提供其封面艺术图像以及其他信息。它可以工作,但一旦它开始处理十几个或更多的封面艺术来检索,它就会很慢,因为我目前正在从主线程上的 id3 执行此操作,我知道这不是一个好主意。 理想情况下,我会使用占位符,以便在图像可用时可以添加图像。我一直在研究将检索移动到后台线程,并查看了不同的选项:AsyncTask,Service,WorkManager。AsyncTask似乎不是要走的路,因为我面临内存泄漏(我需要上下文来通过MetadataRetriever检索封面艺术(。所以我倾向于远离这一点。然而,我正在努力弄清楚哪种方法最适合我的情况。

据我了解,我需要找到一种允许多线程的方法,以及在用户已经移动(滚动或导航离开(的情况下取消检索的方法。我已经在使用 Glide,我知道它应该有助于缓存。 我知道我可以重新设计整个方法并将封面艺术作为图像单独提供,但这对我来说似乎是最后的手段,因为我宁愿不要用更多的数据来压垮应用程序。

该应用程序的当前版本在这里(请注意它不会运行,因为我无法公开透露某些方面(。我正在按如下方式检索封面艺术(在主线程上(:

static public Bitmap getCoverArt(Uri medUri, Context ctxt) {
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource(ctxt, medUri);
byte[] data = mmr.getEmbeddedPicture();
if (data != null) {
return BitmapFactory.decodeByteArray(data, 0, data.length);
} else {
return null;
}
}

我已经找到了很多使用AsyncTask或只是将MetaDataRetriever保留在主线程上的例子,但还没有找到一个示例可以在不减慢主线程速度的情况下检索十几个或更多的封面艺术。我将不胜感激任何帮助和指点。

事实证明,它确实适用于 AsyncTask,只要它本身不是一个类,而是从具有上下文的类设置和调用。这是我的方法的精简版本(我从我的适配器中调用它。

//set up titles and placeholder image so we needn't wait on the image to load
titleTv.setText(selectedMed.getTitle());
subtitleTv.setText(selectedMed.getSubtitle());
imageIv.setImageResource(R.drawable.ic_launcher_foreground);
imageIv.setAlpha((float) 0.2);
final long[] duration = new long[1];
//a Caching system that helps reduce the amount of loading needed. See: https://github.com/cbonan/BitmapFun?files=1
if (lruCacheManager.getBitmapFromMemCache(selectedMed.getId() + position) != null) {

是否有较早的缓存映像可供重用? imageIv.setImageBitmap(lruCacheManager.getBitmapFromMemCache(selectedMed.getId(( + position((; imageIv.setAlpha((float( 1.0(;

titleTv.setVisibility(View.GONE);
subtitleTv.setVisibility(View.GONE);
} else {
//time to load and show the image. For good measure, the duration is also queried, as this also needs the setDataSource which causes slow down
new AsyncTask<Uri, Void, Bitmap>() {
@Override
protected Bitmap doInBackground(Uri... uris) {
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource(ctxt, medUri);
byte[] data = mmr.getEmbeddedPicture();
Log.v(TAG, "async data: " + Arrays.toString(data));
String durationStr = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
duration[0] = Long.parseLong(durationStr);
if (data != null) {
InputStream is = new ByteArrayInputStream(mmr.getEmbeddedPicture());
return BitmapFactory.decodeStream(is);
} else {
return null;
}
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
durationTv.setVisibility(View.VISIBLE);
durationTv.setText(getDisplayTime(duration[0], false));
if (bitmap != null) {
imageIv.setImageBitmap(bitmap);
imageIv.setAlpha((float) 1.0);
titleTv.setVisibility(View.GONE);
subtitleTv.setVisibility(View.GONE);
} else {
titleTv.setVisibility(View.VISIBLE);
subtitleTv.setVisibility(View.VISIBLE);
}
lruCacheManager.addBitmapToMemCache(bitmap, selectedMed.getId() + position);
}
}.execute(medUri);
}

我尝试使用 Glide 进行缓存,但我无法将 TextView 的显示/隐藏链接到是否存在位图。在某种程度上,这更时尚,因为我不需要加载大部分 Glide 库。所以我现在对此感到满意。

最新更新