James James - 1 month ago 13
Android Question

Android Search Interface -- Multiple SearchViews being displayed

I'm trying to incorporate search functionality into one of my applications and I'm having problems solving an issue with multiple SearchViews being displayed.

So, when I click the “search” icon in my actionbar I get a “search view” that occupies the entire actionbar and there is also another “search view” that is either hiding below the top view or it is rendered after the top view is destroyed, I'm not sure which as I haven't been able to track it down.
The SearchView that is rendered on the bottom/second is the actual view that I want. The top view functions correctly when I make a search request, but when I navigate back to the activity that made the search call, the original SearchView is gone and the correct SearchView is now in place. It then functions normally until I close/collapse the SearchView.
The original SearchView can also be closed by a touchEvent anywhere on the screen and the correct SearchView is up and waiting for input.

Any ideas on what is causing this?

Bar before touching search icon:

Bar with both Views:

Bar with Correct View:

Here is my searchable.xml:

<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/search_label"
android:hint="@string/search_hint"
android:searchSettingsDescription="@string/settings_description" />


My menu xml file:

<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/search"
android:title="@string/menu_search"
android:icon="@drawable/ic_menu_search"
android:orderInCategory="0"
android:actionViewClass="android.widget.SearchView"
android:showAsAction="ifRoom|collapseActionView" />




A snippet of my manifest:

<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:windowSoftInputMode="adjustPan" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<activity android:name="SearchMainActivity"
android:finishOnTaskLaunch ="true"
android:configChanges="keyboard|keyboardHidden|orientation"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>


<meta-data
android:name="android.app.default_searchable"
android:value="SearchMainActivity" />


Main Activity where onCreateOptionsMenu is called:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.options_menu, menu);
MenuItem searchItem = menu.findItem(R.id.search);
if(searchItem != null && (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)) {
SearchView searchView = (SearchView) searchItem.getActionView();
if(searchView != null) {
SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
searchView.setIconifiedByDefault(false);
}
}
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.search:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
startSearch(null, false, Bundle.EMPTY, false);
return true;
}
break;
default:
return false;
}
return super.onOptionsItemSelected(item);
}


My SearchActivity.java

public class SearchMainActivity extends FragmentActivity implements SearchListFragment.OnSearchListItemSelectedListener {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
SearchQuery.query = intent.getStringExtra(SearchManager.QUERY);
SearchQuery.original_query = SearchQuery.query;
SearchQuery.query = SearchQuery.query.toLowerCase().trim().replaceAll("'", "''").replaceAll("[^A-Za-z0-9\\.\\-\\'\\\" ]", "");
}
setContentView(R.layout.search_main_layout);

if(findViewById(R.id.fragment_container) != null) {
if(savedInstanceState != null) {
return;
}
SearchListFragment listFrag = new SearchListFragment();
listFrag.setArguments(getIntent().getExtras());

getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, listFrag).commit();
}
}

@Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
SearchQuery.query = intent.getStringExtra(SearchManager.QUERY);
startActivity(intent);
}

@Override
public void onSearchListItemSelected(int position, View v) {
SearchDetailFragment detailFrag = (SearchDetailFragment)
getSupportFragmentManager().findFragmentById(R.id.main_list_detail_fragment);
if(detailFrag != null) {
detailFrag.updateMainDetailView(position);
}
else {
SearchDetailFragment searchDetailFragment = new SearchDetailFragment();

Bundle args = new Bundle();
args.putInt(BaseDetailFragment.CURRENT_LIST_POSITION, position);
searchDetailFragment.setArguments(args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

transaction.replace(R.id.fragment_container, searchDetailFragment);
transaction.addToBackStack(null);
transaction.commit();
}
}
}

Answer

It seems like you're double-implementing the search interface in 2 different ways. If you take a look at the official docs on setting up a search interface in the action bar, you'll note it makes no mention of calling startSearch in onOptionsItemSelected. Try removing that from onOptionsItemSelected and see what happens.

Edit: Upon further research, it looks like you might have tried implementing both of the implementations outlined here, but only one or the other is necessary (though one only works on Honeycomb and above unless you're using ABS or AppCompat).

Comments