参考《Professional Android 4 Development》

搜索

通过下面这几种方式可以给应用程序添加搜索功能:

  • Search Bar

  • Search View

  • Quick Search Box

可搜索的Content Provider

首先,要在res./xml目录下创建一个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=”@string/search_hint”>
</searchable>

其中,Label一般是应用程序的名称。

为应用程序创建Search Activity

Search Activity和普通的Activity不同,它是一直在back stack的栈顶,每次有新的search activity创建时,不会有将其简单的入栈,因为用户是不会希望按返回键时返回自己前面的查询结果。为了表明该Activity可以被搜索,需要将android.intent.action.SEARCH加入到自己的Intent Filter中,同时需要将前面创建的searchable的xml文件加到meta-data标签中:

<activity android:name=”.DatabaseSkeletonSearchActivity” android:label=”Element Search” android:launchMode=”singleTop”>
  <intent-filter>
    <action android:name=”android.intent.action.SEARCH” />
    <category android:name=”android.intent.category.DEFAULT” />
  </intent-filter>
  <meta-data android:name=”android.app.searchable” android:resource=”@xml/searchable” />
</activity>

用户进行搜索后,可以在搜索结果中继续搜索,而这种操作会生成新的Intent,而这些Intent可以通过onNewIntent handler来处理:

@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  // Get the launch Intent
  parseIntent(getIntent());
}
@Override
protected void onNewIntent(Intent intent) {
  super.onNewIntent(intent);
  parseIntent(getIntent());
}
private void parseIntent(Intent intent) {
  // If the Activity was started to service a Search request, extract the search query.
  if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
    String searchQuery = intent.getStringExtra(SearchManager.QUERY);
    // Perform the search
    performSearch(searchQuery);
  }
}

设置默认的Serach Provider

在应用程序中,最好设置一个Activity,让所有的搜索结果都从这个Activity中出来,设置方法也简单,将下面的配置加到程序配置中就可以了:

<meta-data android:name=”android.app.default_searchable” android:value=”.DatabaseSkeletonSearchActivity” />

使用Cursor Loader的Search Activity示例

import android.app.ListActivity;
import android.app.LoaderManager;
import android.app.SearchManager;
import android.content.ContentUris;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
public class DatabaseSkeletonSearchActivity extends ListActivity implements LoaderManager.LoaderCallbacks<Cursor> {
  private static String QUERY_EXTRA_KEY = “QUERY_EXTRA_KEY”;
  private SimpleCursorAdapter adapter;
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Create a new adapter and bind it to the List View
    adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, null, new String[] { MyContentProvider.KEY_COLUMN_1_NAME }, new int[] { android.R.id.text1 }, 0);
    setListAdapter(adapter);
    // Initiate the Cursor Loader
    getLoaderManager().initLoader(0, null, this);
    // Get the launch Intent
    parseIntent(getIntent());
  }
  @Override
  protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    parseIntent(getIntent());
  }
  private void parseIntent(Intent intent) {
    // If the Activity was started to service a Search request, extract the search query.
    if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
      String searchQuery = intent.getStringExtra(SearchManager.QUERY);
      // Perform the search
      performSearch(searchQuery);
    }
  }
  // Execute the search.
  private void performSearch(String query) {
    // Pass the search query as an argument to the Cursor Loader
    Bundle args = new Bundle();
    args.putString(QUERY_EXTRA_KEY, query);
    // Restart the Cursor Loader to execute the new query.
    getLoaderManager().restartLoader(0, args, this);
  }
  public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    String query = “0”;
    // Extract the search query from the arguments.
    if (args != null)
      query = args.getString(QUERY_EXTRA_KEY);
    // Construct the new query in the form of a Cursor Loader.
    String[] projection = {MyContentProvider.KEY_ID, MyContentProvider.KEY_COLUMN_1_NAME};
    String where = MyContentProvider.KEY_COLUMN_1_NAME + “ LIKE \”%” + query + “%\””;
    String[] whereArgs = null;
    String sortOrder = MyContentProvider.KEY_COLUMN_1_NAME + “ COLLATE LOCALIZED ASC”;
    // Create the new Cursor loader.
    return new CursorLoader(this, MyContentProvider.CONTENT_URI, projection, where, whereArgs, sortOrder);
  }
  public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
    // Replace the result Cursor displayed by the Cursor Adapter with the new result set.
    adapter.swapCursor(cursor);
  }
  public void onLoaderReset(Loader<Cursor> loader) {
    // Remove the existing result Cursor from the List Adapter.
    adapter.swapCursor(null);
  }
}

