使用RxAndroid

时间:2017-02-08 13:03:14

标签: android rx-java rx-android sqlbrite

我正在使用提供的the sample,并根据我的要求调整了代码。我正在学习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,但我不知道如何做到这一点并将它与现有的数据库订阅代码结合起来。寻找解决方案。

1 个答案:

答案 0 :(得分:3)

有几种不同的方法可以做到这一点。如果您希望过滤器存在于java中,那么您可以使用asRows上的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字符串。