DEV Community

Jens Klingenberg
Jens Klingenberg

Posted on

3 2

How to use a SearchView with an empty query text submit

At the moment i’m working on an App with a search function. This alone is nothing special. Every second App has a search function. As a standard component the Android SDK offers the class SearchView. You can add an SearchView.OnQueryTextListener to it.

SearchView

SearchView.OnQueryTextListener() {
@Override public boolean onQueryTextSubmit(String s) {
return false;
}
@Override public boolean onQueryTextChange(String s) {
return false;
}
});

SearchView.OnQueryTextListener()

Where is the problem?

The App has a function that gets called when the user presses the search button on the keyboard and there is no text in the SearchView. But this is not possible with the standard SearchView.

Keyboard

Why?

onQueryTextSubmit() gets not called when the query is empty. A look in the source code tells us why:

void onSubmitQuery() {
CharSequence query = mSearchSrcTextView.getText();
if (query != null && TextUtils.getTrimmedLength(query) > 0) {
if (mOnQueryChangeListener == null
|| !mOnQueryChangeListener.onQueryTextSubmit(query.toString())) {
if (mSearchable != null) {
launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null, query.toString());
}
mSearchSrcTextView.setImeVisibility(false);
dismissSuggestions();
}
}
}
view raw onSubmitQuery() hosted with ❤ by GitHub

The listener gets called in onSubmitQuery() of SearchView, but the if-statement checks before if the query length is longer than zero.

if (query != null && TextUtils.getTrimmedLength(query) > 0) {
view raw gistfile1.txt hosted with ❤ by GitHub

How does the SearchView detect when the search button was pressed?

When you take a look which methods call onSubmitQuery() you can see that it gets called inside an OnEditorActionListener.

private final OnEditorActionListener mOnEditorActionListener = new OnEditorActionListener() {
/**
* Called when the input method default action key is pressed.
*/
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
onSubmitQuery();
return true;
}
};
view raw gistfile1.txt hosted with ❤ by GitHub

And this listener is added to the SearchAutoComplete class:

final SearchAutoComplete mSearchSrcTextView;
mSearchSrcTextView.setOnEditorActionListener(mOnEditorActionListener);
view raw gistfile1.txt hosted with ❤ by GitHub

SearchAutoComplete informs SearchView with this listener about the key press. Unfortunately SearchView doesn’t offer a possibility to replace SearchAutoComplete with an custom implementation. But let’s take a look in the constructor of SearchView to see how SearchAutoComplete gets created:

mSearchSrcTextView = findViewById(R.id.search_src_text);
view raw gistfile1.txt hosted with ❤ by GitHub

What now?

public class SearchView extends LinearLayoutCompat implements CollapsibleActionView {
view raw SearchView hosted with ❤ by GitHub

SearchView is nothing more than an extended LinearLayout. With findViewById the SearchAutoComplete inside the layout gets inflated. So it should be possible to also inflate the layout to get at the SearchAutoComplete.

I created a class that extends SearchView. Then i’ve overridden the setOnQueryTextListener() method. Since the listener already has the methods i need and I don’t have to make special changes to my existing code.

@Override public void setOnQueryTextListener(OnQueryTextListener listener) {
super.setOnQueryTextListener(listener);
this.listener = listener;
mSearchSrcTextView = this.findViewById(android.support.v7.appcompat.R.id.search_src_text);
mSearchSrcTextView.setOnEditorActionListener((textView, i, keyEvent) -> {
if (listener != null) {
listener.onQueryTextSubmit(getQuery().toString());
}
return true;
});
}

The listener gets passed to the original SearchView, but in this method I also set a listener to the SearchAutoComplete as explained above. Now every time the user clicks the search button I get the query from the SearchView and pass it to the listener. Except that onQueryTextSubmit() will also get called when the query is empty.

import android.content.Context;
import android.support.v7.widget.SearchView;
import android.util.AttributeSet;
public class EmptySubmitSearchView extends SearchView {
/*
* Created by: Jens Klingenberg (jensklingenberg.de)
* GPLv3
*
* //This SearchView gets triggered even when the query submit is empty
*
* */
SearchView.SearchAutoComplete mSearchSrcTextView;
OnQueryTextListener listener;
public EmptySubmitSearchView(Context context) {
super(context);
}
public EmptySubmitSearchView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public EmptySubmitSearchView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override public void setOnQueryTextListener(OnQueryTextListener listener) {
super.setOnQueryTextListener(listener);
this.listener = listener;
mSearchSrcTextView = this.findViewById(android.support.v7.appcompat.R.id.search_src_text);
mSearchSrcTextView.setOnEditorActionListener((textView, i, keyEvent) -> {
if (listener != null) {
listener.onQueryTextSubmit(getQuery().toString());
}
return true;
});
}
}

Source Code

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post →

Top comments (2)

Collapse
 
g3ngar profile image
gengar

Great solution, works like a charm! Could you please license it MIT or anything less aggressive that GPL? I intend to use it in the company I'm working on and there GPL licenses aren't welcome since they do not want to open-source all the proprietary code by making it GPL.

Collapse
 
tahakucukcom profile image
Taha Yasin KÜÇÜK

That's exactly what I'm looking for. Thank you Jens for the workaround.