SearchView 的 OnCloseListener 不能工作

我试图在 Android 3.0 + ActionBar 中添加对 SearchView的支持,但是我无法让 OnCloseListener工作。

这是我的密码:

@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;
}

搜索工作很好,除了 OnCloseListener以外,每个都在工作。没有任何东西被印到 Logcat。下面是我按下“关闭”按钮时的 Logcat:

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

我检查了 文件和样本,但似乎没有任何改变。我在华硕变形金刚和 Galaxy Nexus 上运行它们都是在冰淇淋三明治上运行的。有什么想法吗?

更新:

是的-System.out.println() 是的工作。这里的证据:

   @Override
public boolean onQueryTextChange(String newText) {
System.out.println(newText + "hello");
searchLibrary(newText);
return false;
}

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
58573 次浏览

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?

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; }
});

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.

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 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);


}

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).

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

Ref: onActionCollapse/onActionExpand

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.

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 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

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;
}
});

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;
}
}

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.

    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
}
}

I used the SearchView close button and set a setOnClickListener on it

searchView.findViewById<ImageView>(R.id.search_close_btn).setOnClickListener {
searchView.setQuery("", false)
searchView.clearFocus()
}
searchView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
System.out.println("This is Fired When Search view was Expanded");
}


@Override
public void onViewDetachedFromWindow(View v) {
System.out.println("This is Fired When Search view was Closed");
}
});