Android应用专辑封面无法显示问题求助
解决Android专辑封面加载失败及相关日志问题
看起来你遇到了几个关联的问题,咱们一步步来拆解解决:
1. 先处理日志里的两个基础问题
「No adapter attached; skipping layout」错误
这个错误说明你的RecyclerView在布局渲染的时候还没有绑定Adapter。正确的做法是先初始化空Adapter并设置给RecyclerView,之后再加载数据更新:
// 在Fragment/Activity的初始化代码里(比如onCreateView/onCreate) _songs = new ArrayList<>(); songAdapter adapter = new songAdapter(getContext(), _songs); recyclerView.setAdapter(adapter); // 之后再调用加载数据的方法
「Skipped 51 frames!」主线程阻塞问题
你直接在主线程里查询MediaStore,这会阻塞UI线程导致卡顿。必须把数据查询放到后台线程,用AsyncTask(Java)来处理,示例代码如下:
private class LoadSongsTask extends AsyncTask<Void, Void, ArrayList<songInfo>> { @Override protected ArrayList<songInfo> doInBackground(Void... voids) { ArrayList<songInfo> songs = new ArrayList<>(); Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; String selection = MediaStore.Audio.Media.IS_MUSIC + "!=0"; String[] projection = { MediaStore.Audio.Media.DISPLAY_NAME, MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.ALBUM_ID }; Cursor cursor = getContext().getContentResolver().query(uri, projection, selection, null, null); if (cursor != null) { int albumIdColumn = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID); if (cursor.moveToFirst()) { do { String name = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME)); String artist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST)); String url = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA)); long albumId = cursor.getLong(albumIdColumn); songs.add(new songInfo(name, artist, url, albumId)); } while (cursor.moveToNext()); } cursor.close(); } return songs; } @Override protected void onPostExecute(ArrayList<songInfo> songs) { super.onPostExecute(songs); _songs.clear(); _songs.addAll(songs); recyclerView.getAdapter().notifyDataSetChanged(); } } // 调用方式 new LoadSongsTask().execute();
2. 专辑封面加载失败的核心问题
这是你最头疼的问题,主要有两个关键错误:
错误1:存错了ID!
你在loadSongs里把歌曲的ID当成专辑ID存进了songInfo,这完全不对!应该获取MediaStore.Audio.Media.ALBUM_ID:
// 修改loadSongs里的专辑ID获取代码 int albumIdColumn = cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID); long albumId = cursor.getLong(albumIdColumn);
错误2:直接把ID转成路径是无效的
专辑ID不是文件路径,你需要通过专辑ID构造对应的Content Uri,或者查询专辑表获取封面路径。最省心的方式是用Glide这类图片加载库,它们能直接处理Content Uri,还自带缓存和错误处理:
// 在Adapter的onBindViewHolder里替换封面加载代码 Uri albumArtUri = ContentUris.withAppendedId( MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, s.getAlbum_art() // 现在这个是正确的专辑ID了 ); Glide.with(context) .load(albumArtUri) .placeholder(R.drawable.your_default_cover) // 加载中的占位图 .error(R.drawable.your_default_cover) // 加载失败时显示的图 .into(songHolder.album_art);
记得先在app的build.gradle里添加Glide的依赖:
implementation 'com.github.bumptech.glide:glide:4.16.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'
额外优化:修复Adapter的点击事件
你原来在onBindViewHolder里每次都设置setOnItemClickListener,这会导致重复绑定,效率很低。改成直接给ViewHolder的itemView设置点击事件:
// 在Adapter的onBindViewHolder里 songHolder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mOnItemClickListener != null) { mOnItemClickListener.onItemClick(songHolder, v, s, i); } } });
然后把原来的setOnItemClickListener调用移到Adapter外部(比如你的Fragment/Activity里),这样才是正确的用法。
最后总结修改步骤
- 提前给RecyclerView设置空Adapter
- 把数据查询逻辑移到AsyncTask后台线程
- 修正专辑ID的获取方式,存正确的ALBUM_ID
- 用Glide加载专辑封面,替换原来的错误路径转换
- 修复Adapter的点击事件绑定逻辑
按照这些步骤修改后,你的专辑封面应该能正常显示,日志里的错误也会消失。
内容的提问来源于stack exchange,提问作者devesh kumawat
相关产品推荐
相关产品推荐

