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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:59:58