无法在操作栏中使用搜索视图

67
我对Java和Android开发都很陌生,目前正在开发一个应用程序,希望能够在其中使用具有SearchView的操作栏。我查看了谷歌的示例,但无法使其正常工作。我一定是做错了什么,现在感到有些放弃应用程序开发:D 我进行了搜索,但没有找到任何有用的信息。也许你们可以帮帮我:)
问题:我已经成功打开搜索视图,但之后什么都没发生。我注意到我的searchManager.getSearchableInfo(getComponentName())返回null。此外,我提供的提示未显示在搜索框中,这让我认为也许应用程序找不到我的searchable.xml?话不多说 :)

MainActivity.java

public class MainActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);

        // Get the SearchView and set the searchable configuration
        SearchManager searchManager =
            (SearchManager) getSystemService(Context.SEARCH_SERVICE);
        SearchView searchView =
            (SearchView) menu.findItem(R.id.menu_search).getActionView();
        searchView.setSearchableInfo(
            searchManager.getSearchableInfo(getComponentName()));

        return true;
    }
}

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/app_label">
</searchable>

Androidmanifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.searchapp"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="15" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

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

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

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

    </application>

</manifest>

SearchableActivity.java

package com.example.searchapp;

import android.app.ListActivity;
import android.app.SearchManager;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

public class SearchableActivity extends ListActivity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.search);

        // Get the intent, verify the action and get the query
        Intent intent = getIntent();
        if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
          String query = intent.getStringExtra(SearchManager.QUERY);
          doMySearch(query);
        }
    }

    private void doMySearch(String query) {
        Log.d("Event",query);
    }
}

这里有一个链接指向相关项目,如果有人能帮助我,我将万分感激!

源代码


menu.findItem(R.id.menu_search) - 这是怎么编译通过的?R.id.menu_search是什么? - AlikElzin-kilaka
如何在搜索活动中继续搜索。如何在搜索活动中重新设置actionBar搜索视图以在同一活动中进行更多搜索。 - madan V
我需要帮助 http://stackoverflow.com/questions/32197791/how-to-access-searchview-in-fragment - Aditya Vyas-Lakhan
9个回答

149

你的问题出现在AndroidManifest文件中。我曾经也和你一样按照文档进行设置,但是文档不够清晰或者存在误导。

通过查看API示例源代码,我发现“android.app.searchable”元数据必须放在“results”活动(即你的搜索结果页)中,而在主活动(或包含SearchView的活动)中,需要使用“android.app.default_searchable”指向前一个活动。

你可以在下面这个文件中查看,这是我测试项目的清单文件:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.test"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="15" />

<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name=".MainActivity"
        android:label="@string/title_activity_main" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>

        <meta-data
            android:name="android.app.default_searchable"
            android:value=".SearchActivity" />
    </activity>
    <activity
        android:name=".SearchActivity"
        android:label="@string/app_name" >

        <!-- This intent-filter identifies this activity as "searchable" -->

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

            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>

        <!-- This metadata entry provides further configuration details for searches -->
        <!-- that are handled by this activity. -->

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

同样重要的是,searchable.xml 中的提示和标签应该是引用而不是硬编码字符串。

希望这可以解决你的问题。我用了整整一天才解决 :(


5
太棒了,它完全奏效了!所以我想这不仅仅是我的问题:) 现在我非常高兴,谢谢Sloy! :) - Jonathan Andersson
6
这篇文章刚刚帮我们解决了问题——缺少的部分是<meta-data android:name="android.app.default_searchable" android:value=".SearchActivity" /> - Richard Lewin
6
在 searchable.xml 中,提示和标签应该是引用而不是硬编码的字符串,这很重要。这解决了我的问题。这是一个非常荒谬的错误。 - Indrek Kõue
1
我简直不敢相信文档居然有漏洞.. 而且看起来确实是这样。 - Lake
3
我也遇到了同样的问题并想到了解决方法。由于官方文档中有几个错误,我花费的时间比预期的要长。在StackOverflow上已经有多次提问,至少有5篇帖子问了同样的问题。我将它们标记为与此重复。我还写了一篇博客总结了我的学习成果。希望对你有所帮助。 - Clint
显示剩余8条评论

83

安卓指南明确指出:

// Assumes current activity is the searchable activity
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));

在您的情况下,这不是真实的。因为您不想在MainActivity中搜索,而是在SearchableActivity中搜索。这意味着您应该使用此ComponentName,而不是getComponentName()方法:

在您的情况下,这并不正确。因为您不想在MainActivity中搜索,而是要在SearchableActivity中搜索。这意味着您应该使用此ComponentName,而不是getComponentName()方法:

ComponentName cn = new ComponentName(this, SearchableActivity.class);
searchView.setSearchableInfo(searchManager.getSearchableInfo(cn));

