Android SearchView.OnQueryTextListener OnQueryTextSubmit not fired on empty query string

爱⌒轻易说出口 提交于 2019-11-27 20:06:28

It is not a bug, the source code deliberately checks against null and empty values:

private void onSubmitQuery() {
    CharSequence query = mQueryTextView.getText();
    if (query != null && TextUtils.getTrimmedLength(query) > 0) {

However you should be able to use the OnQueryTextChange callback to clear your ListView's filterables when the user clears the search EditText.

ive an easier work around: use onQueryTextChange, but only render if its empty.

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                    renderList(true);
                    return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                    if (searchView.getQuery().length() == 0) {
                            renderList(true);
                    }
                    return false;
            }
    });

I had the same problem and end up with the following solution: custom SearchView + OnQueryTextListener.onQueryTextChange

Custom SearchView:

public class MySearchView extends SearchView {

private boolean expanded;

public MySearchView(Context context) {
    super(context);
}

@Override
public void onActionViewExpanded() {
    super.onActionViewExpanded();
    expanded = true;
}

@Override
public void onActionViewCollapsed() {
    super.onActionViewCollapsed();
    expanded = false;
}

public boolean isExpanded() {
    return expanded;
}
}

Creating action and setting callback:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    super.onCreateOptionsMenu(menu, inflater);
    searchAction = menu.add(0, SEARCH_ACTION_ID, 0 , getString(R.string.action_search));
    searchAction.setShowAsAction(SHOW_AS_ACTION_ALWAYS | SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);       
    searchView = new MySearchView(getSherlockActivity());
    searchView.setOnQueryTextListener(searchQueryListener);
    searchView.setIconifiedByDefault(true);
    searchAction.setActionView(searchView);
}

And last the listener:

private OnQueryTextListener searchQueryListener = new OnQueryTextListener() {
    @Override
    public boolean onQueryTextSubmit(String query) {
        search(query);
        return true;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        if (searchView.isExpanded() && TextUtils.isEmpty(newText)) {
            search("");
        }

        return true;
    }

    public void search(String query) {
        // reset loader, swap cursor, etc.
    }

};

Tested on ABS 4.3.

Jan Hofman

I had same issue with SearchView. My solution which consists of styling SearchView as shown in guide http://novoda.com/blog/styling-the-actionbar-searchview/ and setting OnEditorActionListener for EditText( How do I trigger an action when the user has hit enter?) which is part of the SearchView was this:

final SearchView searchView = (SearchView)findViewById(R.id.search);
int searchPlateId = searchView.getContext().getResources().getIdentifier("android:id/search_src_text", null, null);
EditText searchPlate = (EditText) searchView.findViewById(searchPlateId);
searchPlate.setOnEditorActionListener(new TextView.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {

        if (actionId == EditorInfo.IME_ACTION_SEARCH) {
            //Do something
        }
        return false;

    }});
theblang

As others have mentioned this behavior is intentional. I gave up on a solution for OnQueryChangeListener and decided to workaround by implementing OnEditorActionListener on the SearchView's EditText, which you can get a handle to using R.id.search_src_text. As long as you setImeOptions of the SearchView to EditorInfo.IME_ACTION_SEARCH you can handle a click on the keyboard search button. See this SO answer for more details.

I had the same problem, since empty query's are not supported I had to download and use ActionBarSherlock and then modify the onSubmitQuery() method.

This is how my onSubmitQuery() looks like now

private void onSubmitQuery() {
     CharSequence query = mQueryTextView.getText();
     if (query == null) {query = "";}
     if (mOnQueryChangeListener == null
             || !mOnQueryChangeListener.onQueryTextSubmit(query.toString())) {
         if (mSearchable != null) {
             launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null, query.toString());
             setImeVisibility(false);
         }
         dismissSuggestions();
     }
 }

Hope this helps.

This is a very dirty hack, however it works correctly as expected, enabling the submit action even when there is no text entered (or entered then edited) in the SearchView.