大部分情况下,我们需要响应对搜索结果的click事件,因此需要重写onListItemClick方法:

@Override
protected void onListItemClick(ListView listView, View view, int position, long id) {
  super.onListItemClick(listView, view, position, id);
  // Create a URI to the selected item.
  Uri selectedUri = ContentUris.withAppendedId(MyContentProvider.CONTENT_URI, id);
  // Create an Intent to view the selected item.
  Intent intent = new Intent(Intent.ACTION_VIEW);
  intent.setData(selectedUri);
  // Start an Activity to view the selected item.
  startActivity(intent);
}

使用Search View Widget

Android 3.0后推出了Search View Widget以替代Search Activity。将Search View绑定到searchable activity中,首先要获取searchableInfo:

// Use the Search Manager to find the SearchableInfo related  to this Activity.
SearchManager searchManager = (SearchManager)getSystemService(Context.SEARCH_SERVICE);
SearchableInfo searchableInfo = searchManager.getSearchableInfo(getComponentName());
// Bind the Activity’s SearchableInfo to the Search View
SearchView searchView = (SearchView)findViewById(R.id.searchView);
searchView.setSearchableInfo(searchableInfo);

本地Android Content Provider

Android中提供了一些本地的Content Provider,包括下面这些:

  • Media Store
  • Browser
  • Contacts Contract
  • Calendar
  • Call Log

使用Media Store Content Provider

MediaStore类有Audio,Video和Image子类,这些子类又有含有uri信息的子类。每个子类中uri信息是这么存储的:

  • MediaStore.<mediatype>.Media.EXTERNAL_CONTENT_URI
  • MediaStore.<mediatype>.Media.INTERNAL_CONTENT_URI

下面是一个示例:

// Get a Cursor over every piece of audio on the external volume,
// extracting the song title and album name.
String[] projection = new String[] {
  MediaStore.Audio.AudioColumns.ALBUM,
  MediaStore.Audio.AudioColumns.TITLE
};
Uri contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
Cursor cursor = getContentResolver().query(contentUri, projection, null, null, null);
// Get the index of the columns we need.
int albumIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.AudioColumns.ALBUM);
int titleIdx = cursor.getColumnIndexOrThrow(MediaStore.Audio.AudioColumns.TITLE);
// Create an array to store the result set.
String[] result = new String[cursor.getCount()];
// Iterate over the Cursor, extracting each album name and song title.
while (cursor.moveToNext()) {
  // Extract the song title.
  String title = cursor.getString(titleIdx);
  // Extract the album name.
  String album = cursor.getString(albumIdx);
  result[cursor.getPosition()] = title + “ (“ + album + “)”;
}
// Close the Cursor.
cursor.close();

使用Contacts Contract Content Provider

Contacts Contract Provider使用三层模型存储数据:

