Вопрос

I'm having trouble setting up the search view in the action bar.

I followed the developer site, but it doesn't work. I get the feeling that I am missing something.

When I run my code, it always outputs "failed to get searchable info" (MainActivity.setupSearchView()).

MainActivity.java

// package...
// imports...
public class MainActivity extends Activity {
    private static String tag = "Main Activity";
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater mi = getMenuInflater();
        mi.inflate(R.menu.search_view, menu);
        setupSearchView(menu);
        return true;
    }
    private void setupSearchView(Menu menu) {
        SearchManager sm = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchableInfo si = sm.getSearchableInfo(getComponentName());
        if (si == null) {
            Log.wtf(tag, "failed to get searchable info");
            return;
        }
        SearchView sv = (SearchView) menu.findItem(R.id.menu_search).getActionView();
        sv.setSearchableInfo(si);
        // Do not iconify the widget; expand it by default
        sv.setIconifiedByDefault(false);
    }
}

SearchResultsActivity.java

// package...
// imports...
public class SearchResultsActivity extends ListActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final Intent queryIntent = getIntent();
        doSearchQuery(queryIntent);
    }
    @Override
    public void onNewIntent(final Intent newIntent) {
        super.onNewIntent(newIntent);
        final Intent queryIntent = getIntent();
        doSearchQuery(queryIntent);
    }
}

searchable.xml

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:hint="@string/search_hint"
    android:label="@string/search_label" >
</searchable>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="kpaek.examples"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk android:minSdkVersion="15" />
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".search.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".SearchResultsActivity">
            <intent-filter>
                <action android:name="android.intent.action.SEARCH" />
            </intent-filter>
            <meta-data
                android:name="android.app.searchable"
                android:resource="@xml/searchable" />
        </activity>
    </application>
</manifest>
Это было полезно?

Решение

The key thing I found is that searchable.xml must not contain literal strings, only resources. I wasted about half a day on that one, since it causes getSearchableInfo to fail silently.

Другие советы

In my case using custom tags in res/menu/mymenu.xml worked for me:

app:showAsAction="ifRoom|collapseActionView"
app:actionViewClass="android.support.v7.widget.SearchView"

Do not use:

android:showAsAction="ifRoom|collapseActionView"
android:actionViewClass="android.support.v7.widget.SearchView"

I have found that the intent-filter and the meta-data elements must be included in the manifest activity element from which the search is initiated (MainActivity having a SearchView) for the method getSearchableInfo(getComponentName()) to return the correct configuration and not null.

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

    <intent-filter>
        <action android:name="android.intent.action.SEARCH" />
    </intent-filter>

    <meta-data
        android:name="android.app.searchable"
        android:resource="@xml/searchable" />
</activity>

I wonder if instead (and the solution I am going with for now) one should leave the intent and meta-data on the results activity declaration and change the argument to getSearchableInfo() as follows:

<activity android:name=".SearchResultsActivity">
    <intent-filter>
        <action android:name="android.intent.action.SEARCH" />
    </intent-filter>

    <meta-data
        android:name="android.app.searchable"
        android:resource="@xml/searchable" />
</activity>

And the changes to MainActivity (note the assignment statement for searchableInfo):

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.menu_search, menu);
    SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    SearchView mySearchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
    SearchableInfo searchableInfo = searchManager.getSearchableInfo(new ComponentName(getApplicationContext(), SearchResultsActivity.class));
    mySearchView.setSearchableInfo(searchableInfo);

    return true;
}

This killed me for a day - I thought it was ActionBarSherlock-related, but no it works fine with that.

The problem was that I was trying to short-circuit the sample. At least one of your activities - the one you're doing the searching from is sufficient - must have this intent-filter in it in the manifest:

<intent-filter>
  <action android:name="android.intent.action.SEARCH" />
</intent-filter>

If not, then searchManager.getSearchableInfo(getComponentName()) always returns null, and your configuration is ignored.

From the developersite:

A searchable configuration defines how the SearchView behaves and is defined in a res/xml/searchable.xml file. At a minimum, a searchable configuration must contain an android:label attribute that has the same value as the android:label attribute of the or element in your Android manifest.

As an example, they show:

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

app_name is, like in your manifest, the label of the activity. However, in your searchable, the label refers to search_label. Works perhaps if app_name and search_label are equal, but that seems fragile to me.

I encountered this issue but the advice above did not resolve it. Instead it turned out to be setting category default in the SearchResultActivity. For example the following breaks:

<activity android:name=".SearchResultActivity"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
    <intent-filter>
            <action android:name="android.intent.action.SEARCH" />
            <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
    <meta-data
            android:name="android.app.searchable"
            android:resource="@xml/searchable" />
</activity>

Removing android.intent.category.DEFAULT resolves this problem.:

<activity android:name=".SearchResultActivity"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
    <intent-filter>
            <action android:name="android.intent.action.SEARCH" />
    </intent-filter>
    <meta-data
            android:name="android.app.searchable"
            android:resource="@xml/searchable" />
</activity>

Also the previous answers to this question have an error. MainActivity should be defined with android.app.default_searchable. android.app.searchable is only for your SearchResultsActivity.

<activity
    android:name=".MainActivity"
    android:label="@string/app_name">
    <!-- other stuff-->
    <meta-data android:name="android.app.default_searchable"
            android:value=".SearchResultsActivity" />
</activity>

In conclusion the SearchManager is a fragile component prone to silent failures when the AndroidManifest.xml isn't perfect.

I wasted 8 full hours on this one because I checked all the above solutions but one thing was missing for me.

In my Android Manifest:

<meta-data
                android:name="android.app.searchable"
                android:value="@xml/searchable" />

Should has been:

<meta-data
                android:name="android.app.searchable"
                android:resource="@xml/searchable" />

For me it was failing silently. The best thing to do at first is just copy and paste the examples. Just be sure that all your attributes are exactly the same.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top