首先要建立本身的SearchRecentSuggestionsProvider,用於保存和查詢搜索記錄。android
SearchRecentSuggestionsProvider基本實現了進行讀寫搜索歷史所需的全部功能,只需繼承它並定義ContentProvider的AUTHORITY和Mode。Mode必須包含 DATABASE_MODE_QUERIES ,可選包含 DATABASE_MODE_2LINES 來讓歷史記錄具備兩行內容。具體內容以下:git
public class SimpleSearchSuggestionsProvider extends SearchRecentSuggestionsProvider { private static final String LOG_TAG = SimpleSearchSuggestionsProvider.class.getSimpleName(); public final static String AUTHORITY = "com.nex3z.examples.customsearchsuggestionitem.SimpleSearchSuggestionsProvider"; public final static int MODE = DATABASE_MODE_QUERIES; public SimpleSearchSuggestionsProvider() { setupSuggestions(AUTHORITY, MODE); } }
而後要在AndroidManifest.xml中聲明這個ContentProvider:github
<application ... <provider android:name=".SimpleSearchSuggestionsProvider" android:authorities="com.nex3z.examples.customsearchsuggestionitem.SimpleSearchSuggestionsProvider" /> ... </application>
有了SimpleSearchSuggestionsProvider,就可使用SearchRecentSuggestions能夠很方便地保存搜索記錄:app
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this, SimpleSearchSuggestionsProvider.AUTHORITY, SimpleSearchSuggestionsProvider.MODE); suggestions.saveRecentQuery(query, null);
這裏 saveRecentQuery() 的第一個參數表明要保存的搜索記錄,第二個參數爲可選添加的內容(須要在SearchRecentSuggestionsProvider設置 DATABASE_MODE_2LINES )。ide
能夠按照使用通常ContentProvider的方法來查詢搜索記錄。這裏使用了SearchManager來輔助創建uri:佈局
public Cursor getRecentSuggestions(String query, int limit) { Uri.Builder uriBuilder = new Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(SimpleSearchSuggestionsProvider.AUTHORITY); uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY); String selection = " ?"; String[] selArgs = new String[] { query }; if (limit > 0) { uriBuilder.appendQueryParameter( SearchManager.SUGGEST_PARAMETER_LIMIT, String.valueOf(limit)); } Uri uri = uriBuilder.build(); return getContentResolver().query(uri, null, selection, selArgs, null); }
接下來建立自定義的Suggestion Item,在res/layout下創建search_suggestion_item.xml,其中包含一個用於顯示圖標的ImageView和一個用於顯示提示的TextView:ui
<LinearLayout android:orientation="horizontal" ...> <ImageView android:id="@+id/iv_suggestion_item_icon" .../> <TextView android:id="@+id/tv_suggestion_item_title" .../> </LinearLayout>
Adapter把從ContentProvider中獲取的提示數據填充到上面建立的Item裏,這裏的Adapter就是一個簡單的CursorAdapter。前面使用SearchRecentSuggestions的 saveRecentQuery() 方法來保存歷史記錄,對應地,這裏要從 SearchManager.SUGGEST_COLUMN_TEXT_1 獲取所保存的搜索歷史記錄。this
[@Override](https://my.oschina.net/u/1162528) public void bindView(View view, Context context, Cursor cursor) { ViewHolder viewHolder = (ViewHolder) view.getTag(); viewHolder.mTitle.setText( cursor.getString(cursor.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1))); }
Searchable Configuration用於配置搜索對話框的UI。在res/xml下創建searchable.xml,其中必須包含 label ,一般爲app的名稱,通常不可見。這裏還添加了 hint ,用於在用戶未輸入搜索內容時,在搜索框顯示提示。因爲這裏使用了自定義的adapter來顯示搜索提示,這裏並不須要添加 searchSuggestAuthority 。.net
<searchable xmlns:android="http://schemas.android.com/apk/res/android" android:label="@string/app_name" android:hint="@string/search_hint" />
Searchable Activity用來處理搜索,當用戶提交搜索後,系統會啓動對應的Activity,搜索內容經過帶有 ACTION_SEARCH 的intent來傳遞。code
這裏以MainActivity作爲Searchable Activity,首先要在AndroidManifest.xml中聲明。
<application ... <activity android:name=".MainActivity" android:launchMode="singleTop"> <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> ... </application>
首先要添加meta-data,指向上一步中建立的Searchable Configuration(searchable.xml)。而後還要註冊 android.intent.action.SEARCH的intent-filter,用於接收用戶提交搜索後由系統發出的intent。注意這裏還設置了 launchMode 爲 singleTop ,避免搜索時重複啓動Activity。
在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/action_search" android:icon="@drawable/ic_search_24dp" app:showAsAction="collapseActionView|ifRoom" app:actionViewClass="android.support.v7.widget.SearchView" /> </menu>
搜索菜單以放大鏡圖標按鈕的形式顯示,注意這裏指定 app:actionViewClass 爲Support Library的SearchView。
首先在onCreateOptionsMenu()找到搜索菜單對應的MenuItem:
@Override public boolean onCreateOptionsMenu(Menu menu){ getMenuInflater().inflate(R.menu.menu_search, menu); MenuItem searchItem = menu.findItem(R.id.action_search); ... }
而後由searchItem獲取SearchView,並經過SearchManager配置SearchableInfo,也就是以前的searchable.xml:
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE); final SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem); searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
接下來把SearchSuggestionAdapter配置到searchView(注意SearchView的 setSuggestionsAdapter() 只支持CursorAdapter):
mSuggestionAdapter = new SearchSuggestionAdapter(this, null, 0); searchView.setSuggestionsAdapter(mSuggestionAdapter);
當搜索框內容變化時,從ContentProvider查詢對應的搜索記錄,並傳遞給adapter:
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { return false; } @Override public boolean onQueryTextChange(String newText) { Cursor cursor = getRecentSuggestions(newText, 10); mSuggestionAdapter.swapCursor(cursor); return false; } });
當suggestion被選中時,把對應suggestion內容填充到搜索欄,並觸發搜索:
searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() { @Override public boolean onSuggestionSelect(int position) { return false; } @Override public boolean onSuggestionClick(int position) { searchView.setQuery(mSuggestionAdapter.getSuggestionText(position), true); return true; } });
這裏 setQuery() 的第二個參數指示是否觸發搜索,這裏設爲true,當用戶點擊搜索歷史提示時,會當即搜索指定關鍵詞。
使用自定義搜索提示時,處理搜索並無什麼不一樣,這裏順帶一提。當用戶提交搜索後,系統會啓動對應的Searchable Activity,發送ACTION_SEARCH intent,其中帶有名爲 QUERY 的String extra保存了搜索內容。 首先在 onCreate() 中調用 handleIntent() 來處理 ACTION_SEARCH ,另外Activity設置了 launchMode 爲 "singleTop" ,還須要在 onNewIntent() 中調用 handleIntent() 。
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); handleIntent(getIntent()); } @Override protected void onNewIntent(Intent intent) { handleIntent(intent); } private void handleIntent(Intent intent) { if (Intent.ACTION_SEARCH.equals(intent.getAction())) { String query = intent.getStringExtra(SearchManager.QUERY); SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this, SimpleSearchSuggestionsProvider.AUTHORITY, SimpleSearchSuggestionsProvider.MODE); suggestions.saveRecentQuery(query, null);// 保存最近的數據 } }
https://github.com/nex3z/android-examples/tree/master/CustomSearchSuggestionItem