Android FragmentActivity 与(共享?)android.widget.SearchView 在两个片段之间?
Android FragmentActivity with (shared?) android.widget.SearchView between two fragments?
我有一个带有两个片段的 FragmentActivity (support-v4)。
两者都包含一个带有 ActionBar 的 SearchView 的菜单。
播放列表片段:
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
Log.d(LOGTAG, String.format("onCreateOptionsMenu(%s,%s)", this, menu));
inflater.inflate(R.menu.playlist_ab_menu, menu);
buildLocalSearchView(menu.findItem(R.id.menu_playlist_search));
super.onCreateOptionsMenu(menu, inflater);
}
private void buildLocalSearchView(MenuItem item) {
SearchView searchView = (SearchView) item.getActionView();
searchView.setSubmitButtonEnabled(false);
searchView.setIconifiedByDefault(true);
searchView.setIconified(true);
//don't work because a bug in android, @see https://code.google.com/p/android/issues/detail?id=25758
searchView.setOnCloseListener(this);
//workaround for the above
MenuItemCompat.setOnActionExpandListener(item, new MenuItemCompat.OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
return true;
}
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
return true;
}
});
searchView.setOnQueryTextListener(adapter);
}
与 FilterlistFragment 类似:
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
Log.d(LOGTAG, String.format("onCreateOptionsMenu(%s,%s)", this, menu));
inflater.inflate(R.menu.filterlist_ab_menu, menu);
// Get the SearchView and set the searchable configuration
buildLocalSearchView(menu.findItem(R.id.menu_filterlist_search));
super.onCreateOptionsMenu(menu, inflater);
}
但是如果我现在开始在 FilterlistFragment 中搜索并且不关闭 SearchView 而是切换到 PlaylistFragment,则查询字符串从 FilterlistFragment 转移到 PlaylistFragment。但是 ActionBar-SearchView 在 PlaylistFragment 中是可见的,就像关闭一样。
我可以在切换到 PlaylistFragment 后在我的日志中看到:
07-25 05:09:29.277 3315-3315/de.NullZero.ManiDroid D/de.NullZero.ManiDroid.presentation.fragments.FilterListFragment﹕ onDestroyView(FilterListFragment{b12b8090 #2 id=0x7f0a0085 FILTER_2})
07-25 05:09:29.277 3315-3315/de.NullZero.ManiDroid D/PlaylistFragment﹕ onCreate(PlaylistFragment{b13dcc58 #3 id=0x7f0a0085 PLAYLIST},null)
07-25 05:09:29.277 3315-3315/de.NullZero.ManiDroid D/PlaylistFragment﹕ onViewCreated(PlaylistFragment{b13dcc58 #3 id=0x7f0a0085 PLAYLIST},null)
07-25 05:09:29.277 3315-3315/de.NullZero.ManiDroid D/de.NullZero.ManiDroid.presentation.ManiDroidAppActivity﹕ onBackStackChanged() Fragment:PlaylistFragment{b13dcc58 #3 id=0x7f0a0085 PLAYLIST}
07-25 05:09:29.287 3315-3360/de.NullZero.ManiDroid D/DEBUG﹕ searchInPlaylist() = 2 ms
07-25 05:09:29.307 3315-3315/de.NullZero.ManiDroid D/PlaylistFragment﹕ onCreateOptionsMenu(PlaylistFragment{b13dcc58 #3 id=0x7f0a0085 PLAYLIST},com.android.internal.view.menu.MenuBuilder@b106ad90)
07-25 05:09:29.317 3315-3315/de.NullZero.ManiDroid D/PlaylistFragment﹕ onPrepareOptionsMenu(PlaylistFragment{b13dcc58 #3 id=0x7f0a0085 PLAYLIST},com.android.internal.view.menu.MenuBuilder@b106ad90)
07-25 05:09:29.477 3315-3364/de.NullZero.ManiDroid D/DEBUG﹕ searchInFilter(, ManitobaFilter{filterName='Zuletzt gehört'}) = 178 ms
07-25 05:09:29.477 3315-3364/de.NullZero.ManiDroid D/DEBUG﹕ searchInPlaylist(max) = 1 ms
searchInPlaylist() 方法是 PlaylistFragment 的 SearchView(适配器)方法,而 searchInFilter(...) 是 FilterlistFragment 的方法。
如您所见,调用了最后一个 searchInPlaylist(max),参数与之前我在 FilterlistFragment SearchView 中输入的参数相同。
为什么这个搜索参数在两个不同的 SearchView 之间传递?
我怎样才能将它重置为默认的空字符串?
在FilterlistFragment的onDestroyView中是否需要一些特殊的处理来取消当前的SearchView?
P.S.
找到原因但没有解决办法:
com.android.internal.widget.ActionBarView.ExpandedActionViewMenuPresenter#collapseItemActionView
通话
// Do this before detaching the actionview from the hierarchy, in case
// it needs to dismiss the soft keyboard, etc.
if (mExpandedActionView instanceof CollapsibleActionView) {
((CollapsibleActionView) mExpandedActionView).onActionViewCollapsed();
}
由于我的 setOnQueryTextListener,这将触发 setQuery("") 并因此触发 sql-search。在上面的日志中,这是
07-25 05:09:29.477 3315-3364/de.NullZero.ManiDroid D/DEBUG﹕searchInFilter(, ManitobaFilter{filterName='Zuletzt gehört'})
呼唤。
关于新片段的方法
com.android.internal.view.menu.MenuBuilder#restoreActionViewStates
在 onPrepareOptionsMenu 之后被调用以恢复旧的视图状态。
因此,我的 ActionBar/SearchView/TextView 使用 query=max 从这个 Bundle 中恢复了一个(错误的)状态。
这会触发来自 SearchView 的 onTextChange,因此会在我的新片段中触发 sql-搜索 "max",如您所见,这是最后一行日志。
如何禁用 ActionBar/SearchView/TextView 的保存和恢复?
@Override
public void onDestroyView() {
super.onDestroyView();
Log.d(LOGTAG, String.format("onDestroyView(%s)", this));
searchView.setOnQueryTextListener(null);
searchView.setQuery("", true);
}
这样就可以了。
不可能使用多个 SearchView 真的很丑陋,因为它们都具有相同的 TextView,因此 save/restore 来自相同的 Bundle-Key。
我有一个带有两个片段的 FragmentActivity (support-v4)。 两者都包含一个带有 ActionBar 的 SearchView 的菜单。
播放列表片段:
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
Log.d(LOGTAG, String.format("onCreateOptionsMenu(%s,%s)", this, menu));
inflater.inflate(R.menu.playlist_ab_menu, menu);
buildLocalSearchView(menu.findItem(R.id.menu_playlist_search));
super.onCreateOptionsMenu(menu, inflater);
}
private void buildLocalSearchView(MenuItem item) {
SearchView searchView = (SearchView) item.getActionView();
searchView.setSubmitButtonEnabled(false);
searchView.setIconifiedByDefault(true);
searchView.setIconified(true);
//don't work because a bug in android, @see https://code.google.com/p/android/issues/detail?id=25758
searchView.setOnCloseListener(this);
//workaround for the above
MenuItemCompat.setOnActionExpandListener(item, new MenuItemCompat.OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
return true;
}
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
return true;
}
});
searchView.setOnQueryTextListener(adapter);
}
与 FilterlistFragment 类似:
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
Log.d(LOGTAG, String.format("onCreateOptionsMenu(%s,%s)", this, menu));
inflater.inflate(R.menu.filterlist_ab_menu, menu);
// Get the SearchView and set the searchable configuration
buildLocalSearchView(menu.findItem(R.id.menu_filterlist_search));
super.onCreateOptionsMenu(menu, inflater);
}
但是如果我现在开始在 FilterlistFragment 中搜索并且不关闭 SearchView 而是切换到 PlaylistFragment,则查询字符串从 FilterlistFragment 转移到 PlaylistFragment。但是 ActionBar-SearchView 在 PlaylistFragment 中是可见的,就像关闭一样。
我可以在切换到 PlaylistFragment 后在我的日志中看到:
07-25 05:09:29.277 3315-3315/de.NullZero.ManiDroid D/de.NullZero.ManiDroid.presentation.fragments.FilterListFragment﹕ onDestroyView(FilterListFragment{b12b8090 #2 id=0x7f0a0085 FILTER_2})
07-25 05:09:29.277 3315-3315/de.NullZero.ManiDroid D/PlaylistFragment﹕ onCreate(PlaylistFragment{b13dcc58 #3 id=0x7f0a0085 PLAYLIST},null)
07-25 05:09:29.277 3315-3315/de.NullZero.ManiDroid D/PlaylistFragment﹕ onViewCreated(PlaylistFragment{b13dcc58 #3 id=0x7f0a0085 PLAYLIST},null)
07-25 05:09:29.277 3315-3315/de.NullZero.ManiDroid D/de.NullZero.ManiDroid.presentation.ManiDroidAppActivity﹕ onBackStackChanged() Fragment:PlaylistFragment{b13dcc58 #3 id=0x7f0a0085 PLAYLIST}
07-25 05:09:29.287 3315-3360/de.NullZero.ManiDroid D/DEBUG﹕ searchInPlaylist() = 2 ms
07-25 05:09:29.307 3315-3315/de.NullZero.ManiDroid D/PlaylistFragment﹕ onCreateOptionsMenu(PlaylistFragment{b13dcc58 #3 id=0x7f0a0085 PLAYLIST},com.android.internal.view.menu.MenuBuilder@b106ad90)
07-25 05:09:29.317 3315-3315/de.NullZero.ManiDroid D/PlaylistFragment﹕ onPrepareOptionsMenu(PlaylistFragment{b13dcc58 #3 id=0x7f0a0085 PLAYLIST},com.android.internal.view.menu.MenuBuilder@b106ad90)
07-25 05:09:29.477 3315-3364/de.NullZero.ManiDroid D/DEBUG﹕ searchInFilter(, ManitobaFilter{filterName='Zuletzt gehört'}) = 178 ms
07-25 05:09:29.477 3315-3364/de.NullZero.ManiDroid D/DEBUG﹕ searchInPlaylist(max) = 1 ms
searchInPlaylist() 方法是 PlaylistFragment 的 SearchView(适配器)方法,而 searchInFilter(...) 是 FilterlistFragment 的方法。
如您所见,调用了最后一个 searchInPlaylist(max),参数与之前我在 FilterlistFragment SearchView 中输入的参数相同。 为什么这个搜索参数在两个不同的 SearchView 之间传递? 我怎样才能将它重置为默认的空字符串?
在FilterlistFragment的onDestroyView中是否需要一些特殊的处理来取消当前的SearchView?
P.S.
找到原因但没有解决办法:
com.android.internal.widget.ActionBarView.ExpandedActionViewMenuPresenter#collapseItemActionView
通话
// Do this before detaching the actionview from the hierarchy, in case
// it needs to dismiss the soft keyboard, etc.
if (mExpandedActionView instanceof CollapsibleActionView) {
((CollapsibleActionView) mExpandedActionView).onActionViewCollapsed();
}
由于我的 setOnQueryTextListener,这将触发 setQuery("") 并因此触发 sql-search。在上面的日志中,这是
07-25 05:09:29.477 3315-3364/de.NullZero.ManiDroid D/DEBUG﹕searchInFilter(, ManitobaFilter{filterName='Zuletzt gehört'})
呼唤。
关于新片段的方法
com.android.internal.view.menu.MenuBuilder#restoreActionViewStates
在 onPrepareOptionsMenu 之后被调用以恢复旧的视图状态。 因此,我的 ActionBar/SearchView/TextView 使用 query=max 从这个 Bundle 中恢复了一个(错误的)状态。 这会触发来自 SearchView 的 onTextChange,因此会在我的新片段中触发 sql-搜索 "max",如您所见,这是最后一行日志。
如何禁用 ActionBar/SearchView/TextView 的保存和恢复?
@Override
public void onDestroyView() {
super.onDestroyView();
Log.d(LOGTAG, String.format("onDestroyView(%s)", this));
searchView.setOnQueryTextListener(null);
searchView.setQuery("", true);
}
这样就可以了。 不可能使用多个 SearchView 真的很丑陋,因为它们都具有相同的 TextView,因此 save/restore 来自相同的 Bundle-Key。