Setting搜索 ===》了解是如何初始搜索索引以及去掉控件搜索
一、系统层级搜索索引(需系统签名权限)
1、核心机制
系统层级的搜索索引用于增强系统全局搜索能力(如设置项搜索)。需要系统应用权限(BINDSEARCHINDEXABLES)和系统签名。
关键组件:
SettingsIntelligence
在 Android 系统中,SettingsIntelligence 是负责实现 全局搜索功能 的核心组件,它深度集成在系统设置应用(Settings App)中,用于管理和响应用户在系统设置界面中的搜索请求,SettingsIntelligence 的核心作用是搜索入口管理、索引构建与维护以及结果排序与过滤。
源码路径:packages/apps/SettingsIntelligence
核心类:
SettingsIntelligenceService:主服务,负责搜索请求的调度。
SearchIndexManager:管理索引的生命周期(构建、更新、销毁)。
SearchResultLoader:从数据库加载索引数据并返回给 UI。
SearchIndexProvider
在 Android 中,SearchIndexProvider 是一个核心接口,用于为系统或应用提供可搜索内容的索引数据。它是搜索功能的基础组件,负责向系统搜索服务(如 SettingsIntelligence)提供需要被索引的配置和动态数据,使用户能在全局搜索栏中快速找到相关内容。SearchIndexProvider 的作用包括:定义可搜索内容、支持搜索范围控制以及与系统搜索服务交互。
SearchIndexProvider 的核心方法
实现 SearchIndexProvider 需重写以下关键方法:
1、getXmlResourcesToIndex():返回需要索引的静态配置(XML 文件)。
2、getRawDataToIndex():返回动态数据(如实时状态、数据库内容)。
2、完整代码示例
步骤 1:实现系统级索引提供者
// SystemSearchIndexProvider.java
import android.content.Context;
import android.provider.SearchIndexablesContract;
import androidx.search.indexable.SearchIndexableResource;
import androidx.search.indexable.SearchIndexablesContract.Raw;
import androidx.search.indexable.SearchIndexableProvider;
import java.util.ArrayList;
import java.util.List;
public class SystemSearchIndexProvider extends SearchIndexableProvider {// 定义需要索引的系统配置private static final List<SearchIndexableResource> INDEXABLES = new ArrayList<>();static {SearchIndexableResource sir = new SearchIndexableResource();sir.xmlResId = R.xml.system_searchable; // 系统级搜索配置INDEXABLES.add(sir);}@Overridepublic List<SearchIndexableResource> getXmlResourcesToIndex(Context context, boolean enabled) {return INDEXABLES; // 返回系统级搜索配置}@Overridepublic List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {List<SearchIndexableRaw> rawData = new ArrayList<>();// 添加动态数据(例如飞行模式状态)SearchIndexableRaw item = new SearchIndexableRaw(context);item.key = "flight_mode";item.title = context.getString(android.R.string.airplane_mode);item.summaryOn = "已开启飞行模式";item.summaryOff = "已关闭飞行模式";rawData.add(item);return rawData;}
}
步骤 2:注册系统级 Provider
在 AndroidManifest.xml 中声明(需系统签名):
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.android.system.settings"><providerandroid:name=".SystemSearchIndexProvider"android:authorities="com.android.settings.search"android:exported="false"android:permission="android.permission.BIND_SEARCH_INDEXABLES" />
</manifest>
步骤 3:定义系统级搜索配置
res/xml/system_searchable.xml:
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"android:label="@string/system_search_label"android:hint="搜索系统设置..."android:searchSettingsDescription="全局系统设置搜索">
</searchable>
步骤 4:手动触发索引更新(系统服务调用)
// 需在系统服务中调用(例如 SettingsService)
public void updateSystemIndex(Context context) {SearchManager searchManager = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);if (searchManager != null) {searchManager.updateIndexAsync(); // 异步更新索引}
}
二、应用层级搜索功能(普通应用)
1、 核心机制
应用层级的搜索功能仅作用于当前应用,使用 SearchView 和 SearchManager 实现本地数据搜索。
关键组件:
SearchManager在 Android 系统中,SearchManager 是负责管理全局搜索功能的核心服务,它充当应用与系统搜索功能之间的桥梁。SearchManager 的核心作用是搜索服务入口、搜索配置管理以及权限与安全控制。
关键方法与属性
SearchView
SearchView 是 Android 提供的一个 UI 控件,用于在应用中实现搜索栏的交互界面。用户可以在搜索栏中输入关键词,查看历史记录、热门建议或实时搜索结果。核心功能包括:输入框、语音搜索、搜索建议以及提交搜索。
SearchableInfo
SearchableInfo 是一个 配置类,用于定义搜索功能的元数据(如搜索标签、提示语、搜索范围等)。它通过 AndroidManifest.xml 声明,并与 SearchView 绑定,控制搜索行为。
核心配置项
2. 完整代码示例
步骤 1:添加搜索配置
res/xml/app_searchable.xml:
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"android:label="@string/app_name"android:hint="搜索笔记..."android:searchSettingsDescription="搜索本地笔记">
</searchable>
步骤 2:实现搜索逻辑
// MainActivity.java
import android.app.SearchManager;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SearchView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.main_menu, menu);// 绑定搜索视图MenuItem searchItem = menu.findItem(R.id.action_search);SearchView searchView = (SearchView) searchItem.getActionView();// 获取应用级搜索服务SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);if (searchManager != null) {searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));}// 设置搜索监听searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {@Overridepublic boolean onQueryTextSubmit(String query) {performLocalSearch(query);return true;}@Overridepublic boolean onQueryTextChange(String newText) {return false;}});return true;}private void performLocalSearch(String query) {// 示例:搜索本地数据库或内存数据Toast.makeText(this, "搜索关键词: " + query, Toast.LENGTH_SHORT).show();}
}
步骤 3:定义菜单布局
res/menu/main_menu.xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"><itemandroid:id="@+id/action_search"android:title="搜索"android:icon="@android:drawable/ic_menu_search"app:actionViewClass="androidx.appcompat.widget.SearchView"app:showAsAction="ifRoom" />
</menu>
步骤 4:声明搜索能力
在 AndroidManifest.xml 中注册:
<activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.SEARCH" /></intent-filter><meta-data android:name="android.app.searchable"android:resource="@xml/app_searchable" />
</activity>
三、移除搜索控件的实现方法
方法 1:系统层级移除(需系统权限)
修改 AndroidManifest.xml,删除 SearchIndexProvider 的注册:
<manifest><application>
- <provider
- android:name=".SystemSearchIndexProvider"
- android:authorities="com.android.settings.search"
- android:exported="false"
- android:permission="android.permission.BIND_SEARCH_INDEXABLES" /></application>
</manifest>
方法 2:应用层级移除
方案 A:隐藏搜索栏(修改菜单)
删除 res/menu/main_menu.xml 中的搜索项:
<menu>
- <item
- android:id="@+id/action_search"
- android:title="搜索"
- android:icon="@android:drawable/ic_menu_search"
- app:actionViewClass="androidx.appcompat.widget.SearchView"
- app:showAsAction="ifRoom" />
</menu>
方案 B:禁用搜索逻辑
在 onCreateOptionsMenu 中直接返回 true 并跳过搜索绑定:
@Override
public boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.main_menu, menu);return true; // 不初始化搜索栏
}