如何使用DiffUtil更新RecyclerView中Firebase文件上传的进度等状态数据
修改实现步骤
1. 完善FileUpdate模型类
确保该类包含所有需要存储的字段,以及用于DiffUtil匹配的唯一标识,建议用枚举定义上传状态避免硬编码常量:
public class FileUpdate { // 唯一标识,建议用文件本地绝对路径,用于区分不同条目 private String fileId; private String fileName; // 上传进度范围 0-100 private int uploadProgress; private UploadStatus uploadStatus; // 可选:存储文件本地路径,后续上传逻辑需要用到 private String localFilePath; public enum UploadStatus { PENDING, // 待上传 UPLOADING, // 上传中 SUCCESS, // 上传成功 FAILED // 上传失败 } // 补充全参构造方法、所有字段的getter、setter方法 // Java请重写equals和hashCode方法,Kotlin可直接用data class }
2. 补全适配器的DiffUtil配置
你的AdminUploadFileAdapter建议继承ListAdapter,该类内置DiffUtil处理逻辑,无需手动维护列表引用:
public class AdminUploadFileAdapter extends ListAdapter<FileUpdate, AdminUploadFileAdapter.ViewHolder> { // DiffUtil匹配规则 public static final DiffUtil.ItemCallback<FileUpdate> DIFF_CALLBACK = new DiffUtil.ItemCallback<FileUpdate>() { @Override public boolean areItemsTheSame(@NonNull FileUpdate oldItem, @NonNull FileUpdate newItem) { // 用唯一ID判断是否为同一个文件条目 return oldItem.getFileId().equals(newItem.getFileId()); } @Override public boolean areContentsTheSame(@NonNull FileUpdate oldItem, @NonNull FileUpdate newItem) { // 所有展示字段相同才不刷新条目 return oldItem.getFileName().equals(newItem.getFileName()) && oldItem.getUploadProgress() == newItem.getUploadProgress() && oldItem.getUploadStatus() == newItem.getUploadStatus(); } // 可选:实现局部刷新,仅更新变化的控件,提升性能 @Nullable @Override public Object getChangePayload(@NonNull FileUpdate oldItem, @NonNull FileUpdate newItem) { Bundle payload = new Bundle(); if (!oldItem.getFileName().equals(newItem.getFileName())) { payload.putString("KEY_FILE_NAME", newItem.getFileName()); } if (oldItem.getUploadProgress() != newItem.getUploadProgress()) { payload.putInt("KEY_PROGRESS", newItem.getUploadProgress()); } if (oldItem.getUploadStatus() != newItem.getUploadStatus()) { payload.putSerializable("KEY_STATUS", newItem.getUploadStatus()); } return payload.isEmpty() ? null : payload; } }; public AdminUploadFileAdapter() { super(DIFF_CALLBACK); } // 全量绑定条目逻辑 @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { FileUpdate item = getItem(position); holder.fileNameTv.setText(item.getFileName()); holder.progressBar.setProgress(item.getUploadProgress()); switch (item.getUploadStatus()) { case PENDING: holder.statusTv.setText("待上传"); break; case UPLOADING: holder.statusTv.setText("上传中"); break; case SUCCESS: holder.statusTv.setText("上传成功"); break; case FAILED: holder.statusTv.setText("上传失败"); break; } } // 局部刷新逻辑 @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position, @NonNull List<Object> payloads) { if (payloads.isEmpty()) { super.onBindViewHolder(holder, position, payloads); return; } Bundle changePayload = (Bundle) payloads.get(0); for (String key : changePayload.keySet()) { switch (key) { case "KEY_FILE_NAME": holder.fileNameTv.setText(changePayload.getString(key)); break; case "KEY_PROGRESS": holder.progressBar.setProgress(changePayload.getInt(key)); break; case "KEY_STATUS": FileUpdate.UploadStatus status = (FileUpdate.UploadStatus) changePayload.getSerializable(key); // 按状态更新状态文本即可 break; } } } // 原有ViewHolder、onCreateViewHolder逻辑无需大幅修改 public static class ViewHolder extends RecyclerView.ViewHolder { TextView fileNameTv, statusTv; ProgressBar progressBar; public ViewHolder(@NonNull View itemView) { super(itemView); // 控件绑定逻辑保持原有即可 } } }
3. 修改UploadActivity逻辑
不再维护三个独立列表,仅需维护一个List<FileUpdate>类型的数据源即可:
新增文件逻辑(选完文件后调用)
// 全局维护的数据源 private List<FileUpdate> fileList = new ArrayList<>(); private AdminUploadFileAdapter adapter; // 选中单个文件后执行 File selectedFile = // 你选中的文件实例 FileUpdate newFile = new FileUpdate( selectedFile.getAbsolutePath(), // fileId用本地路径保证唯一 selectedFile.getName(), 0, FileUpdate.UploadStatus.PENDING, selectedFile.getAbsolutePath() ); fileList.add(newFile); // 必须传入新的列表实例,DiffUtil才能检测到变化 adapter.submitList(new ArrayList<>(fileList));
上传进度更新逻辑
// 你已有的Firebase上传进度监听 String currentFileId = // 当前上传的文件路径,用于匹配对应条目 int newProgress = // 回调返回的最新进度 for (int i = 0; i < fileList.size(); i++) { if (fileList.get(i).getFileId().equals(currentFileId)) { FileUpdate updateFile = fileList.get(i); updateFile.setUploadProgress(newProgress); updateFile.setUploadStatus(FileUpdate.UploadStatus.UPLOADING); fileList.set(i, updateFile); break; } } // 切到主线程提交新列表 runOnUiThread(() -> adapter.submitList(new ArrayList<>(fileList)));
上传结果更新逻辑
// 上传成功/失败回调 String currentFileId = // 当前上传的文件路径 boolean isSuccess = // 上传结果 for (int i = 0; i < fileList.size(); i++) { if (fileList.get(i).getFileId().equals(currentFileId)) { FileUpdate updateFile = fileList.get(i); updateFile.setUploadStatus(isSuccess ? FileUpdate.UploadStatus.SUCCESS : FileUpdate.UploadStatus.FAILED); if (isSuccess) updateFile.setUploadProgress(100); fileList.set(i, updateFile); break; } } runOnUiThread(() -> adapter.submitList(new ArrayList<>(fileList)));
注意事项
- 所有
submitList操作必须在主线程执行,Firebase的异步回调默认在子线程,需手动切线程 - 每次提交列表必须传入新的列表实例,不能直接传入原有
fileList引用,否则DiffUtil会认为新旧列表相同,不会触发刷新 - 每个文件的进度、结果回调必须对应正确的
fileId,避免更新错条目
内容的提问来源于stack exchange,提问作者Krutarth Vaishnav
相关产品推荐
相关产品推荐