It reflectively gains access to the inner TextView editor action listener, wraps it in a custom listener where it delegates the call to the handler, and finally sets it as the action listener of the inner TextView.

    Class klass = searchView.getClass();
    try {
        Field currentListenerField = klass.getDeclaredField("mOnEditorActionListener");
        currentListenerField.setAccessible(true);
        TextView.OnEditorActionListener previousListener = (TextView.OnEditorActionListener) currentListenerField.get(searchView);
        TextView.OnEditorActionListener newListener = new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (v.getText().length() == 0)
                    handleQuery("");
                return previousListener.onEditorAction(v, actionId, event);
            }
        };
        Field innerTextViewField = klass.getDeclaredField("mSearchSrcTextView");
        innerTextViewField.setAccessible(true);
        SearchView.SearchAutoComplete innerTextView = (SearchView.SearchAutoComplete) innerTextViewField.get(searchView);
        innerTextView.setOnEditorActionListener(newListener);
    } catch (Exception e) {
        throw new IllegalStateException(e);
    }
GeeF

You cannot overwrite this behavior. A workaround could be to clear the filter, when a user exits the searchview.

You could use the OnCloseListener for this. However, this can cause problems as well, depending on the minimum API Level you are developing for.

Another option is to trigger the onQueryTextChange method manually through a TextWatcher:

public class MyActivity extends Activity implements SearchView.OnQueryTextListener, TextWatcher {

    // Basic onCreate(Bundle) here

    @Override
    public boolean onCreateOptionsMenu (final Menu menu) {
        getMenuInflater().inflate(R.menu.myMenu, menu);

        final SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
        final SearchManager manager = (SearchManager) getSystemService(SEARCH_SERVICE);
        searchView.setSearchableInfo(manager.getSearchableInfo(getComponentName()));
        searchView.setOnQueryTextListener(this);

        final int resource_edit_text = searchView.getContext().getResources().getIdentifier("android:id/search_src_text", null, null);
        ((EditText) searchView.findViewById(resource_edit_text)).addTextChangedListener(this);

        return super.onCreateOptionsMenu(menu);
    }

    // Implementation of TextWatcher, used to have a proper onQueryTextChange (it doesn't update when the last character is removed)
    @Override
    public void beforeTextChanged (final CharSequence charSequence, final int start, final int count, final int after) {}

    @Override
    public void onTextChanged (final CharSequence charSequence, final int start, final int before, final int after) {}

    @Override
    public void afterTextChanged (final Editable editable) {
        if (editable.length() == 0)
            onQueryTextChange(editable.toString());
    }

    // Implementation of OnQueryTextChangeListener

    @Override
    public boolean onQueryTextChange (final String query) {
        // do stuff
        return false;
    }

    @Override
    public boolean onQueryTextSubmit (final String query) {
        // do stuff
        return false;
    }
}

This all goes with all the default xml files which have been given up here, that is not the point of this answer. This is a workaround that I choose to use, feel free to use others

I can manage to do it simply by implementing the setOnQueryTextListener in this way:

SearchView searchView = (SearchView) menu.findItem(R.id.searchProductView).getActionView();
    searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextSubmit(String query) {
            return false;
        }

        @Override
        public boolean onQueryTextChange(String newText) {
            if (TextUtils.isEmpty(newText)) {
                loadLocalData(newText);
            }
            return true;
        }
    });

Where my loadLocalData method is

//query my DB
products = ProductDAO.findByIdList(idList);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
listView.setLayoutManager(layoutManager);
listView.setAdapter(<YOURADAPTER>)

This solution clears your query even if you clear the text with the "X" button

In my case I just wanted to enable user to clear his query as it was used as keyword in API search, so the simplest idea was:

    searchView.setOnSearchClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            userQuery = "";
        }
    });

where userQuery is my variable used for searching etc.

Hope it helps someone :)

It's an old thread but I've found another solution (Kotlin code, but works in Java as well):

override fun onQueryTextChange(newText: String?): Boolean {
            if(newText == null || newText.isEmpty())
                searchView.setQuery("\u00A0", false)
            return true
        }

\u00A0 is a character that looks like space, but code-wise it is not. In other words SearchView is not empty. Empty string or " " would not work, because base SearchView uses trim, plus user may want to search text ending or beginning with space. But as far as I know users cannot enter \u00A0 character.

Then all you need to do is override getQuery to return super.getQuery.replace("\u00A0", "") in your custom SearchView

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!