You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

切换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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 11:05:15