Android 4 学习(18):搜索的更多相关文章

  1. Android Animation学习(二) ApiDemos解析:基本Animatiors使用

    Animator类提供了创建动画的基本结构,但是一般使用的是它的子类: ValueAnimator.ObjectAnimator.AnimatorSet ApiDemos中Animation部分是单独 ...

  2. Android:学习AIDL,这一篇文章就够了(下)

    前言 上一篇博文介绍了关于AIDL是什么,为什么我们需要AIDL,AIDL的语法以及如何使用AIDL等方面的知识,这一篇博文将顺着上一篇的思路往下走,接着介绍关于AIDL的一些更加深入的知识.强烈建议 ...

  3. Android WiFiDirect 学习(二)——Service Discovery

    Service Discovery 简介 在Android WifiDirect学习(一 )中,简单介绍了如何使用WifiDirect进行搜索——连接——传输. 这样会有一个问题,那就是你会搜索到到附 ...

  4. Android 数字签名学习笔记

    Android 数字签名学习笔记 在Android系统中,所有安装到系统的应用程序都必有一个数字证书,此数字证书用于标识应用程序的作者和在应用程序之间建立信任关系,如果一个permission的pro ...

  5. Android 布局学习之——Layout(布局)具体解释二(常见布局和布局參数)

     [Android布局学习系列]   1.Android 布局学习之--Layout(布局)具体解释一   2.Android 布局学习之--Layout(布局)具体解释二(常见布局和布局參数)   ...

  6. 我的Android 4 学习系列之数据库和Content Provider

    目录 创建数据库和使用SQLite 使用Content Provider.Cusor和Content Value来存储.共享和使用应用程序数据 使用Cursor Loader异步查询Content P ...

  7. 我的Android 4 学习系列之文件、保存状态和首选项

    目录 使用Shared Preference 保留简单的应用程序数据 保存回话间的Activity实例数据 管理应用程序首选项和创建Preference Screen 保存并加载文件以及管理本地文件系 ...

  8. Android 自定义支持快速搜索筛选的选择控件(一)

    Android 自定义支持快速搜索筛选的选择控件 项目中遇到选择控件选项过多,需要快速查找匹配的情况. 做了简单的Demo,效果图如下: 源码地址:https://github.com/whieenz ...

  9. Android JNI学习(四)——JNI的常用方法的中文API

    本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...

随机推荐

  1. object references an unsaved transient instance【异常】

    [异常提示] TransientObjectException: object references an unsaved transient instance -save the transient ...

  2. bzoj 4595 激光发生器

    bzoj 4595 激光发生器 光线为射线,每次找到与当前光线相交且距离最近的镜子,然后旋转光线. 直线,射线利用线上一点+方向向量的方式表示.旋转时,旋转中心作为线上一点不变,方向向量左乘旋转矩阵. ...

  3. 重温CLR(十五) 托管堆和垃圾回收

    本章要讨论托管应用程序如何构造新对象,托管堆如何控制这些对象的生存期,以及如何回收这些对象的内存.简单地说,本章要解释clr中的垃圾回收期是如何工作的,还要解释相关的性能问题.另外,本章讨论了如何设计 ...

  4. BW建模开发入门

    本文档主要指导具体操作步骤,一些技术名称和描述可能在各步骤中不对应,可以忽略 一.模型建立 1.建立信息区和信息对象目录 1)进入BW工作台 2)创建信息区 输入技术名称和描述 3)创建特性和关键值的 ...

  5. vue-router教程二(要素篇之新手入门)

    注意,我们将在指南中使用es 2015代码样本.此外,所有示例都将使用VUE的完整版本来使在线模板编译成为可能.请参阅这里的更多细节. 用vue路由器创建单页应用程序是非常简单的.使用vue.js,我 ...

  6. Wordpress网站添加七牛云cdn

    1.一个搭建好的网站和七牛云账号 2.七牛云进入控制面板 3创建存储空间 4创建好了空间拿七牛给你了测试域名(但只可以使用30天)所以绑定自定义域名(这个必须是备案过的) 5.设置自定义域名(加速域名 ...

  7. 什么是YARN

    YARN的核心组件: 1)ResourceManager,扮演Master角色(和HDFS的nameNode很像)主要用于资源分配:RM有两个子组件,分别是Scheduler(Capacity Sch ...

  8. Python控制台输出不换行(进度条等)

    sys.stdout.write('\r'+str) sys.stdout.flush() time.sleep(1)

  9. docker怎么破?

    为什么要装docker? 因为linux服务器不好用,很多操作不好进行,比如安装包没有管理员权限 docker可以访问本地显卡,比一般的virtual box 或者VMware都要好 怎么装docke ...

  10. 推荐PHP程序员进阶的好书

    <UNIX网络编程卷1(第3版)> <UNIX网络编程卷2(第2版)> <UNIX环境高级编程(第3版)> <UNIX编程艺术> <MySQL技术 ...