SearchView's OnCloseListener doesn't work
سؤال
I'm trying to add support for the SearchView
in the Android 3.0+ ActionBar, but I can't get the OnCloseListener
to work.
Here's my code:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
searchView = (SearchView) menu.findItem(R.id.search_textbox).getActionView();
searchView.setOnQueryTextListener(new OnQueryTextListener() {
@Override
public boolean onQueryTextChange(String newText) {
searchLibrary(newText);
return false;
}
@Override
public boolean onQueryTextSubmit(String query) { return false; }
});
searchView.setOnCloseListener(new OnCloseListener() {
@Override
public boolean onClose() {
System.out.println("Testing. 1, 2, 3...");
return false;
}
});
return true;
}
The search works great and every is working except for the OnCloseListener
. Nothing is being printed to Logcat. Here's the Logcat for when I'm pressing the "Close" button:
02-17 13:01:52.914: I/TextType(446): TextType = 0x0
02-17 13:01:57.344: I/TextType(446): TextType = 0x0
02-17 13:02:02.944: I/TextType(446): TextType = 0x0
I've looked through the documentation and samples, but nothing seemed to change it. I'm running it on a Asus Transformer Prime and a Galaxy Nexus, both on Ice Cream Sandwich. Any ideas?
Update:
Yes - System.out.println()
does work. Here's proof:
@Override
public boolean onQueryTextChange(String newText) {
System.out.println(newText + "hello");
searchLibrary(newText);
return false;
}
Results in this Logcat:
02-17 13:04:20.094: I/System.out(21152): hello
02-17 13:04:24.914: I/System.out(21152): thello
02-17 13:04:25.394: I/System.out(21152): tehello
02-17 13:04:25.784: I/System.out(21152): teshello
02-17 13:04:26.064: I/System.out(21152): testhello
المحلول
I also meet this problem, and I have no choice but give up "oncloselistener". Instead, you can get your menuItem, then setOnActionExpandListener
. Then override unimplents methods.
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
// TODO Auto-generated method stub
Log.d("*******","onMenuItemActionExpand");
return true;
}
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
//do what you want to when close the sesarchview
//remember to return true;
Log.d("*******","onMenuItemActionCollapse");
return true;
}
نصائح أخرى
For Android API 14+ (ICS and greater) use this code:
// When using the support library, the setOnActionExpandListener() method is
// static and accepts the MenuItem object as an argument
MenuItemCompat.setOnActionExpandListener(menuItem, new OnActionExpandListener() {
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
// Do something when collapsed
return true; // Return true to collapse action view
}
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
// Do something when expanded
return true; // Return true to expand action view
}
});
For more information: http://developer.android.com/guide/topics/ui/actionbar.html#ActionView
For this problem I came up with something like this,
private SearchView mSearchView;
@TargetApi(14)
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.conversation_index_activity_menu, menu);
mSearchView = (SearchView) menu.findItem(R.id.itemSearch).getActionView();
MenuItem menuItem = menu.findItem(R.id.itemSearch);
int currentapiVersion = android.os.Build.VERSION.SDK_INT;
if (currentapiVersion >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH)
{
menuItem.setOnActionExpandListener(new OnActionExpandListener()
{
@Override
public boolean onMenuItemActionCollapse(MenuItem item)
{
// Do something when collapsed
Log.i(TAG, "onMenuItemActionCollapse " + item.getItemId());
return true; // Return true to collapse action view
}
@Override
public boolean onMenuItemActionExpand(MenuItem item)
{
// TODO Auto-generated method stub
Log.i(TAG, "onMenuItemActionExpand " + item.getItemId());
return true;
}
});
} else
{
// do something for phones running an SDK before froyo
mSearchView.setOnCloseListener(new OnCloseListener()
{
@Override
public boolean onClose()
{
Log.i(TAG, "mSearchView on close ");
// TODO Auto-generated method stub
return false;
}
});
}
return super.onCreateOptionsMenu(menu);
}
I ran into same problem on android 4.1.1. Looks like it is a known bug: https://code.google.com/p/android/issues/detail?id=25758
Anyway, as a workaround i used state change listener (when SearchView is detached from action bar, it is also closed obviously).
view.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
@Override
public void onViewDetachedFromWindow(View arg0) {
// search was detached/closed
}
@Override
public void onViewAttachedToWindow(View arg0) {
// search was opened
}
});
Above code worked well in my case.
I post same answer here: https://stackoverflow.com/a/24573266/2162924
I ended up using a bit of a hack, that works well for my purpose - not sure it'll work with all purposes. Anyway, I'm doing a check to see if the search query is empty. This is not really related to the SearchView
's OnCloseListener
though - that still doesn't work!
searchView.setOnQueryTextListener(new OnQueryTextListener() {
@Override
public boolean onQueryTextChange(String newText) {
if (newText.length() > 0) {
// Search
} else {
// Do something when there's no input
}
return false;
}
@Override
public boolean onQueryTextSubmit(String query) { return false; }
});
Well, this solved my problem:
Menu item with showAsAction="always"
<item
android:id="@+id/action_search"
android:icon="@drawable/ic_action_search"
android:title="Search"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="always"/>
and in activity
searchView.setOnCloseListener(new OnCloseListener() {
@Override
public boolean onClose() {
Log.i("SearchView:", "onClose");
searchView.onActionViewCollapsed();
return false;
}
});
I have encountered the same problem with onCloseListener not invoking for the SearchView. Understand from the bug issue raised in 25758, and some postings I have read, to invoke onCloseListener, you need to set:
searchView.setIconifiedByDefault(true);
But for my case I wanted to have the search view opened & not iconified all the time. I manage to resolve this by adding one more line below:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.search_bar, menu);
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
searchView = (SearchView) menu.findItem(R.id.search).getActionView();
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
searchView.setOnQueryTextListener(queryTextListener);
searchView.setIconifiedByDefault(true);
searchView.setIconified(false);
return true;
}
The searchView.setIconified(false) will cause the searchView to open up, despite setting the default to iconified to true in the previous line. In this way, I managed to have both a SearchView that opens up all the time & having it invoke the onCloseListener.
In order to make the OnCloseListener
work, make sure that showAsAction
is set to always
in the search menu item.
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".SearchActivity">
<item
android:id="@+id/search"
android:title="@string/search"
android:icon="@drawable/ic_search_toolbar"
app:showAsAction="always"
app:actionViewClass="android.support.v7.widget.SearchView"/>
</menu>
For MenuItemCompat
problem I added ViewTreeObserver to track the visibility state. You can check my answer here:
https://stackoverflow.com/a/28762632/1633609
Create the menu item with the app:showAsAction
set to always.
<item
android:id="@+id/action_search"
android:title="..."
android:icon="..."
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="always"/>
When creating the SearchView
in the onCreateOptionsMenu
method do something similar
inflater.inflate(R.menu.menu_search, menu);
final MenuItem item = menu.findItem(R.id.action_search);
final SearchView search = (SearchView) item.getActionView();
search.setQueryHint(getString(R.string.search_brand_item));
search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
// add your code
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
// add your code
return false;
}
});
search.setOnCloseListener(new SearchView.OnCloseListener() {
@Override
public boolean onClose() {
// add your code here
return false;
}
});
search.setIconifiedByDefault(true); // make sure to set this to true
The search.setIconifiedByDefault(true)
needs to be set to true
to call the onClose()
method on the SearchView.OnCloseListener()
created above.
The reason the OnCloseListener
is not called is because there is a bug in the Android code -- the listener is only called if you also call setIconifiedByDefault(true)
.
seems an old thread already, but I thought I got the same problem API 18 in the first beginning. After googled around, found this thread, another hour read the javadoc tried and errored for something I don't pretend fully understand in javadoc, the following work for me now:
searchView.setIconifiedByDefault(true);
// OnQueryTextListener
@Override
public boolean onQueryTextSubmit(String query) {
Log.d(tag, "onQueryTextSubmit: " + query);
return true;
}
@Override
public boolean onQueryTextChange(String query) {
Log.d(tag, "onQueryTextChange: " + query);
return true;
}
// OnCloseListener
@Override
public boolean onClose() {
Log.w(tag, "onClose: ");
return false;
}
I played with true/false a bit, that somehow makes the difference, and it works for me now. Hopefully, it could save someone time.
It's a workaround but has worked for me
searchView.setOnQueryTextListener(new android.widget.SearchView.OnQueryTextListener() {
String lastText;
@Override
public boolean onQueryTextChange(final String newText) {
if (lastText != null && lastText.length() > 1 && newText.isEmpty()) {
// close ctn clicked
return true;
}
}
searchView.setOnCloseListener {
d("click", "close clicked")
return@setOnCloseListener false
}
if you click on close searchView ->
D/click: close clicked
I encountered this issue while trying to detect the showing/dismissal of the SearchView. I ended up using a different listener and it worked for what I need:
setOnQueryTextFocusChangeListener { _, hasFocus ->
if (hasFocus) {
// SearchView is being shown
} else {
// SearchView was dismissed
}
}
There is no console in Android to log to. Instead, use the android logging framework:
Log.d("Test Tag", "Testing. 1, 2, 3...");
See also this question: Why doesn't "System.out.println" work in Android?
There are two common patterns for SearchView.setOnCloseListener()
. This is really true of all listeners, but I'm addressing your question specifically. The first way is to create a listener function and attach it to a member variable, and the second is to make the class implement the interface and have the handler be a member function.
Creating a listener object looks like this:
private SearchView mSearchView;
private final SearchView.OnCloseListener mOnCloseListener =
new SearchView.OnCloseListener() {
public boolean onClose() {
doStuff();
return myBooleanResult;
}
};
mSearchView.setOnCloseListener(mOnCloseListener);
Implementing listener at class level looks like this:
public class MyClass implements OnCloseListener {
private SearchView mSearchView;
public MyClass(...) {
mSearchView.setOnCloseListener(this);
}
@Override
public boolean onClose() {
doStuff();
return false;
}
}
I have not seen any examples that create the OnCloseListener
ad-hoc, as you did in your question.