为Android应用增加搜索功能:增加搜索建议

译文
移动开发 Android
在本系列共两篇的教程中,将指导开发者如何利用Android的 搜索框架进行搜索功能的开发。在本讲中,将继续学习在搜索应用中增加搜索提示建议的功能。

在上一篇教程<<为Android应用添加搜索功能>>中,我们学习了如何在android应用中其搜索框架的基本功能,在本讲中,将继续学习在搜索应用中增加搜索提示建议的功能。

什么是搜索建议

首先我们来看下什么是搜索建议。在Android应用中,当用户输入搜索字符串是,系统会根据输入的字符串的部分或整体,以下拉框的方式列出含有用户输入字符串的列表,这样用户就可以不必输入完所有字符,可以直接从下拉列表中选择,方便了用户。如果能在APP应用的搜索模块中加入这个功能,对用户来说无疑是十分方便的,下图是在搜索应用中使用搜索建议的图:

搜索建议的两类模式

要让搜索应用支持搜索建议,必须在应用中增加一个自定义的content provider,并且要设置配置文件中的搜索元数据。

Android支持两种类型的搜索建议模式:

· 基于用户输入的搜索建议

· 基于APP应用本身数据库的搜索建议,即从APP应用数据库中提取数据做搜索建议

下面分别讲解两种搜索建议方式是如何配置的:

基于用户输入的搜索建议

