在后台在 Recyclerview 中显示 Coverart(来自 id3)

Posted

技术标签:

【中文标题】在后台在 Recyclerview 中显示 Coverart(来自 id3)【英文标题】:Displaying Coverart (from id3) in Recyclerview in background 【发布时间】:2020-01-20 13:26:01 【问题描述】:

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

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

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

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 保留在主线程上的示例,但还没有找到一个示例可以在不减慢主线程速度的情况下检索十几个或更多封面艺术。我将不胜感激任何帮助和指示。

【问题讨论】:

【参考方案1】:

事实证明,它确实适用于 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 库。所以我现在对此很满意。

【讨论】:

以上是关于在后台在 Recyclerview 中显示 Coverart(来自 id3)的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Recyclerview 中显示图像 - Recyclerview 图像显示错误

在垂直 RecyclerView 中显示水平 RecyclerView 时获得闪烁效果

Android RecyclerView 在 notifyDataSetChanged 调用上冻结 UI

无法在 Recyclerview 中显示图像 - 文本已成功显示

在 Fragment 中显示 RecyclerView

如何在 RecyclerView 中显示“重”图像?