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

RecyclerView侧滑删除后重复添加最后一项问题求助

问题分析与解决方案

看起来你遇到的重复条目问题,根源在于数据源与UI不同步、文件操作逻辑错误这几个核心问题,我们一步步拆解并修复:

核心问题总结

  1. 每次启动Activity都会重建所有文件:onCreate里的文件创建循环没有检查文件是否存在,导致删除的文件会被立刻重新生成。
  2. 侧滑删除未更新数据源:只调用了notifyItemRemoved(position),但没有从recordingArrayList中移除对应元素,导致Adapter的数据源和UI状态不一致。
  3. 文件删除的文件名计算错误:用position-1作为文件序号,比如第一个条目(position=0)会生成Recording-1.txt,根本无法删除正确的目标文件。
  4. 文件读取逻辑混乱:拼接所有文件内容再分割的方式,导致无法正确将单个文件内容对应到RecyclerView的条目。

修复后的完整代码与说明

1. 修复文件创建逻辑(仅在文件不存在时创建)

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my_recordings);

    // 仅当文件不存在时创建,避免删除后重建
    for(int i=0;i<5;i++){
        try{
            userRecordingFile = new File(createRecordingFiles(), "Recording"+i+".txt");
            if (!userRecordingFile.exists()) {
                FileWriter writer = new FileWriter(userRecordingFile);
                writer.append("DEF"+i+"__HIJ "+i+"__\n");
                writer.flush();
                writer.close();
            }
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    getSupportActionBar().hide();
    recordingArrayList=new ArrayList<>();
    recyclerView=findViewById(R.id.recyclerView);
    recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
    recyclerView.setHasFixedSize(true);
    itemTouchHelper.attachToRecyclerView(recyclerView);

    // 读取文件内容到数据源
    readFiles();

    recordingsAdapter=new RecordingsAdapter(recordingArrayList);
    recyclerView.setAdapter(recordingsAdapter);
}

2. 修复侧滑删除逻辑(同步数据源与文件操作)

ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        return false;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
        final int position = viewHolder.getAdapterPosition();
        // 1. 先从数据源移除对应条目
        recordingArrayList.remove(position);
        // 2. 通知Adapter更新UI
        recordingsAdapter.notifyItemRemoved(position);
        // 3. 删除对应的文件(position直接对应文件序号,无需减1)
        File workDir = new File(getExternalCacheDir(), USER_MIX_DIR);
        File file = new File(workDir, "Recording" + position + ".txt");
        if (file.delete()) {
            Toast.makeText(getApplicationContext(), "Removed item " + (position+1), Toast.LENGTH_LONG).show();
        } else {
            Toast.makeText(getApplicationContext(), "Failed to delete file", Toast.LENGTH_LONG).show();
            // 删除失败时恢复条目,避免数据源与文件不一致
            recordingArrayList.add(position, new Recording(R.drawable.ic_launcher, "DEF"+position, "HIJ "+position));
            recordingsAdapter.notifyItemInserted(position);
        }
    }
};

3. 修复文件读取逻辑(逐个解析文件内容)

public void readFiles(){
    recordingArrayList.clear(); // 清空旧数据
    File workDir = new File(getExternalCacheDir(), USER_MIX_DIR);
    
    for(int i=0;i<5;i++){
        File file = new File(workDir,"Recording"+i+".txt");
        if (!file.exists()) continue; // 跳过已删除的文件
        
        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader(file));
            String line;
            while ((line = br.readLine()) != null) {
                String[] parts = line.split("__");
                if (parts.length >= 2) {
                    // 将单个文件内容解析为Recording对象,添加到数据源
                    recordingArrayList.add(new Recording(R.drawable.ic_launcher, parts[0].trim(), parts[1].trim()));
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

额外优化建议

  • 如果未来文件数量不是固定5个,可以遍历目录下的所有.txt文件,而不是固定循环5次,提升灵活性。
  • 建议给RecordingsAdapter添加更新数据源的方法,方便后续批量更新:
    public void updateData(ArrayList<Recording> newData) {
        mData.clear();
        mData.addAll(newData);
        notifyDataSetChanged();
    }
    

内容的提问来源于stack exchange,提问作者user8412632

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:45:05