切换Fragment时RecyclerView列表项重复翻倍问题求助
问题解决:Fragment切换时RecyclerView列表重复翻倍
问题原因
你的HomeFragment中,songsList是Fragment的成员变量,每次切换回HomeFragment时,onCreateView方法会被重新执行,而你在查询歌曲前没有清空旧的列表数据,直接往原列表中追加新查询到的歌曲,导致列表项每次切换都翻倍。另外,代码中未关闭Cursor,存在内存泄漏风险。
解决方案
方案1:每次查询前清空列表
在查询MediaStore之前,先调用songsList.clear()清空旧数据,确保每次加载都是全新的歌曲列表:
修改后的HomeFragment代码:
public class HomeFragment extends Fragment { ArrayList<AudioModel> songsList = new ArrayList<>(); RecyclerView recyclerView; TextView noMusicTextView; @SuppressLint("MissingInflatedId") @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_home, container, false); recyclerView = view.findViewById(R.id.recycler_view); noMusicTextView = view.findViewById(R.id.noSongs); // 先清空旧列表 songsList.clear(); String[] projection = { MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.DURATION, }; String selection = MediaStore.Audio.Media.IS_MUSIC + " !=0"; Cursor cursor = null; try { cursor = getActivity().getContentResolver().query( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, null, null ); if (cursor != null) { while (cursor.moveToNext()) { AudioModel songData = new AudioModel( cursor.getString(1), cursor.getString(0), cursor.getString(2) ); if (new File(songData.getPath()).exists()) { songsList.add(songData); } } } } finally { // 关闭Cursor,避免内存泄漏 if (cursor != null) { cursor.close(); } } if (songsList.size() == 0) { noMusicTextView.setVisibility(View.VISIBLE); } else { recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); recyclerView.setAdapter(new MusicListAdapter(songsList, getContext())); } return view; } }
方案2:只加载一次歌曲数据(优化)
如果本地歌曲不会频繁变动,可以只在Fragment创建时加载一次数据,避免每次切换都重复查询MediaStore:
修改后的HomeFragment代码:
public class HomeFragment extends Fragment { ArrayList<AudioModel> songsList = new ArrayList<>(); RecyclerView recyclerView; TextView noMusicTextView; // 标记是否已加载过歌曲数据 private boolean isDataLoaded = false; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 在onCreate中加载数据,只执行一次 loadSongsData(); } private void loadSongsData() { if (isDataLoaded) return; songsList.clear(); String[] projection = { MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DATA, MediaStore.Audio.Media.DURATION, }; String selection = MediaStore.Audio.Media.IS_MUSIC + " !=0"; Cursor cursor = null; try { cursor = getActivity().getContentResolver().query( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, null, null ); if (cursor != null) { while (cursor.moveToNext()) { AudioModel songData = new AudioModel( cursor.getString(1), cursor.getString(0), cursor.getString(2) ); if (new File(songData.getPath()).exists()) { songsList.add(songData); } } } } finally { if (cursor != null) { cursor.close(); } } isDataLoaded = true; } @SuppressLint("MissingInflatedId") @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_home, container, false); recyclerView = view.findViewById(R.id.recycler_view); noMusicTextView = view.findViewById(R.id.noSongs); if (songsList.size() == 0) { noMusicTextView.setVisibility(View.VISIBLE); } else { recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); recyclerView.setAdapter(new MusicListAdapter(songsList, getContext())); } return view; } }
额外注意点
- 确保
AudioModel类的equals方法正确实现(如果后续需要去重操作)。 - 访问MediaStore需要申请
READ_EXTERNAL_STORAGE权限(Android 13及以上需要READ_MEDIA_AUDIO权限),记得在Manifest中声明并动态申请。
内容的提问来源于stack exchange,提问作者Dragon 313
相关产品推荐
相关产品推荐

