如何使ViewModel观察者最初不观察?

问题描述 投票:0回答:1

我通过onCreateOptionsMenu(菜单菜单)在工具栏上有一个SearchView图标。单击该图标将创建一个EditText行,以供用户输入搜索输入。我有一个TextWatcher()附加到EditText行,以便将文本添加到该行(afterTextChanged Editable)时,将通过搜索Room数据库的ViewModel运行searchQuery方法。

我的问题是,即使在用户输入任何查询之前,观察者也会在创建时触发。使用Toasts,我可以确认观察者是否在用户按下SearchView图标时以及在用户输入任何搜索查询之前正在运行空白查询“ %%”。即使在afterTextChanged()中设置了观察者,也会发生这种情况。如何使ViewModel观察器仅在用户输入文本后才触发?

Activity
...
@Override
public boolean onCreateOptionsMenu(Menu menu) {

getMenuInflater().inflate(R.menu.mainactiv_menu, menu);
searchItem = menu.findItem(R.id.action_search);
menu.findItem(R.id.action_search).setVisible(false);
if (cardsAdapter != null && cardsAdapter.getItemCount() > 0) {
    menu.findItem(R.id.action_search).setVisible(true);
}
SearchManager searchManager = (SearchManager) MainActivity.this.getSystemService(Context.SEARCH_SERVICE);
if (searchItem != null) {
    mSearchView = (SearchView) searchItem.getActionView();
    if (mSearchView != null) {
        mSearchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
        EditText mSearchEditText = mSearchView.findViewById(androidx.appcompat.R.id.search_src_text);
        mSearchEditText.setInputType(android.text.InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
        mSearchEditText.addTextChangedListener(new TextWatcher() {

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
               // not needed
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                // not needed
            }

            @Override
            public void afterTextChanged(Editable s) {

                String queryText = "%" + s.toString() + "%";

                mQuickcardViewModel.searchQuery(queryText).observe(MainActivity.this, searchCards -> {

                    searchList = searchCards;

                    if (!mSearchView.isIconified() && searchList.size() > 0) {
                        // do something
                    } 

                    ...     
android android-viewmodel android-textwatcher
1个回答
2
投票

如何使ViewModel观察器仅在用户输入文本后才触发?

在观察之前使用if语句查看字符串是否为空:

@Override
public void afterTextChanged(Editable s) {
     if (s.toString().size > 0) {
         // the rest of your code goes here, preferably with some modifications
     }
}

我建议的其他更改包括:

  • 添加一些“去抖动”措施。给定您的搜索表达式,您似乎正在访问searchQuery()中的数据库。如果用户快速连续键入10个字符,则将进行10个查询,这将使性能变差。 “反跳”表示“仅在用户暂停一会后才进行查询”,例如500毫秒,没有任何其他输入。

  • 在需要时添加智能功能以取消未完成的查询。假设用户键入了一点,然后经过了反跳周期。因此,您将触发查询。由于您的(假定的)LIKE表达式,您的查询将执行“表扫描”,检查表的每一行。这可能很慢,并且用户可能会在第一个查询完成之前开始输入更多内容。您不再需要该查询,因为它的结果是错误的(它用于上一个搜索表达式,而不是当前的搜索表达式)。因此,您需要一种取消该工作的方法。

  • 处理配置更改。您可能会争辩说您正在使用ViewModelLiveData,它们应该处理...并且确实可以,但前提是您正确使用它们。在您的情况下,您似乎在观察LiveData后就将其扔掉了,依此类推,在进行配置更改时,您将无法重新观察它。这就是为什么许多样本专注于将“请做背景工作”与“请给我背景工作的结果”分离的原因。您仍然可以拥有一个调用的searchQuery()方法,但是它将返回void。结果将通过LiveData保留的某些ViewModel传递,您可以在onCreate()中观察到。这样,在更改配置后,您将再次观察到LiveData,并获得更改之前的数据。

  • 使用FTS。 LIKE慢。如果您打算这样做,请考虑在SQLite中使用FTS3 / FTS4进行全文搜索。如果您使用的是Room,则Room 2.2.0中对此提供了内置支持。

© www.soinside.com 2019 - 2024. All rights reserved.