Как заставить ViewModel наблюдателя не наблюдать изначально? - PullRequest
1 голос
/ 23 октября 2019

У меня есть значок SearchView на панели инструментов через onCreateOptionsMenu (меню меню). Щелчок по значку создает строку EditText для пользователя, чтобы ввести входные данные поиска. У меня есть TextWatcher (), присоединенный к строке EditText, так что при добавлении текста в строку (afterTextChanged Editable s) через SearchModel запускается метод searchQuery, который ищет базу данных Room.

Моя проблема заключается в том, чтоОбозреватель запускается при создании еще до того, как пользователь вводит какой-либо запрос. Используя тосты, я смог подтвердить, что наблюдатель запускает пустой запрос «%%» прямо при нажатии пользователем значка 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
                    } 

                    ...     

1 Ответ

3 голосов
/ 23 октября 2019

Как заставить наблюдатель ViewModel срабатывать только после ввода текста пользователем?

Используйте оператор if, чтобы увидеть, пуста ли строка перед наблюдением:

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

Другие изменения, которые я бы порекомендовал, включают:

  • Добавление некоторой меры "debounce". Учитывая ваше поисковое выражение, вы, похоже, попали в базу данных в searchQuery(). Если пользователь быстро наберет 10 символов, вы сделаете 10 запросов, что снизит производительность. «Debounce» говорит «только запрос после того, как пользователь сделал небольшую паузу», например, 500 мс без какого-либо дополнительного ввода.

  • Добавление в смарт-сообщениях для отмены невыполненного запроса при необходимости. Предположим, что пользователь набирает немного, а затем период отката истекает. Итак, вы запускаете запрос. Из-за вашего (предполагаемого) выражения LIKE ваш запрос выполнит «сканирование таблицы», изучая каждую строку таблицы. Это может быть медленным, и пользователь может начать вводить еще немного, прежде чем первый запрос завершится. Вам больше не нужен этот запрос, поскольку его результаты неверны (он относится к предыдущему поисковому выражению, а не к текущему). Итак, вам нужен способ отменить эту работу.

  • Работа с изменениями конфигурации. Вы можете утверждать, что вы используете ViewModel и LiveData, которые должны справиться с этим ... и это так, но только если вы используете их правильно. В вашем случае вы, кажется, выбрасываете LiveData после наблюдения, и поэтому при изменении конфигурации вы не будете в состоянии повторно наблюдать его. Вот почему во многих примерах основное внимание уделяется отделению «пожалуйста, сделайте фоновую работу» от «пожалуйста, дайте мне результаты фоновой работы». У вас все еще может быть метод searchQuery(), который вы вызываете, но он вернет void. Результаты будут переданы через LiveData, удерживаемый ViewModel, который вы наблюдаете в onCreate(). Таким образом, после изменения конфигурации вы снова наблюдаете это LiveData, и вы получаете данные, которые были до этого изменения конфигурации.

  • Использование FTS. LIKE медленно. Если вы собираетесь делать это много, рассмотрите возможность использования FTS3 / FTS4 в SQLite для полнотекстового поиска. Если вы используете Room, в Room 2.2.0 есть встроенная поддержка для этого.

...