这种方式相对比较容易,先来介绍下。在Android中,提供了SearchRecentSuggestionsProvider这个类,可以实现从用户最近输入的内容中进行检索,开发者只需要做的,只需要继承这个类,并且在构造函数中进行如下设置:

  1. import android.content.SearchRecentSuggestionsProvider; 
  2. publicclass SampleRecentSuggestionsProvider 
  3. extends SearchRecentSuggestionsProvider { 
  4. public static final String AUTHORITY = 
  5. SampleRecentSuggestionsProvider.class.getName(); 
  6. public static final int MODE =DATABASE_MODE_QUERIES; 
  7. public SampleRecentSuggestionsProvider() { 
  8. setupSuggestions(AUTHORITY, MODE); 

在上面的这个类中,继承了SearchRecentSuggestionsProvider,并且在构造函数中进行了设置,这样这个自定义的contentprovider就拥有了查询用户最近输入检索的能力了。

但必须同时保存用户曾经的检索输入,这样就能在用户再次输入时,重新显示出来,这个必须在search的activity中,写入如下代码:

  1. SearchRecentSuggestions suggestions = 
  2. newSearchRecentSuggestions(this
  3. SampleRecentSuggestionsProvider.AUTHORITY, 
  4. SampleRecentSuggestionsProvider.MODE); 
  5. suggestions.saveRecentQuery(query, null); 

上面的代码中可以看到,使用了SearchRecentSuggestionsProvider的

saveRecentQuery方法进行了搜索记录的保存。

接下来,在配置文件中必须对这个contentprovider进行配置,如下:

  1. <provider 
  2. android:authorities="de.openminds.SampleRecentSuggestionsProvider" 
  3. android:name=".SampleRecentSuggestionsProvider"> 
  4. </provider> 

***,在searchable.xml中进行配置即可使用,如下:

  1. <? xml version="1.0"encoding="utf-8"?> 
  2. <searchablexmlns:androidsearchablexmlns:android="http://schemas.android.com/apk/res/android" 
  3. android:label="@string/search_label" 
  4. android:hint="@string/search_hint" 
  5. android:searchSettingsDescription="@string/search_settings_description" 
  6. android:searchSuggestAuthority="com.grokkingandroid.SampleRecentSuggestionsProvider " 
  7. android:searchSuggestIntentAction="android.intent.action.SEARCH" 
  8. android:searchSuggestThreshold="1" 
  9. android:includeInGlobalSearch="true" 
  10. android:searchSuggestSelection=" ?" 
  11. > 
  12. </searchable> 

其中的一些参数说明如下:

android:searchSuggestAuthorith

此属性的值就是SearchSuggestAuthorith中的AUTHORITH了。

android:searchSuggestIntentAction

此属性定义了当我们选中搜索提示的内容时发生的目的动作。

android:searchSuggestThreshold

此属性定义了至少输入几个字符时才会弹出提示

android:includeInGlobalSearch

是否将内容加入android的全局搜索。true,加入。

android:searchSuggestSelection

定义搜索时参数的占位符

Android中数据库保存的搜索记录

SearchRecentSuggestionsProvider将用户最近的搜索记录保存在suggestions.db中,这个db保存了id,query查询项,一个显示的文本和搜索时候的时间戳。注意的是这个时间戳是必须的,因为所有的搜索记录都是按时间排序的。

作为开发者来说,应该考虑定期清理搜索记录,或者提供给用户手动清除搜索记录的机会,以让用户定期从搜索建议列表中看到更多的搜索建议项。清除搜索建议记录是十分容易的,只需要调用SearchRecentSuggestions对象的clearHistory()方法即可。Android会默认保留250个搜索建议项在系统中。

基于应用的搜索建议

在更多情况下,开发者希望是提供给用户基于app应用本身的搜索功能,这样用户在搜索时,将基于APP应用本身的内容提供给用户搜索建议。这个时候,在自定义provider中,只需要关注query()和getContentType()就可以了。

首先,在应用中必须获得用户在搜索文本框中输入的内容,然后再调用query()方法去搜索app应用。这个可以通过如下两类方法去获得用户的输入内容

· 默认的是通过URI的方式获得用户的输入内容

· 在配置文件中的查询字符串

先看下如何过URI的方式获得用户的输入内容。系统都会通过query()函数在Content Provider中进行查询,然后用Cursor返回对应的suggestion。系统对用户的输入,构造成如下的URI:

content://authority/optionalPath/SUGGEST_URI_PATH_QUERY /queryText

注意这里的Uri末尾的querytext是用URL方式进行编码的,所以你需要解码。

一般都是采用如下的方式取得它:Stringquery = uri.getLastPathSegment().toLowerCase();

这里的optional.suggest.path就是在searchable配置文件中设置的android:searchSuggestPath,如果在searchable配置文件没有设置它,optional.suggest.path当然也不会包括在uri中。只有需要一个ContentProvider为多个searchable activities提供suggestions查询的时候,才需要设置android:searchSuggestPath,这时它用于区分是哪个searchableactivities。

注意:SUGGEST_URI_PATH_QUERY 并不是URI的字面字符串,它是一个静态成员常量,表示是把该常量的值加到uri中

下面是相关的使用方法代码:

  1. public Cursor query(Uri uri, String[] projection, String selection, 
  2. String[] selectionArgs, String sortOrder){ 
  3. String query = uri.getLastPathSegment(); 
  4. if (SearchManager.SUGGEST_URI_PATH_QUERY.equals(query)) { 
  5. //如果找到符合用户输入的记录 
  6. else { 
  7. //如果找不到符合用户输入的记录 

接着看下如何在配置文件中进行查询字符串的设置。可以在配置文件中进行如下配置,增加android:searchSuggestSelection选项,如下:

android:searchSuggestSelection="namelike ?"

那么query()方法代码如下:

  1. public Cursor query(Uri uri, String[]projection, String selection, 
  2. String[]selectionArgs, String sortOrder) { 
  3. if (selectionArgs!= null && selectionArgs.length > 0 &&selectionArgs[0].length() > 0) { 
  4. // 用户输入内容保存在 selectionArgs[0] 中 
  5. else { 
  6. // 用户没输入任何内容 

此外,还可以在配置文件中配置搜索建议的最短字符数,比如android:searchSuggestThreshold="3",则表明,用户至少输入3个字符后,才开始调用搜索建议项。

处理返回的结果

下面讲解如何处理搜索建议返回给前端界面的问题。首先要在配置文件中,配置使用哪个action并且使用哪一个URI(这个URI其实就是搜索建议项的***数据来源列表),配置如下:

  android:searchSuggestIntentAction =

"android.intent.action.VIEW"

android:searchSuggestIntentData =

"content://someAuthority/somePath"

对返回的搜索建议项,是以一个cursor的方式返回的,各个列必须严格遵守相关的规定,下面是几个重要的列的列表:

常量

用法

SUGGEST_COLUMN_TEXT_1

要在***行显示的文本

SUGGEST_COLUMN_TEXT_2

在第二行显示的文字

SUGGEST_COLUMN_INTENT_DATA_ID

添加到data_uri的额外的id

虽然说只有Searchmanager.SUGGEST_COLUMN_TEXT_1是强制要求的,但由于要知道用户选择的是哪一个选项,因此一般来说,id选项也是需要的。

此外,还需要将查询出来的搜索数据转换为cursor的数据格式,这个需要进行一点转换工作。这可以使用SQLITEQueryBuilder的setprojectionMap方法进行转换,在下一篇教程中,将会具体讲解其用法,这里先列出相关代码如下:

  1. Map<String, String> projectionMap = newHashMap<String, String>(); 
  2.  
  3. projectionMap.put(COL_BAND, COL_BAND +" AS " + SearchManager.SUGGEST_COLUMN_TEXT_1); 
  4.  
  5. projectionMap.put(COL_ID, COL_ID); 
  6.  
  7. projectionMap.put(COL_ROW_ID,COL_ROW_ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID); 
  8.  
  9. projectionMap.put(COL_LOCATION,COL_LOCATION + " AS " + SearchManager.SUGGEST_COLUMN_TEXT_2); 
  10.  
  11. projectionMap.put(COL_DATE, COL_DATE); 
  12.  
  13. builder.setProjectionMap(projectionMap); 

响应用户搜索的intent

当用户输入搜索词后,Android的搜索框架将调用manifest文件中配置的搜索的activity,这其中会使用显式的intent去实现。就在app中搜索用的搜索建议而言,这个intent会包括在配置文件中的数据和从cursor中返回的数据。

对用户搜索的响应的具体处理,取决于使用的是基于用户已经输入过的搜索词的搜索建议,还是基于APP应用本身数据提供的搜索建议。

如果使用了基于用户已经输入过的搜索词的搜索建议,那么intent的action就是Intent.ACTION_SEARCH ,这和上一篇教程中谈到的是一样的。

对于基于APP应用本身数据提供的搜索建议的情况,用户大多数情况下,希望看到的是数据的详细的情况,所以点了提供的搜索建议后,期望跳转看到数据的详情,这个可以通过设置Intent.ACTION_VIEW来实现。

由于搜索的activity一般会继承ListActivity,所以一般情况下需要另外打开一个activity去查看某项数据的具体内容,代码如下:

  1. private void handleIntent(Intentintent) { 
  2.  
  3. if(Intent.ACTION_SEARCH.equals(intent.getAction())) { 
  4.  
  5. String query =intent.getStringExtra(SearchManager.QUERY); 
  6.  
  7. doSearch(query); 
  8.  
  9. else if(Intent.ACTION_VIEW.equals(intent.getAction())) { 
  10.  
  11. Uri detailUri =intent.getData(); 
  12.  
  13. String id = detailUri.getLastPathSegment(); 
  14.  
  15. Intent detailsIntent =new Intent(getApplicationContext(), DetailsActivity.class); 
  16.  
  17. detailsIntent.putExtra("ID", id); 
  18.  
  19. startActivity(detailsIntent); 
  20.  
  21. finish(); 
  22.  
  23.  

全局搜索

对于全局搜索的设置,只需要在配置文件中进行如下设置:

android:includeInGlobalSearch="true"

但问题是如何将你的APP应用能放置到Android本身的搜索列表中去呢?如下图:

List of globally searchable items

你的APP应用本身不能改变这些值,但Android提供了

android.app.SearchManager.INTENT_ACTION_GLOBAL_SEARCH

的方法,可以将你的APP应用添加到搜索列表中去,这样的话,在搜索列表中,可以象如下图的样子进行搜索:

Global search suggestions showing results of the sample app

关于搜索建议***的问题

要注意的是关于搜索建议***的问题,在于开发者很难在样式上进行控制,这将会是一个很大的问题。特别对于APP中如果搜索建议展示的样式跟APP中其他的样式很不同的话,将会影响用户体验。

另外,如果要在搜索建议中展示不同的数据 ,有的时候也会变得麻烦。比如在一个关于音乐会的app应用中,可能会出现位置和乐团或乐队的相关信息,开发者企图将它们在搜索建议中明确划分开来,以方便用户选择,但可惜除非开发者进行自定义开发,否则无法实现这样的功能。

小结

在本篇教程中,重点讲解了如何在APP应用中加入搜索建议的两种方法和注意点,在下一篇教程中,将讲解如何使用搜索的快捷方式,敬请期待。

【51CTO译稿,非经授权谢绝转载,合作媒体转载请注明原文出处、作者及51CTO译者!】

责任编辑:佚名 来源: 51CTO.com
相关推荐

2012-07-30 09:41:04

Android搜索功能

2011-09-14 16:40:12

Android SDK

2009-03-23 10:04:46

Java Web入侵检Java Web应用EasyJWeb

2023-08-16 19:00:53

谷歌人工智能搜索

2013-07-10 09:18:13

微软Office 365

2011-06-02 11:37:34

Android 检索

2012-03-05 10:41:00

思科防火墙

2020-03-10 09:16:42

勒索软件攻击赎金

2009-03-13 08:37:35

GoogleAndroidiPhone

2013-12-08 21:33:31

谷歌移动搜索应用内搜索

2014-12-31 17:12:54

模糊查询模糊查询

2011-08-30 09:18:39

EnterpriseD云计算迁移

2012-10-29 12:49:49

2011-02-15 09:39:37

Ubuntu OneUbuntu 11.0

2009-12-24 10:46:08

WPF MediaEl

2013-10-21 10:35:21

Map值Map保存搜索键

2023-09-01 17:21:21

PyCharmLinuxWayland

2022-10-09 09:18:01

ColadaPinia

2009-03-03 11:31:21

Twintter集成搜索

2021-01-01 10:00:04

Windows 10Windows操作系统
点赞
收藏

51CTO技术栈公众号