Realm Java:合并一对多关联的Task与Subtask列表并实现排序过滤
嘿,这个需求我之前做过类似的,给你分享下具体的实现思路和代码片段,应该能帮你快速搞定!
核心思路
因为Realm不支持跨不同对象类型的联合查询,所以我们需要先把Task和Subtask统一包装成一个通用类,再合并成列表处理排序和过滤,最后用RecyclerView适配器展示。
1. 创建通用包装类
首先定义一个TaskItemWrapper,用来统一Task和Subtask的公共字段,这样适配器可以无缝处理两种类型:
public class TaskItemWrapper { private RealmObject item; // 存储Task或Subtask实例 public TaskItemWrapper(RealmObject item) { this.item = item; } // 统一获取标题 public String getTitle() { if (item instanceof Task) { return ((Task) item).getTitle(); } else if (item instanceof Subtask) { return ((Subtask) item).getTitle(); } return ""; } // 统一获取截止日期 public Date getDeadline() { if (item instanceof Task) { return ((Task) item).getDeadline(); } else if (item instanceof Subtask) { return ((Subtask) item).getDeadline(); } return null; } // 统一获取分类(假设Subtask继承所属Task的分类) public String getCategory() { if (item instanceof Task) { return ((Task) item).getCategory(); } else if (item instanceof Subtask) { return ((Subtask) item).getTask().getCategory(); } return ""; } // 获取原始对象,方便后续区分处理 public RealmObject getItem() { return item; } }
2. 合并并监听Realm数据变化
我们需要监听Task和Subtask的实时变化,每次数据更新时重新合并列表并排序:
private Realm realm; private List<TaskItemWrapper> mergedTaskList = new ArrayList<>(); private MergedTaskAdapter taskAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_task_list); realm = Realm.getDefaultInstance(); initRecyclerView(); setupRealmListeners(); } private void initRecyclerView() { RecyclerView recyclerView = findViewById(R.id.task_recycler); recyclerView.setLayoutManager(new LinearLayoutManager(this)); taskAdapter = new MergedTaskAdapter(mergedTaskList); recyclerView.setAdapter(taskAdapter); } private void setupRealmListeners() { // 异步获取所有Task和Subtask RealmResults<Task> tasks = realm.where(Task.class).findAllAsync(); RealmResults<Subtask> subtasks = realm.where(Subtask.class).findAllAsync(); // 添加数据变化监听器 tasks.addChangeListener((collection, changeSet) -> refreshMergedList()); subtasks.addChangeListener((collection, changeSet) -> refreshMergedList()); } private void refreshMergedList() { mergedTaskList.clear(); // 添加所有Task for (Task task : realm.where(Task.class).findAll()) { mergedTaskList.add(new TaskItemWrapper(task)); } // 添加所有Subtask for (Subtask subtask : realm.where(Subtask.class).findAll()) { mergedTaskList.add(new TaskItemWrapper(subtask)); } // 默认按截止日期排序 sortByDeadline(); taskAdapter.notifyDataSetChanged(); }
3. 实现排序功能
添加两种排序逻辑,绑定到UI按钮即可:
// 按截止日期排序(空日期放最后) private void sortByDeadline() { Collections.sort(mergedTaskList, (item1, item2) -> { Date d1 = item1.getDeadline(); Date d2 = item2.getDeadline(); if (d1 == null && d2 == null) return 0; if (d1 == null) return 1; if (d2 == null) return -1; return d1.compareTo(d2); }); } // 按名称字母排序(忽略大小写) private void sortByName() { Collections.sort(mergedTaskList, (item1, item2) -> item1.getTitle().compareToIgnoreCase(item2.getTitle()) ); }
4. 实现搜索过滤功能
支持按分类和名称双重过滤,这里直接更新适配器数据源:
// 过滤方法:category为空则不限制分类,searchQuery为空则不限制名称 public void filterTasks(String category, String searchQuery) { List<TaskItemWrapper> filteredList = new ArrayList<>(); String lowerQuery = searchQuery.toLowerCase(); for (TaskItemWrapper item : mergedTaskList) { boolean matchCategory = category.isEmpty() || item.getCategory().equalsIgnoreCase(category); boolean matchName = searchQuery.isEmpty() || item.getTitle().toLowerCase().contains(lowerQuery); if (matchCategory && matchName) { filteredList.add(item); } } taskAdapter.updateData(filteredList); }
对应的适配器要支持更新数据源:
public class MergedTaskAdapter extends RecyclerView.Adapter<MergedTaskAdapter.ViewHolder> { private List<TaskItemWrapper> taskItems; public MergedTaskAdapter(List<TaskItemWrapper> taskItems) { this.taskItems = taskItems; } // 更新数据源并通知UI public void updateData(List<TaskItemWrapper> newItems) { this.taskItems = newItems; notifyDataSetChanged(); } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_task, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { TaskItemWrapper item = taskItems.get(position); holder.titleTv.setText(item.getTitle()); holder.deadlineTv.setText(item.getDeadline() != null ? new SimpleDateFormat("yyyy-MM-dd").format(item.getDeadline()) : "无截止日期"); holder.categoryTv.setText(item.getCategory()); // 区分Task和Subtask:给Subtask加缩进 if (item.getItem() instanceof Subtask) { holder.itemView.setPadding( dpToPx(holder.itemView.getContext(), 32), holder.itemView.getPaddingTop(), holder.itemView.getPaddingRight(), holder.itemView.getPaddingBottom() ); } else { holder.itemView.setPadding(0, holder.itemView.getPaddingTop(), holder.itemView.getPaddingRight(), holder.itemView.getPaddingBottom()); } } @Override public int getItemCount() { return taskItems.size(); } static class ViewHolder extends RecyclerView.ViewHolder { TextView titleTv, deadlineTv, categoryTv; public ViewHolder(@NonNull View itemView) { super(itemView); titleTv = itemView.findViewById(R.id.tv_task_title); deadlineTv = itemView.findViewById(R.id.tv_deadline); categoryTv = itemView.findViewById(R.id.tv_category); } } // 工具方法:dp转px private int dpToPx(Context context, int dp) { return (int) (dp * context.getResources().getDisplayMetrics().density); } }
关键注意事项
- Realm生命周期管理:在Activity/Fragment的
onDestroy方法中记得关闭Realm并移除监听器,避免内存泄漏:@Override protected void onDestroy() { super.onDestroy(); if (realm != null && !realm.isClosed()) { realm.close(); } } - 性能优化:如果数据量很大,建议用RxJava异步处理合并和排序,避免阻塞主线程;也可以考虑给Task和Subtask的查询结果提前排序,减少后续排序开销。
- UI区分:通过缩进、图标或字体样式区分Task和Subtask,提升用户体验。
内容的提问来源于stack exchange,提问作者jdkay
相关产品推荐
相关产品推荐

