1

我正在使用提供的示例,并根据我的要求调整了代码。我正在学习 Rx,但并不完全熟悉它的工作原理。所以,在我的片段中,我有

private static String LIST_QUERY = "SELECT * FROM " + TodoItem.TABLE;

我的 onResume 看起来像:

@Override
public void onResume() {
    super.onResume();

    subscription = db.createQuery(TodoItem.TABLE, LIST_QUERY)
            .mapToList(TodoItem.MAPPER)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(adapter);
}

适配器在列表视图中显示数据,它工作正常,但现在我在列表顶部添加了一个 TextView,并且希望在用户输入文本时过滤结果。我相信 RxAndroid 提供了一个 debounce 运算符来提高效率(而不是立即查询数据库),但我不确定如何结合这个订阅代码来监听 textView 的变化并根据该文本进行过滤。

我已经尝试将 LIST_QUERY 更改为"SELECT * FROM " + TodoItem.TABLE + " WHERE " + TodoItem.DESCRIPTION + " LIKE \"" + query + "\" LIMIT 5”;

然后在尝试:

    etSearch.addTextChangedListener(new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence searchQuery, int i, int i1, int i2) {
            query = searchQuery.toString();
            adapter.notifyDataSetChanged();
        }

        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { //ignore }

        @Override
        public void afterTextChanged(Editable editable) { //ignore }
    });

这导致列表为空(我认为这没关系,因为初始查询是空字符串)但是当我输入一些文本时,查询根本没有更新/过滤列表。

我尝试了另一种方法,并在 mapToList 之后添加了 take(5) (因为我想要 LIMIT 5),这有效并且只显示了 5 个项目。然后我添加了 .filter(,输入 new 并让 Android Studio 生成 Func1 代码,它看起来像:

    subscription = db.createQuery(ListItem.TABLE, LIST_QUERY)
            .mapToList(Item.MAPPER)
            .filter(new Func1<List<ListItem>, Boolean>() {
                @Override
                public Boolean call(List<ListItem> items) {
                    return null;
                }
            })

所以问题是它要求我过滤整个列表。我试过这个:

public Boolean call(List<ListItem> items) {
   for(ListItem i: items)
      if(!i.description().startsWith(query))
          items.remove(i);
   return true;
}

但是仍然显示整个列表,并且文本中的更改根本不会使列表发生变化。我相信我错过了一些东西,我必须订阅 EditText 但我不确定我将如何做到这一点并将其与现有的数据库订阅代码结合起来。寻找解决方案。

4

1 回答 1

3

有几种不同的方法可以做到这一点。如果您希望过滤器存在于 java 中,那么您可以使用asRows运算符 on QueryObservable

database.createQuery(ListItem.TABLE, ListItem.QUERY)
  .flatMap(query -> query.asRows(Item.MAPPER)
    .filter(item -> item.description.startsWith(query))
    .toList())

这将是一个Observable<List<Item>>仅包含与查询匹配的项目。

但是,您最初的方法是理想的方法,您只是使用LIKE不正确。您可能希望包含通配符 (%_) 以包含与查询不完全匹配的结果。例如:

"SELECT * FROM " + TodoItem.TABLE + " WHERE " + TodoItem.DESCRIPTION + " LIKE \"%" + query + "%\" LIMIT 5”;

将匹配描述中包含查询的任何结果。通配符匹配 0个%或多个任意字符。_通配符匹配单个字符。

您提到的另一部分是列表没有正确更新。你想在这里使用 RxAndroid 而不是 textChangedListeners 最有可能。在您看来,您将拥有类似的东西

RxTextView.textChanges(editText)
  .switchMap(query -> database.createQuery(ListItem.TABLE, ListItem.query(query))
    .mapToList(ListItem.MAPPER))
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(list -> {
    adapter.setData(list);
    adapter.notifyDataSetChanged();
  });

这样,您就不必担心查询执行和适配器收到通知调用之间的任何竞争。该ListItem.query(query)方法只是将该 sqlite 字符串与查询组合在一起。

于 2017-02-08T13:23:57.110 回答