SearchView 完全用法解析
搜索是 App 里最常见的人机入口之一,Android 也为此专门提供了 SearchView。但很多人对它的印象停留在"放个输入框、加个监听",其实它背后还有一整套可搜索配置(searchable 配置)、searchable Activity、ACTION_SEARCH 传递与搜索建议机制。本文从零开始,把 SearchView 的两种用法、清单声明、接收查询、控件接入、输入监听到搜索建议讲透,看完即可在项目里完整落地。
1、SearchView 概述与两种用法
SearchView 是 Android 自带的搜索输入控件。常见有两套用法:一是系统托管的搜索对话框(Search Dialog),调用 onSearchRequested() 弹出;二是把 SearchView 作为 Toolbar / ActionBar 的 action view,自定义度更高,也是最主流的做法。本文围绕后者展开。
两个实现版本:
- android.widget.SearchView:框架原生,样式偏旧
- androidx.appcompat.widget.SearchView:AppCompat 版,推荐使用,向下兼容、样式统一
全文使用 AppCompat 版 SearchView,配合 searchable 配置、searchable Activity、输入监听与搜索建议,构成一套完整方案。
2、Searchable 配置与清单声明
搜索功能需要两样东西:一份 searchable 配置文件,和清单里承接搜索的 Activity 声明。先在 res/xml/ 下新建配置文件:
<!-- res/xml/searchable.xml -->
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/app_name"
android:hint="@string/search_hint" />然后在 AndroidManifest.xml 里声明承接搜索的 Activity,绑定这份配置:
<activity
android:name=".SearchableActivity"
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>声明要点:
1. res/xml/searchable.xml 的 <searchable> 至少配 android:label 与 android:hint
2. android:label 必须是字符串资源(不能直接写字面量),通常与 app 名一致
3. 承接搜索的 Activity 要加 ACTION_SEARCH 的 intent-filter
4. 用 <meta-data android:name="android.app.searchable"> 把配置绑定到该 Activity
3、接收搜索:searchable Activity
用户提交搜索后,系统会以 ACTION_SEARCH Intent 启动(或复用)searchable Activity,查询词藏在 SearchManager.QUERY 这个 extra 里。
public class SearchableActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handleSearch(getIntent());
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
handleSearch(intent);
}
private void handleSearch(Intent intent) {
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
doSearch(query); // 用 query 执行实际搜索
}
}
}接收要点:
1. onCreate 里判断 getIntent().getAction() 是否为 ACTION_SEARCH
2. 用 getStringExtra(SearchManager.QUERY) 取出查询词
3. Activity 设为 singleTop 后,再次搜索会走 onNewIntent 而非重建
4. 把搜索逻辑抽到 handleSearch,onCreate 与 onNewIntent 共用
4、SearchView 控件接入菜单
最常见的做法是把 SearchView 作为 Toolbar 菜单项的 actionView,先在 res/menu/ 下定义菜单:
<!-- res/menu/menu_search.xml -->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_search"
android:title="@string/search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="ifRoom|collapseActionView" />
</menu>然后在 Activity 里 inflate 菜单,拿到 SearchView 并绑定 SearchableInfo:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_search, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) searchItem.getActionView();
// 绑定 searchable 配置,复用 hint 等设置
SearchManager sm = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
searchView.setSearchableInfo(sm.getSearchableInfo(getComponentName()));
return true;
}接入要点:
1. menu item 用 app:actionViewClass="androidx.appcompat.widget.SearchView"(注意是 app 命名空间)
2. showAsAction 用 ifRoom|collapseActionView,可折叠成搜索图标、点击展开
3. 用 searchItem.getActionView() 拿到 SearchView 实例
4. setSearchableInfo 绑定后,SearchView 才会复用 searchable.xml 里的 hint 等配置
5、监听输入与常用 API
核心是 OnQueryTextListener,它给出"提交"和"逐字变化"两个回调;再配合一组常用方法控制外观与行为。
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
// 用户点击搜索键
doSearch(query);
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
// 输入逐字变化,常用于实时过滤列表
filter(newText);
return true;
}
});常用 API:
- setQueryHint / setQuery(text, submit):提示文案与代码设置查询
- setSubmitButtonEnabled:是否显示提交按钮
- setIconified / setIconifiedByDefault:折叠态控制,后者设 false 可默认展开
- setOnCloseListener / setOnQueryTextFocusChangeListener:关闭与焦点回调
- setMaxWidth / setOnSuggestionListener:宽度与搜索建议点击
监听要点:
1. onQueryTextSubmit:用户点搜索键时触发,return true 表示已消费
2. onQueryTextChange:逐字变化,适合做列表实时过滤
3. 实时过滤要加防抖,避免每个字符都触发查询造成卡顿
4. setIconifiedByDefault(false) 可让搜索框默认处于展开状态
6、搜索建议:Suggestions
搜索建议分两类:最近搜索(系统提供的 SearchRecentSuggestions)与自定义数据源(CursorAdapter)。最近搜索实现成本最低,几行就能加。
// 提交搜索时,把查询词记录到最近搜索
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(
this,
MySuggestionProvider.AUTHORITY, // 自定义 ContentProvider 的 authority
MySuggestionProvider.MODE);
suggestions.saveRecentQuery(query, null);建议接入要点:
1. 最近搜索需继承一个 ContentProvider(如 MySuggestionProvider),声明 authority 与 mode
2. searchable.xml 加 android:searchSuggestAuthority 指向该 provider
3. 自定义建议可改用 CursorAdapter 提供数据,配合 setOnSuggestionListener 处理点击
4. 点击建议项时,onSuggestionSelect 回调里可拿到位置并自行跳转
7、注意事项与最佳实践
落地时容易踩的坑与建议:
- 优先用 androidx.appcompat.widget.SearchView,样式与兼容性都更好
- 使用 collapseActionView 时,注意在销毁前保存、恢复搜索状态
- 实时搜索务必加防抖(如 Handler postDelayed 或 RxJava debounce)
- searchable Activity 设 singleTop + onNewIntent,避免任务栈里堆积多个实例
- 想接入系统全局搜索,需在 searchable.xml 设 android:includeInGlobalSearch
- 新项目若用 Jetpack Compose,可改用 Material3 的 SearchBar 替代传统 SearchView
8、总结
SearchView 的完整用法,可以归纳为一条主线:searchable 配置(res/xml/searchable.xml)+ 清单声明 searchable Activity(ACTION_SEARCH + meta-data)+ 在 Activity 里接收 SearchManager.QUERY + 把 SearchView 作为 Toolbar 的 actionView 接入 + OnQueryTextListener 监听输入 + 可选的搜索建议。优先选用 AppCompat 版 SearchView。
落地时把 SearchView 接入 Toolbar(actionViewClass + collapseActionView)、绑定 SearchableInfo、在 searchable Activity 接收查询;需要历史或联想词,再叠加 SearchRecentSuggestions 或自定义 CursorAdapter。新项目用 Compose 可考虑 Material3 的 SearchBar,但在 View 体系下,传统 SearchView 仍是成熟、可靠的搜索方案。

