準備好在應用程式中加入搜尋功能時,Android 可協助您實作使用者介面,方法是使用活動視窗頂端顯示的搜尋對話方塊,或是插入版面配置的搜尋小工具。搜尋對話方塊和小工具都能將使用者的搜尋查詢傳送至應用程式中的特定活動。這樣一來,使用者就能從任何提供搜尋對話方塊或小工具的活動發起搜尋,系統也會啟動適當的活動來執行搜尋並顯示結果。
搜尋對話方塊和搜尋小工具的其他可用功能包括:
- 語音搜尋
- 根據近期查詢記錄提供的搜尋建議
- 與應用程式資料中的實際結果相符的搜尋建議
本文說明如何設定應用程式,透過搜尋對話方塊或搜尋小工具,提供由 Android 系統輔助傳送搜尋查詢的搜尋介面。
相關資源:
基本概念
開始前,請先決定要使用搜尋對話方塊還是搜尋小工具,實作搜尋介面。兩者提供的搜尋功能相同,但方式略有不同:
- 搜尋對話方塊是由 Android 系統控制的 UI 元件。使用者啟動後,搜尋對話方塊會顯示在活動頂端。
Android 系統會控管搜尋對話方塊中的所有事件。使用者提交查詢時,系統會將查詢傳送至您指定的活動,以處理搜尋作業。對話方塊也會在使用者輸入內容時提供搜尋建議。
- 搜尋小工具是
SearchView的執行個體,可放在版面配置中的任何位置。根據預設,搜尋小工具的行為與標準小工具類似,不會執行任何動作,但您可以設定讓 Android 系統處理所有輸入事件、將查詢傳送至適當的活動,並提供搜尋建議,就像搜尋對話方塊一樣。EditText
當使用者從搜尋對話方塊或搜尋小工具執行搜尋時,系統會建立 Intent,並在其中儲存使用者查詢。接著,系統會啟動您宣告要處理搜尋的活動 (「可搜尋活動」),並將意圖傳送給該活動。如要為這類輔助搜尋設定應用程式,您需要:
- 搜尋設定
- XML 檔案,用於設定搜尋對話方塊或小工具的某些設定。 包括語音搜尋、搜尋建議和搜尋框提示文字等功能設定。
- 可搜尋的活動
- 接收搜尋查詢、搜尋資料,並顯示搜尋結果的
。Activity- 搜尋介面,可透過下列任一方式提供:
- 搜尋對話方塊
- 搜尋對話方塊預設為隱藏。當使用者輕觸「搜尋」按鈕時,呼叫
onSearchRequested(),畫面頂端就會顯示這個按鈕。SearchView小工具- 使用搜尋小工具,即可在活動中的任何位置放置搜尋方塊,包括應用程式列中的動作檢視畫面。
本文的其餘部分將說明如何建立搜尋設定和可搜尋的活動,以及如何使用搜尋對話方塊或搜尋小工具實作搜尋介面。
建立可供搜尋的設定
首先,您需要名為「搜尋設定」的 XML 檔案。這項設定會設定搜尋對話方塊或小工具的特定 UI 方面,並定義建議和語音搜尋等功能的運作方式。這個檔案傳統上會命名為 searchable.xml,且必須儲存在 res/xml/ 專案目錄中。
搜尋設定檔必須包含 <searchable> 元素做為根節點,並指定一或多個屬性,如下列範例所示:
<?xml version="1.0" encoding="utf-8"?> <searchable xmlns:android="http://schemas.android.com/apk/res/android" android:label="@string/app_label" android:hint="@string/search_hint" > </searchable>
android:label 屬性是唯一的必要屬性。這個屬性會指向字串資源,該資源必須是應用程式名稱。啟用快速搜尋框的搜尋建議功能後,使用者才會看到這個標籤,且標籤會顯示在系統設定的可搜尋項目清單中。
雖然不是必要條件,但我們建議您一律加入 android:hint 屬性,在使用者輸入查詢之前,於搜尋方塊中提供提示字串。提示非常重要,因為可為使用者提供重要的搜尋線索。
<searchable> 元素可接受其他幾個屬性。不過,在加入搜尋建議和語音搜尋等功能之前,您不需要大多數屬性。如要進一步瞭解搜尋設定檔,請參閱搜尋設定參考文件。
建立可搜尋的活動
可搜尋的活動是指應用程式中的 Activity,會根據查詢字串執行搜尋並顯示搜尋結果。
使用者在搜尋對話方塊或小工具中執行搜尋時,系統會啟動可搜尋的活動,並在 Intent 中透過 ACTION_SEARCH 動作將搜尋查詢傳送給活動。可搜尋的活動會從意圖的 QUERY 額外資料中擷取查詢,然後搜尋資料並顯示結果。
由於您可以在應用程式中的任何其他活動中加入搜尋對話方塊或小工具,系統必須知道哪個活動是可搜尋的活動,才能正確傳送搜尋查詢。因此,請先在 Android 資訊清單檔案中宣告可搜尋的活動。
宣告可搜尋的活動
如果沒有,請建立一個可執行搜尋並顯示結果的 Activity。您還不需要實作搜尋功能,只要建立可在資訊清單中宣告的活動即可。在資訊清單的 <activity> 元素中,執行下列操作:
- 在
<intent-filter>元素中,宣告活動接受ACTION_SEARCH意圖。 - 在
<meta-data>元素中指定要使用的搜尋設定。
例如:
<application ... > <activity android:name=".SearchableActivity" > <intent-filter> <action android:name="android.intent.action.SEARCH" /> </intent-filter> <meta-data android:name="android.app.searchable" android:resource="@xml/searchable"/> </activity> ... </application>
<meta-data> 元素必須包含 android:name 屬性 (值為 "android.app.searchable") 和 android:resource 屬性 (參照可搜尋的設定檔)。在上述範例中,這指的是 res/xml/searchable.xml 檔案。
執行搜尋
在資訊清單中宣告可搜尋的活動後,請按照下列程序在可搜尋的活動中執行搜尋:
接收查詢
使用者透過搜尋對話方塊或小工具執行搜尋時,系統會啟動可搜尋的活動,並傳送 ACTION_SEARCH 意圖。這項意圖會在 QUERY 字串額外資訊中攜帶搜尋查詢。活動啟動時,請檢查這項意圖並擷取字串。舉例來說,以下說明如何在可搜尋的活動啟動時取得搜尋查詢:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.search) // Verify the action and get the query. if (Intent.ACTION_SEARCH == intent.action) { intent.getStringExtra(SearchManager.QUERY)?.also { query -> doMySearch(query) } } }
Java
@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); } }
QUERY 字串一律會隨附於 ACTION_SEARCH 意圖。在上一個範例中,系統會擷取查詢並傳遞至本機 doMySearch() 方法,實際的搜尋作業會在該方法中完成。
搜尋資料
儲存及搜尋資料的程序因應用程式而異。您可以使用多種方式儲存及搜尋資料,本文不會說明具體做法。請根據需求和資料格式,考量如何儲存及搜尋資料。以下提供幾項實用訣竅:
- 如果資料儲存在裝置的 SQLite 資料庫中,使用 FTS3 (而非
LIKE查詢) 執行全文搜尋,可更全面地搜尋文字資料,並大幅加快產生結果的速度。如要瞭解 FTS3,請參閱 sqlite.org;如要瞭解 Android 上的 SQLite,請參閱SQLiteDatabase類別。 - 如果資料儲存在線上,使用者資料連線可能會影響搜尋效能。您可能想顯示進度指標,直到搜尋傳回結果為止。如需網路 API 的參考資料,請參閱
android.net,如要瞭解如何顯示進度指標,請參閱ProgressBar。
呈現結果
無論資料儲存位置和搜尋方式為何,我們都建議您使用 Adapter 將搜尋結果傳回可搜尋的活動。這樣一來,您就能在RecyclerView中呈現所有搜尋結果。如果資料來自 SQLite 資料庫查詢,您可以透過 CursorAdapter 將結果套用至 RecyclerView。如果資料採用其他格式,您可以建立 BaseAdapter 的擴充功能。
Adapter 會將一組資料中的每個項目繫結至 View 物件。將 Adapter 套用至 RecyclerView 時,每個資料片段都會做為個別檢視區塊插入清單。Adapter 只是介面,因此需要實作 (例如 CursorAdapter,用於繫結 Cursor 中的資料)。如果現有實作方式都不適用於您的資料,您可以從 BaseAdapter實作自己的方式。
使用搜尋對話方塊
搜尋對話方塊會在畫面頂端提供浮動搜尋框,左側則顯示應用程式圖示。搜尋對話方塊可在使用者輸入內容時提供搜尋建議。使用者執行搜尋時,系統會將搜尋查詢傳送至執行搜尋的可搜尋活動。
根據預設,搜尋對話方塊一律會隱藏,直到使用者啟用為止。
應用程式可以呼叫 onSearchRequested() 啟動搜尋對話方塊。不過,您必須先為活動啟用搜尋對話方塊,這個方法才能運作。
如要啟用搜尋對話方塊來執行搜尋,請向系統指出哪些可搜尋的活動必須接收搜尋對話方塊的搜尋查詢。舉例來說,在建立可搜尋活動的上一節中,我們建立了一個名為 SearchableActivity 的可搜尋活動。如果您希望由名為 OtherActivity 的獨立活動顯示搜尋對話方塊,並將搜尋查詢傳送至 SearchableActivity,請在資訊清單中宣告 SearchableActivity 是要用於 OtherActivity 中搜尋對話方塊的可搜尋活動。
如要為活動的搜尋對話方塊宣告可搜尋的活動,請在相應活動的 <activity> 元素內新增 <meta-data> 元素。<meta-data> 元素必須包含 android:value 屬性,指定可搜尋活動的類別名稱,以及值為 "android.app.default_searchable" 的 android:name 屬性。
舉例來說,以下是可搜尋活動 SearchableActivity 和另一個活動 OtherActivity 的聲明,後者會使用 SearchableActivity 執行從搜尋對話方塊執行的搜尋:
<application ... > <!-- This is the searchable activity; it performs searches. --> <activity android:name=".SearchableActivity" > <intent-filter> <action android:name="android.intent.action.SEARCH" /> </intent-filter> <meta-data android:name="android.app.searchable" android:resource="@xml/searchable"/> </activity> <!-- This activity enables the search dialog to initiate searches in the SearchableActivity. --> <activity android:name=".OtherActivity" ... > <!-- Enable the search dialog to send searches to SearchableActivity. --> <meta-data android:name="android.app.default_searchable" android:value=".SearchableActivity" /> </activity> ... </application>
由於 OtherActivity 現在包含 <meta-data> 元素,可宣告要用於搜尋的可搜尋活動,因此活動會啟用搜尋對話方塊。雖然使用者位於這個活動中,但 onSearchRequested() 方法會啟動搜尋對話方塊。使用者執行搜尋時,系統會啟動 SearchableActivity,並將 ACTION_SEARCH 意圖傳送給該服務。
如要讓應用程式中的每個活動都提供搜尋對話方塊,請將上述 <meta-data> 元素插入為 <application> 元素的子項,而不是每個 <activity>。這樣一來,每個活動都會繼承值、提供搜尋對話方塊,並將搜尋結果傳送至同一個可搜尋的活動。如果您有多個可搜尋的活動,可以在個別活動中放置不同的 <meta-data> 宣告,覆寫預設的可搜尋活動。
活動已啟用搜尋對話方塊,應用程式現在可以執行搜尋。
叫用搜尋對話方塊
雖然部分裝置提供專用的搜尋按鈕,但按鈕的行為可能因裝置而異,而且許多裝置根本沒有搜尋按鈕。因此,使用搜尋對話方塊時,您必須在 UI 中提供搜尋按鈕,透過呼叫 onSearchRequested() 啟動搜尋對話方塊。
舉例來說,在選項選單或 UI 版面配置中新增搜尋按鈕,呼叫 onSearchRequested()。
你也可以啟用「輸入即搜尋」功能,讓使用者在鍵盤上輸入內容時啟動搜尋對話方塊。按鍵會插入搜尋對話方塊。如要在活動中啟用輸入搜尋功能,請在活動的 onCreate() 方法中呼叫 setDefaultKeyMode 或 DEFAULT_KEYS_SEARCH_LOCAL。
搜尋對話方塊對活動生命週期的影響
搜尋對話方塊會浮動顯示在畫面頂端。Dialog這不會導致活動堆疊發生任何變化,因此當搜尋對話方塊顯示時,系統不會呼叫任何生命週期方法,例如 onPause()。您的活動會失去輸入焦點,因為輸入焦點會提供給搜尋對話方塊。
如要在搜尋對話方塊啟動時收到通知,請覆寫 onSearchRequested() 方法。系統呼叫這個方法時,表示活動失去搜尋對話方塊的輸入焦點,因此您可以執行適合該事件的任何工作,例如暫停遊戲。除非您傳遞搜尋內容資料 (本文另一節會說明),否則請呼叫父類別實作來結束方法:
Kotlin
override fun onSearchRequested(): Boolean { pauseSomeStuff() return super.onSearchRequested() }
Java
@Override public boolean onSearchRequested() { pauseSomeStuff(); return super.onSearchRequested(); }
如果使用者輕觸「返回」按鈕取消搜尋,搜尋對話方塊就會關閉,活動也會重新取得輸入焦點。您可以註冊在搜尋對話方塊關閉時收到通知,方法是使用 setOnDismissListener()、setOnCancelListener() 或兩者。您只需要註冊 OnDismissListener,因為每次關閉搜尋對話方塊時都會呼叫這個函式。OnCancelListener
僅適用於使用者明確結束搜尋對話方塊的事件,因此執行搜尋時不會呼叫此函式。執行搜尋時,搜尋對話方塊會自動消失。
如果目前的活動不是可搜尋的活動,當使用者執行搜尋時,系統會觸發正常的活動生命週期事件,目前的活動會收到 onPause(),如「活動簡介」所述。不過,如果目前的活動是可搜尋的活動,則會發生下列其中一種情況:
- 根據預設,可搜尋的活動會透過呼叫
onCreate()接收ACTION_SEARCH意圖,且活動的新例項會移至活動堆疊頂端。活動堆疊中現在有兩個可搜尋活動的例項,因此輕觸「返回」按鈕會返回可搜尋活動的上一個例項,而不是結束可搜尋活動。 - 如果將
android:launchMode設為"singleTop",可搜尋活動就會透過呼叫onNewIntent(Intent)接收ACTION_SEARCH意圖,並傳遞新的ACTION_SEARCH意圖。舉例來說,以下說明如何處理這個情況,其中可搜尋活動的啟動模式為"singleTop":Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.search) handleIntent(intent) } override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) setIntent(intent) handleIntent(intent) } private fun handleIntent(intent: Intent) { if (Intent.ACTION_SEARCH == intent.action) { intent.getStringExtra(SearchManager.QUERY)?.also { query -> doMySearch(query) } } }
Java
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.search); handleIntent(getIntent()); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); handleIntent(intent); } private void handleIntent(Intent intent) { if (Intent.ACTION_SEARCH.equals(intent.getAction())) { String query = intent.getStringExtra(SearchManager.QUERY); doMySearch(query); } }
與執行搜尋一節中的程式碼範例相比,現在處理搜尋意圖的所有程式碼都位於
handleIntent()方法中,因此onCreate()和onNewIntent()都能執行該方法。系統呼叫
onNewIntent(Intent)時,活動不會重新啟動,因此getIntent()方法會傳回與onCreate()一起收到的相同意圖。因此,您必須在onNewIntent(Intent)內呼叫setIntent(Intent),這樣一來,如果日後呼叫getIntent(),活動儲存的意圖就會更新。
第二種情境是使用 "singleTop" 啟動模式,通常較為合適,因為使用者完成搜尋後可能會執行其他搜尋,您不希望應用程式建立可搜尋活動的多個例項。建議您在應用程式資訊清單中,將可搜尋的活動設為 "singleTop" 啟動模式,如下列範例所示:
<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>
傳遞搜尋內容資料
在某些情況下,您可以在每次搜尋時,對可搜尋的活動進行必要的搜尋查詢調整。不過,如果想根據使用者執行搜尋的活動,調整搜尋條件,可以在系統傳送至可搜尋活動的意圖中提供額外資料。您可以在 APP_DATA
Bundle 中傳遞額外資料,這會包含在 ACTION_SEARCH 意圖中。
如要將這類資料傳遞至可搜尋的活動,請覆寫使用者可執行搜尋的活動的 onSearchRequested() 方法,使用額外資料建立 Bundle,然後呼叫 startSearch() 啟動搜尋對話方塊。例如:
Kotlin
override fun onSearchRequested(): Boolean { val appData = Bundle().apply { putBoolean(JARGON, true) } startSearch(null, false, appData, false) return true }
Java
@Override public boolean onSearchRequested() { Bundle appData = new Bundle(); appData.putBoolean(SearchableActivity.JARGON, true); startSearch(null, false, appData, false); return true; }
傳回 true 表示您已成功處理這個回呼事件,並呼叫 startSearch() 啟動搜尋對話方塊。使用者提交查詢後,系統會將查詢連同您新增的資料,一併傳送至可搜尋的活動。您可以從 APP_DATA
Bundle 擷取額外資料,以修正搜尋結果,如下例所示:
Kotlin
val jargon: Boolean = intent.getBundleExtra(SearchManager.APP_DATA)?.getBoolean(JARGON) ?: false
Java
Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA); if (appData != null) { boolean jargon = appData.getBoolean(SearchableActivity.JARGON); }
使用搜尋小工具
圖 1. 應用程式列中的動作檢視畫面 SearchView 小工具。
搜尋小工具提供的功能與搜尋對話方塊相同。當使用者執行搜尋時,這個類別會啟動適當的活動,並提供搜尋建議和執行語音搜尋。如果無法將搜尋小工具放在應用程式列中,可以改為放在活動版面配置的某個位置。
設定搜尋小工具
建立搜尋設定和可搜尋的活動後,請呼叫 setSearchableInfo() 並傳遞代表可搜尋設定的 SearchableInfo 物件,為每個 SearchView 啟用輔助搜尋功能。
您可以呼叫 SearchManager 上的 getSearchableInfo(),取得 SearchableInfo 的參照。
舉例來說,如果您在應用程式列中使用 SearchView 做為動作檢視畫面,請在 onCreateOptionsMenu() 回呼期間啟用小工具,如下列範例所示:
Kotlin
override fun onCreateOptionsMenu(menu: Menu): Boolean { // Inflate the options menu from XML. val inflater = menuInflater inflater.inflate(R.menu.options_menu, menu) // Get the SearchView and set the searchable configuration. val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager (menu.findItem(R.id.menu_search).actionView as SearchView).apply { // Assumes current activity is the searchable activity. setSearchableInfo(searchManager.getSearchableInfo(componentName)) setIconifiedByDefault(false) // Don't iconify the widget. Expand it by default. } return true }
Java
@Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the options menu from XML. MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.options_menu, 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(); // Assumes current activity is the searchable activity. searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName())); searchView.setIconifiedByDefault(false); // Don't iconify the widget. Expand it by default. return true; }
搜尋小工具已設定完成,系統會將搜尋查詢傳送至可搜尋的活動。你也可以為搜尋小工具啟用搜尋建議。
如要進一步瞭解應用程式列中的動作檢視畫面,請參閱「使用動作檢視畫面和動作供應程式」。
其他搜尋小工具功能
SearchView 小工具提供幾項額外功能,可能符合您的需求:
- 提交按鈕
- 根據預設,系統不會提供提交搜尋查詢的按鈕,因此使用者必須按下鍵盤上的 Return 鍵才能啟動搜尋。您可以呼叫
setSubmitButtonEnabled(true)新增「提交」按鈕。 - 修正查詢,取得更精確的搜尋建議
- 啟用搜尋建議時,您通常會希望使用者選取建議,但他們也可能想修正建議的搜尋查詢。您可以為每項建議新增按鈕,呼叫
setQueryRefinementEnabled(true),在搜尋框中插入建議,供使用者修正。 - 可切換搜尋框的顯示設定
- 根據預設,搜尋小工具會「圖示化」,也就是只以搜尋圖示 (放大鏡) 表示。使用者輕觸圖示時,這個圖示會展開並顯示搜尋框。如上一個範例所示,您可以呼叫
setIconifiedByDefault(false),依預設顯示搜尋方塊。您也可以呼叫setIconified(),切換搜尋小工具的外觀。
SearchView 類別中還有其他 API,可供您自訂搜尋小工具。不過,大多數屬性只會在您自行處理所有使用者輸入內容時使用,而不是使用 Android 系統傳送搜尋查詢及顯示搜尋建議。
同時使用小工具和對話方塊
如果您在應用程式列中插入搜尋小工具做為動作檢視區塊,並設定 android:showAsAction="ifRoom",在應用程式列有空間時顯示該小工具,則搜尋小工具可能不會顯示為動作檢視區塊。而是顯示在溢位選單中。舉例來說,如果應用程式在較小的螢幕上執行,應用程式列可能沒有足夠空間顯示搜尋小工具,以及其他動作項目或導覽元素,因此選單項目會改為顯示在溢位選單中。如果放在溢位選單中,項目會像一般選單項目一樣運作,不會顯示動作檢視區塊 (即搜尋小工具)。
如要處理這種情況,您附加搜尋小工具的選單項目必須在使用者從溢位選單選取時,啟動搜尋對話方塊。如要達成這個目標,請實作
onOptionsItemSelected()
來處理「搜尋」選單項目,並呼叫
onSearchRequested() 開啟搜尋對話方塊。
如要進一步瞭解應用程式列中的項目運作方式,以及如何處理這種情況,請參閱「新增應用程式列」。
新增語音搜尋
如要將語音搜尋功能新增至搜尋對話方塊或小工具,請在可搜尋的設定中加入 android:voiceSearchMode 屬性。這會新增語音搜尋按鈕,啟動語音提示。
使用者說完話後,系統會將轉錄的搜尋查詢傳送至可搜尋的活動。
例如:
<?xml version="1.0" encoding="utf-8"?> <searchable xmlns:android="http://schemas.android.com/apk/res/android" android:label="@string/search_label" android:hint="@string/search_hint" android:voiceSearchMode="showVoiceSearchButton|launchRecognizer" > </searchable>
如要啟用語音搜尋,必須將值設為 showVoiceSearchButton。第二個值 launchRecognizer 則指定語音搜尋按鈕必須啟動辨識器,將轉錄文字傳回可搜尋的活動。
您可以提供其他屬性來指定語音搜尋行為,例如預期語言和要傳回的結果數上限。如要進一步瞭解可用屬性,請參閱搜尋設定參考資料。
新增搜尋建議
搜尋對話方塊和搜尋小工具都能在使用者輸入內容時,透過 Android 系統輔助提供搜尋建議。系統會管理建議清單,並在使用者選取建議時處理事件。
您可以提供兩種搜尋建議:
- 近期查詢搜尋建議
- 這些建議是使用者先前在應用程式中使用的搜尋查詢字詞。詳情請參閱「新增自訂搜尋建議」。
- 自訂搜尋建議
- 這些搜尋建議來自你提供的資料來源,可協助使用者立即選取正確的拼字或搜尋項目。詳情請參閱「新增自訂搜尋建議」。