You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android中RxBinding结合EditText过滤对象数组的toList()问题

问题原因分析

核心问题出在 toList() 操作符的工作机制上:

toList() 的作用是收集上游 Observable 发射的所有元素,直到上游发送 onComplete 事件,才会把收集到的所有数据打包成一个 List 一次性发射出去。如果上游 Observable 永远不发送 onCompletetoList() 就会一直处于等待状态,永远不会触发 subscribeonNext 回调。

你之前的代码里:

  • 当移除 toList() 时,上游的过滤结果会被逐个发射,所以 subscribe 能收到单个元素;
  • 但保留 toList() 时,你的上游流(比如结合文本变化后的 Observable)没有发送 onComplete,导致 toList() 一直“卡”在等待状态,自然不会输出任何结果。

另外你最初的代码还有个隐性问题:在 map 操作符里修改外部的 professionsNameList,这会导致数据重复添加(每次发射一个 Profession 对象就往列表里加一次,最终 flatMapIterable 会重复发射旧数据),而且存在线程安全风险。

解决方案

正确的做法是:每次文本变化时,创建一个独立的、会自动完成的 Observable来处理过滤逻辑,让 toList() 能正常收集结果。

示例代码如下:

// 监听EditText文本变化
RxTextView.textChangeEvents(yourEditText)
    .debounce(300, TimeUnit.MILLISECONDS) // 防抖,避免频繁触发
    .skip(1) // 跳过初始空文本(可选,根据需求调整)
    .map(event -> event.text().toString().trim())
    .switchMap(query -> {
        // 每次新查询时,创建独立的Observable处理过滤
        return Observable.fromArray(((GetStartedActivity) getActivity()).professions)
            // 过滤符合查询条件的职业
            .filter(profession -> {
                String formattedName = capitalizeFirstLetter(profession.getName());
                return formattedName.contains(query) || query.isEmpty();
            })
            // 转换为格式化后的名称
            .map(profession -> capitalizeFirstLetter(profession.getName()))
            // 收集为List,因为fromArray会自动发送onComplete,所以toList能正常工作
            .toList()
            // 把Single转换为Observable,适配switchMap的要求
            .toObservable();
    })
    .subscribe(filteredNameList -> {
        // 这里就能收到过滤后的完整列表了
        // 比如更新Adapter或本地集合
        professionsNameList.clear();
        professionsNameList.addAll(filteredNameList);
        yourAdapter.notifyDataSetChanged();
    }, throwable -> {
        // 处理错误,比如打印日志
        throwable.printStackTrace();
    });
关键细节说明
  1. switchMap 的作用:每次文本变化时,会取消之前未完成的过滤请求,只处理最新的查询,避免旧结果覆盖新结果。
  2. fromArray 的自动完成特性Observable.fromArray() 在发射完数组中所有元素后,会自动发送 onComplete,这就给了 toList() 触发的信号,让它能把所有过滤后的元素打包成 List 发射。
  3. 避免修改外部集合:所有数据处理都在 RxJava 链内部完成,最后直接拿到完整的过滤列表,不需要在操作符里修改外部的 professionsNameList,既安全又简洁。

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

火山引擎 最新活动