谢谢!这真的是我犯的错误。 - Randy
请点击此处获取帮助:http://stackoverflow.com/questions/32197791/how-to-access-searchview-in-fragment - Aditya Vyas-Lakhan
这份文档也让我有些困惑。感谢您的帮助,这个建议在使用Xamarin时非常有效,唯一的改变是您需要使用以下C#代码var componentName = new ComponentName(this, Java.Lang.Class.FromType(typeof(SearchView))) - Alex Sorokoletov
谢谢,这真的帮了我很多。不过我要补充一点,在我的情况下,除了这个答案之外,我还必须在目标活动清单中添加可搜索的元数据,否则它就无法启动。 - Raymond Lagonda
1
这解决了问题,但是键盘中的搜索图标现在被箭头替换了。如何将其恢复? - Iqbal
显示剩余2条评论

12

看起来,android:hint和android:label属性必须是在strings.xml中的字符串引用。懒惰地硬编码字符串值似乎根本行不通 :)

也就是说,不要这样做:

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:hint="Search for something..."
    android:label="My App">
</searchable>

但绝对要做到(正如原帖作者正确地所做的):

<?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/app_label">
</searchable>

4
这是一个错误还是一些特定的技术限制?在我看来,它似乎是一个错误(文档中没有提到不能使用硬编码字符串)。 - Indrek Kõue
2
谢谢你。在弄清楚之前,我浪费了两天时间。 - lahsrah

7

要小心处理 "xml/searchable.xml" 文件。如果您在 android:hintandroid:label 中硬编码,它将无法正常工作。应该这样写:

<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:hint="@string/app_name"
android:label="@string/search_lb"
android:voiceSearchMode="showVoiceSearchButton|launchRecognizer"/>

1
这太奇怪了,这是一个错误吗? - Tanner Summers

7
如果您正在使用Android Studio,
<meta-data
            android:name="android.app.default_searchable"
            android:value=".SearchActivity" />

某部分可能无法正常工作。

请写出完整的软件包名称,例如

<meta-data
                android:name="android.app.default_searchable"
                android:value="com.example.test.SearchActivity" />

1
没有问题。我使用的是Android Studio(版本0.8.1),它可以很好地使用.SearchActivity。 - Clint
这解决了我的问题,使用Android Studio 2.3.3和build tools 25.0.2。 - sonic

2
实际上,没有必要像上面的答案中描述的那样使用“缺失部分”。这种方法(使用SearchView)完全按照官方文档的说法工作,直到使用搜索小部件。在这里,需要进行微小的修改,如下所示: SearchableInfo中的属性用于显示标签、提示、建议、创建启动搜索结果屏幕的意图以及控制其他可见性,例如语音按钮(文档)。
因此,我们传递给SearchView.setSearchableInfo(SearchableInfo s)SearchableInfo对象必须包含对目标活动的正确引用,该活动应显示搜索结果。这是通过手动传递我们目标活动的ComponentName来完成的。创建ComponentName的一个构造函数为:
public ComponentName (String pkg, String cls)

pkgcls是目标活动的包名和类名,用于显示搜索结果。请注意:

pkg必须指向您项目的根包名称,

cls必须是类的完全限定名称(即整个名称)

例如:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_main, menu);
    // Get the SearchView and set the searchable configuration
String pkg = "com.example.musicapp"
String cls = "com.example.musicapp.search.SearchActivity"
ComponentName mycomponent = new ComponentName(pkg,cls);       
SearchManager searchManager =(SearchManager)getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
searchView.setSearchableInfo(searchManager.getSearchableInfo(mycomponent));
searchView.setIconifiedByDefault(false);   //if using on actionbar
return true;
}

根据您的需求,可以查看其他ComponentName构造函数。


2
请确保您的searchables.xml文件位于正确的位置(即在res/xml/文件夹中),并且相同的文件不包含任何错误-否则,您将发现(SearchManager)getSystemService(Context.SEARCH_SERVICE).getSearchableInfo(componentName)将返回null,从而破坏您的搜索功能。
(另外,请确保以适当的方式设置componentName,因为Android指南中显示的示例仅用于在同一Activity中进行搜索和显示搜索。)

0

我遇到了同样的问题,尝试将搜索意图过滤器添加到可搜索活动中:

   <activity
        android:launchMode="singleTop"
        android:name=".ui.activities.MainActivity"
        android:label="@string/app_name"
        android:theme="@style/AppTheme.NoActionBar">

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

-1

请仔细检查values/strings.xml中是否存在对应的条目(例如search_hint和app_label)

例如:

      <string name="app_label">FunApp</string>
      <string name="search_hint">Caps Off</string>

他其实并没有错,只是没有解释清楚。请看下面的解决方案。 - Tanner Summers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接