Creating a Search Interface
版本:Android 4.0 r1
快速查看
- Android系統把搜索請求從搜索對話框或widget發送給執行搜索並顯示結果的activity
- 可以把搜索widget作爲“action view”放入Action Bar中,用於快速訪問
在本文中
關鍵類
相關示例
Action Bar中的SearchView
下載
參閱
如果要在應用程序中添加搜索功能,Android將會幫助程序實現用戶界面,可以用顯示在activity窗口頂端的搜索對話框, 也可以選用能夠置入程序layout的搜索widget,兩者都可以把用戶的搜索請求傳遞給程序指定的activity。 這樣,用戶就能從任何一個支持搜索框或搜索widget的activity中發起搜索,系統會啓動合適的activity來執行搜索並顯示結果。
搜索對話框和widget支持的其它特性包括:
- 語音搜索
- 根據最近的請求給出搜索建議項
- 匹配應用系統實際數據的搜索建議項
本指南展示了應用程序如何利用搜索對話框或者搜索widget來提供搜索界面,並在Android系統支持下從該界面中發送搜索請求。
首先,應該確定是否要用搜索對話框或搜索widget來實現搜索界面。這兩者提供的搜索功能是一樣的,只是在以下方面有細微差別:
- 搜索對話框是一個由Android 系統控制的UI組件。當被用戶激活時,搜索對話框顯示在activity的頂端,如圖1所示。
圖1.某應用程序搜索對話框的屏幕截圖
Android系統控制搜索對話框中所有的事件。當用戶提交一個請求時,系統將把該請求傳遞給預設的處理搜索的activity。搜索對話框還能在用戶鍵入時提供搜索建議項。 - 搜索widget是一個 SearchView的實例,可以把它放入layout的任何位置。默認情況下,搜索widget的顯示方式類似於一個標準的 EditText widget,並且不會執行任何動作。但可以對其進行配置,讓Android系統來處理所有錄入事件、把搜索請求傳遞給相應的activity、提供搜索建議項(如同搜索對話框一樣)。
不過,只有Android 3.0 (API Level 11) 以上版本才支持搜索widget。
注意:如果需要的話,可以利用多種回調方法和偵聽器(listener),來自行處理搜索widget內的所有用戶輸入。 不過本文重點關注如何結合系統和搜索widget來實現搜索功能。如果要自行處理所有的用戶輸入,請閱讀 SearchView及其內部接口的參考文檔。
一旦用戶在搜索對話框或搜索widget中執行了搜索,系統就會創建一個 Intent並把用戶的請求置入其中。然後系統會啓動activity並把intent傳給它,該activity是已聲明用於處理搜索的activity(“searchable activity”)。如果應用程序要設置爲這種搜索方式,則需要:
- 搜索配置文件
一個XML文件,定義了一些有關搜索對話框或widget的配置信息。包括了諸如語音搜索、搜索建議項和搜索框的提示文本等特性的設置。 - 搜索activity
接收搜索請求的 Activity ,用於搜索數據並顯示搜索結果。 - 搜索界面,可由以下方式之一提供:
- 搜索對話框
默認情況下,搜索對話框是隱藏的。當用戶按下設備上的“搜索”鍵(如果有的話)或者界面上的某個按鈕時,搜索框將出現在屏幕的頂端。 - 或者, SearchViewwidget
使用搜索widget可以把搜索框放入應用程序activity的任何位置。不過對於用戶而言,通常將它用作Action Bar中的action顯得更爲便捷,而不是放入某個activity layout中。
- 搜索對話框
本文以下部分展示瞭如何創建搜索配置文件、搜索activity,並用搜索對話框和搜索widget實現了一個搜索界面。
首先需要創建一個稱爲搜索配置文件(searchable configuration)的XML文件,它設置了搜索對話框或widget的用戶界面外觀,也定義了諸如搜索建議項、語音搜索之類的功能特性。該文件習慣上命名爲 searchable.xml,且必須存放於res/xml/ 目錄下。
注意:系統將利用該文件來初始化 SearchableInfo 對象,但在運行時無法自行創建此對象——只能在XML文件中聲明搜索配置。
搜索配置文件必須包含 <searchable> 元素作爲根節點,並指定一個以上的屬性。例如:
<?xml version="1.0" encoding="utf-8"?>
<searchablexmlns:android="http://schemas.android.com/apk/res/android"
</searchable>
只有android:label是必需的屬性,它指向字符串資源且應該是應用程序的名稱。用戶只有在“快速搜索框”中啓用搜索建議項時纔會看到這個文本標籤。這種情況下,該標籤會顯示在系統設置的“可搜索項”列表中。
雖然android:hint屬性不是必需項,但還是建議都要包含它。用戶錄入搜索文本前,它能在搜索框中顯示提示信息。這個提示信息相當重要,因爲它爲用戶能夠搜到什麼提供了重要線索。
提示:爲了與其它Android應用程序保持一致,應該把android:hint設置爲“搜索 <內容或產品>”的格式。例如:“搜索歌名或歌手名”或“搜索YouTube”。
<searchable> 元素還可以包含很多其它參數。不過,在加入諸如搜索建議項和語音搜索特性之前,大部分屬性都不需要用到。關於搜索配置文件的詳細信息,請參閱搜索配置文件 參考文檔。
創建搜索Activity
搜索activity是指應用程序中根據請求文本執行搜索並顯示結果的Activity。
當用戶在搜索對話框或widget中執行搜索時,系統將啓動搜索activity,並把搜索請求置入附帶ACTION_SEARCHaction的Intent中傳遞給它。搜索activity從intent附帶的QUERY中讀取查詢請求,然後搜索數據並顯示結果。
因爲搜索對話框或widget可能是位於應用程序的其它activity中,所以系統必須知道哪個activity將作爲搜索activity使用,以便正確地傳送搜索請求。因此,必須首先在Android manifest文件中聲明搜索activity。
聲明搜索activity
如果沒有現成的activity,就創建一個執行搜索並顯示結果的Activity。現在還不需要實現搜索功能——只是在manifest聲明一下來創建activity。在manifest的<activity>元素中:
1.
2.
例如:
<application ... >
</application>
<meta-data>元素必須包含值爲"android.app.searchable"的android:name屬性,以及指向搜索配置文件的android:resource屬性(此例中,指向res/xml/searchable.xml文件)。
注意:<intent-filter> 不需要指定值爲DEFAULT的<category>屬性(通常<activity> 元素中是會見到的),因爲系統會利用組件名稱把ACTION_SEARCH intent明確地傳遞給搜索activity。
一旦在manifest中完成了搜索activity的聲明,在搜索activity中執行搜索就涉及到以下三步:
1.
2.
3.
按照慣例,搜索結果應該顯示在ListView中,因此搜索activity可能需要繼承自ListActivity。包括默認帶一個ListView的layout,以及很多便於使用ListView的方法。
當用戶從搜索對話框或widget中執行搜索時,系統將會啓動搜索activity,並向它發送一個ACTION_SEARCHintent。該intent在QUERY字符串中附帶了搜索請求。搜索activity啓動後必須檢查此intent並解析該字符串。例如:以下是搜索activity啓動時如何讀取查詢請求的示例:
@Override
publicvoid onCreate(Bundle savedInstanceState){
}
ACTION_SEARCH intent總是包含QUERY字符串的。此例中,查詢請求讀取後又傳給了doMySearch()方法,實際的搜索操作在該方法中執行。
存儲和檢索數據的過程對於應用程序而言應該是唯一的。可以採用多種方式存儲和搜索數據,而本文並不展示如何存儲和檢索數據。存儲和檢索數據應該是依據需求和數據格式來仔細考慮的問題。下面是一些可能有用的提示:
·
·
關於適配器Adapter
適配器Adapter用於把一組數據綁定到View對象中。當把Adapter提交給ListView時,每項數據將作爲單獨的view插入到列表中。Adapter僅僅是一個接口,因此諸如CursorAdapter(綁定Cursor的數據)還是需要去實現代碼的。如果還沒有實現對數據的處理,則可以自己從BaseAdapter實現一個。安裝API Level 4的SDK示例包,可以看到“支持檢索的字典”的原始版本,它創建了一個自定義的適配器來讀取文件數據。
不論數據是否可用,也不管搜索方式如何,都建議用Adapter把搜索結果返回給搜索activity。這樣就可以很容易地把所有的搜索結果顯示在ListView中。如果數據來自SQLite數據庫查詢,可以用CursorAdapter把結果提交給ListView。如果數據來源是其它類型的,則可以創建一個繼承自BaseAdapter的類。
如上所述,建議把ListView作爲顯示搜索結果的用戶界面,這樣可能就需要讓搜索activity繼承自ListActivity。可以調用setListAdapter(),並把綁定了數據的Adapter傳遞給它。這就把所有搜索結果裝入了activity的ListView中。
更多關於顯示結果列表的有用信息,請參閱ListActivity文檔。
關於如何檢索SQLite數據庫以及用Adapter提交結果給ListView的完整示例,請參閱支持檢索的字典例程。
應該用搜索對話框還是widget?
答案大致取決於是否爲Android 3.0 (API Level 11) 以上版本進行開發,因爲SearchView widget自Android 3.0纔開始引入。因此,如果是爲低於3.0版的Android開發程序,就不能選擇搜索widget,應使用搜索對話框來實現搜索界面。
如果正在爲Android 3.0以上版本進行開發,則答案更多取決於需求。大多數情況下,建議把搜索widget作爲Action Bar 中的一個“action view”來使用。不過,因爲某些原因(也許沒有足夠的空間或者不會用到Action Bar),可能無法把搜索widget放入Action Bar。這樣就可能需要把搜索widget放入自己的activity layout中去。假如沒有其它方式可用且可以忍受不可見的搜索框,則還是可以換用搜索對話框。實際上在某些場合,可能需要同時提供對話框和widget。關於widget的詳情,請跳轉到使用搜索Widget.。
搜索對話框提供了位於屏幕頂部的浮動搜索框,搜索框左邊帶有應用程序圖標。用戶執行搜索時,搜索對話框可以在用戶鍵入時提供搜索建議項,系統將把搜索請求發送給執行檢索的搜索activity。不過,如果是爲運行Android 3.0的設備開發應用的話,則應考慮改用搜索widget(參見上文)。
搜索對話框默認是隱藏的,除非用戶激活它。如果用戶設備帶有“搜索”按鈕,則默認情況下按下此按鈕會激活搜索對話框。應用程序也可以在需要時調用onSearchRequested()激活搜索對話框。不過,這都要在activity中啓用搜索對話框之後才能生效。
要啓用搜索對話框,必須告訴系統哪個搜索activity將會從搜索對話框接收搜索請求並執行搜索。例如在上一節創建搜索Activity中,創建了一個名爲SearchableActivity的搜索activity。如果需要一個單獨的名爲OtherActivity的activity,用於顯示搜索對話框併發送搜索請求給SearchableActivity,則必須在manifest中聲明:SearchableActivity是供OtherActivity中的搜索對話框使用的搜索activity。
要爲activity中的搜索對話框聲明搜索activity,請在activity各自的<activity>元素內加入<meta-data>元素。<meta-data>元素必須包含android:value屬性,用於指定搜索activity類的名稱,以及值爲"android.app.default_searchable".的android:name屬性。
下面是演示了搜索activity SearchableActivity和OtherActivity的例程,搜索由OtherActivity中的對話框發起,而SearchableActivity執行搜索:
<application ... >
</application>
因爲OtherActivity現在包含了<meta-data>元素,即指明瞭使用哪個搜索activity來進行搜索,所以就表示OtherActivity已經啓用了搜索對話框。當用戶使用此activity時,設備的“搜索”按鈕(如果有的話)和onSearchRequested()方法將會激活搜索對話框。用戶一旦提交了搜索,系統將啓動SearchableActivity並向其發送ACTION_SEARCH intent。
注意:搜索activity本身默認是支持搜索對話框的,因此不需要在SearchableActivity加入以上聲明。
如果應用程序中所有的activity都需要支持搜索對話框,只要把上述<meta-data> 元素作爲子節點插入<application>元素中即可,而不需要對每個<activity>進行聲明。這樣每個activity都會繼承該值,對搜索對話框提供支持,並會把請求發送到同一個搜索activity中去。(如果存在多個搜索activity,可以把不同的<meta-data>聲明放入各自的activity中,覆蓋默認的搜索activity聲明即可。)
activity開啓搜索對話框後,應用程序就準備好執行搜索了。
如上所述,只要在manifest中對當前activity用到的搜索activity進行了聲明,設備上的“搜索”按鈕就會啓動搜索對話框。
不過有些設備不提供專用的“搜索”按鈕,所以不能假定該按鈕總是可用的。如果要使用搜索對話框,必須保證在用戶界面上另外提供一個搜索按鈕,用於調用onSearchRequested()激活搜索對話框。
舉例來說,應該在選項菜單提供一個菜單項,或者在activity layout上提供一個按鈕,它們可以調用onSearchRequested()來激活搜索。search_icons.zip文件包含了適應中密度和高密度屏幕的圖標,可用於搜索菜單項或按鈕(在低密度屏幕上會把高分辨率hdpi圖片縮小一半顯示)。
還可以啓用“鍵入搜索”(“type-to-search”)功能,使得用戶開始鍵盤輸入時激活搜索對話框——敲入的字符會插入到搜索對話框中去。通過在onCreate()方法內調用setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL),可以啓用activity的“鍵入搜索”功能。
搜索對話框對activity生命週期的影響
搜索對話框是一個浮動在屏幕頂端的Dialog。它不會導致activity棧發生任何變化,因此搜索對話框出現時,不會調用任何生命週期方法(比如onPause())。activity只是失去焦點,因爲輸入焦點切換給了搜索對話框。
如果期望搜索對話框激活時能夠獲得通知,請覆蓋onSearchRequested()方法。如果系統調用了該方法,就表明activity已經失去了焦點,而搜索對話框獲取了焦點,這樣就可以執行合適的生命週期事件操作了(比如暫停遊戲)。除非正在傳送搜索內容(在下文討論),否則就應該調用父類來結束本方法。例如:
@Override
publicboolean onSearchRequested(){
}
如果用戶按下“回退”按鈕取消了搜索,則搜索對話框會關閉,activity將重新獲得輸入焦點。可以用setOnDismissListener()和/或setOnCancelListener()進行註冊,使得搜索對話框關閉時能獲得通知。應該只需要註冊OnDismissListener即可,因爲每次關閉搜索對話框時都會調用它。而OnCancelListener只有在用戶顯式退出搜索對話框時纔會被調用,因此搜索執行完畢就不會調用它(這時搜索對話框自然會消失)。
如果當前activity不是搜索activity,則用戶執行搜索後會觸發正常的生命週期事件(當前activity會接收到onPause()等事件,如Activities文檔中所述)。不過,如果當前activity是搜索activity,則會發生以下兩件情況之一:
a.
b.
@Override
publicvoid onCreate(Bundle savedInstanceState){
}
@Override
protectedvoid onNewIntent(Intent intent){
}
privatevoid handleIntent(Intent intent){
}
對比執行搜索一節的示例代碼可以發現,現在所有處理搜索intent的代碼都放在handleIntent()方法中,這樣onCreate()和onNewIntent()都能調用它。
系統調用onNewIntent(Intent)時,activity並未被重啓,因此getIntent()方法返回的與onCreate()接收到的是同一個intent。這就是爲什麼應在onNewIntent(Intent)內調用setIntent(Intent)的原因(這樣以後調用getIntent()時,activity保存的intent將會更新)。
上述使用“singleTop”啓動模式的第二種情況通常是比較理想的,因爲一旦搜索完成,用戶就很有可能會執行其它搜索。如果應用程序創建了多個搜索activity實例,用戶體驗就會很糟糕。所以,建議在應用程序的manifest中把搜索activity設置爲“singleTop”啓動模式:
<activityandroid:name=".SearchableActivity"
某些情況下,在每次執行搜索的時候可能需在搜索activity中對搜索請求進行一些必要的優化。不過,如果是要根據用戶發起搜索的activity對搜索標準進行修改,則可以在系統發給搜索activityde intent中附帶額外數據。可以在APP_DATABundle中發送附加數據,它包含在ACTION_SEARCH intent中。
要發送這種數據給搜索activity,請覆蓋搜索發起activity的onSearchRequested()方法,創建一個帶有附加數據的Bundle,再調用startSearch()來激活搜索對話框。例如:
@Override
publicboolean onSearchRequested(){
返回“true”則表明已經成功處理了回調事件,調用startSearch()來激活搜索對話框。一旦用戶提交了請求,附加數據將會一起傳遞給搜索activity。可以從APP_DATABundle中解析出附加數據並對請求進行優化。比如:
Bundle appData = getIntent().getBundleExtra(SearchManager.APP_DATA);
if(appData !=null){
}
警告:永遠不要在onSearchRequested()回調方法以外調用startSearch()。要在activity中激活搜索對話框,一定要調用onSearchRequested()。否則,onSearchRequested()將不會被調用,自定義的功能(比如上述附加appData數據的例子)將會失效。
使用搜索Widget
Android 3.0以上版本才支持SearchView widget。如果正在爲Android 3.0開發應用程序,並決定使用搜索widget,則建議把搜索widget作爲一個Action Bar中的action view 進行插入,從而代替搜索對話框(也代替把搜索widget放入activity layout的方式)。圖2展示了Action Bar中的搜索widget 。
圖2.SearchView widget用作Action Bar 中的“action view”
搜索widget提供的功能與搜索對話框一樣。用戶執行搜索時,它將啓動相應的activity,並能支持搜索建議項和語音搜索。
注意:在把搜索widget作爲action view使用時,可能仍需同時提供搜索對話框的支持,因爲這種情況下搜索widget有可能不能適用於Action Bar。請參閱下節同時使用widget和對話框。
配置搜索widget
如上所述,在創建完搜索配置文件和搜索activity,需要啓用SearchView中的相應搜索功能。可以通過調用setSearchableInfo()實現這一目的,請將表示搜索配置的SearchableInfo對象傳入其中。
調用SearchManager中getSearchableInfo()的,可以獲得一個SearchableInfo引用。
比如,假設正在把SearchView用作Action Bar中的action view,應該在onCreateOptionsMenu()回調方法中啓用widget:
@Override
publicboolean onCreateOptionsMenu(Menu menu){
}
這就夠了。搜索widget現在已配置完成,系統將會把搜索請求發送給搜索activity。也可以爲搜索widget啓用搜索建議項。
注意:如果要自行處理所有的用戶輸入,利用一些回調方法和事件偵聽器即可。詳細信息請參閱SearchView的參考文檔,有關事件偵聽器可參閱其內部的接口。
關於Action Bar中action views的詳情,請參閱Action Bar開發者指南(內含把搜索widget作爲action view加入其中的示例代碼)。
其它搜索widget特性
SearchView widget還支持一些其它可能有用的特性:
提交按鈕
默認情況下是沒有用於提交查詢請求的按鈕的,用戶必須按下鍵盤上的“回車”鍵來啓動搜索。可以通過調用setSubmitButtonEnabled(true)來增加“提交”按鈕。
精確確認搜索建議項中的搜索請求
如果啓用了搜索建議項,通常是期望用戶能簡單地選中建議項即可,但是有可能需要對建議的搜索請求進行精確確認。通過調用setQueryRefinementEnable
切換搜索框的可見性
默認情況下,搜索widget是“圖標化的”,也就是隻用一個搜索圖標(放大鏡)來表示,當用戶觸摸時纔會展開顯示搜索框。如上所示,通過調用setIconifiedByDefault(false),也可以默認就把搜索框顯示出來。還可以通過調用setIconified(),來切換搜索widget的顯示方式。
在SearchView類中還有很多其它的API,可用於定製搜索widget。不過大部分API都只是在自行處理用戶輸入時纔會用到,用於取代Android系統來發送搜索請求並顯示搜索建議項。
同時使用widget和對話框
如果把搜索widget作爲action view插入Action Bar,並且設置爲Action Bar“空間夠用時”才顯示(設置android:showAsAction="ifRoom"),那麼搜索widget有可能無法顯示爲一個action view,而是作爲菜單項顯示在overflow菜單中的。比如,應用程序如果運行在小屏幕上,Action Bar可能會沒有足夠的空間,無法在其它action項或瀏覽元素邊上再顯示搜索widget了,於是它就會作爲菜單項顯示在overflow 菜單中。如果放入了overflow菜單中,則它會表現爲普通的菜單項,而不會顯示爲action view(搜索widget)。
爲了應付這種狀況,用戶從overflow菜單中選中時,與搜索widget關聯的菜單項應該激活搜索對話框。爲了實現這一目標,必須實現onOptionsItemSelected()來處理“搜索”菜單項,並調用onSearchRequested()打開搜索對話框。
關於Action Bar中的項目如何工作及如何處理這種情況,請參閱Action Bar開發者指南。
關於同時使用對話框和widget的示例代碼,請參閱支持檢索的字典。
通過在搜索配置文件中添加android:voiceSearchMode屬性,可以在搜索對話框或widget 中加入語音搜索功能。這會增加一個語音搜索按鈕,用於啓動語音提醒。當用戶說完後,轉譯成文本的請求將會發送給搜索activity。
例如:
<?xml version="1.0" encoding="utf-8"?>
<searchablexmlns:android="http://schemas.android.com/apk/res/android"
</searchable>
值showVoiceSearchButton是開啓語音搜索的必填項,而第二個值launchRecognizer標明語音搜索按鈕應啓動一個識別器返回轉譯過的文本,用於搜索activity 。
可以用其它一些屬性來定義語音搜索的行爲,比如所用的語言和返回結果的最大數量。關於支持的屬性的詳情,請參閱搜索配置文件。
注意:請仔細考慮一下應用程序是否適合使用語音搜索。所有用語音搜索鍵執行的的搜索都是立即提交給搜索activity 的,用戶沒有機會查看轉譯過的請求文本。請對語音識別過程進行充分的測試,確保對用戶可能在本應用中提交的請求能作出正確的理解。
在Android系統的支持下,搜索對話框和搜索widget都能在用戶鍵入時提供搜索建議項,系統將管理建議項列表並對用戶選中建議項時觸發的事件進行處理。
可以提供兩種搜索建議項:
最近請求搜索建議
這類建議項很簡單,即爲用戶之前在本應用程序中使用過的搜索請求文本。
參閱添加最近請求建議項。
自定義搜索建議
這類搜索建議來自於自定義數據源,可幫助用戶迅速選中正確的拼寫或所檢索的內容。圖3展示了一個字典應用中的自定義建議項示例——用戶可以選中建議項以直接獲取釋義。
請參閱添加自定義建議項。
圖3.帶自定義搜索建議項的搜索對話框屏幕截圖