Content Providers是Android平台中重要的组件之一,它提供了一套标准的接口用来实现数据的增删改查,可以使各个应用程序之间实现数据共享。一方面,我们可以获得系统内部的如音频、视频、图像和联系人等Content Providers,还可以定义自己开发应用程序的CP,提供其他应用程序访问自身数据的接口。

1. 对Content Providers的操作

Content Providers把它的数据作为数据库模型上的单一数据表提供出来,在数据表中,每一行是一条记录,每一列代表某一特定类型的值。下表是联系人信息的数据模型。

 
_ID NUMBER NUMBER_KEY LABEL NAME TYPE
13 (425) 555 6677 425 555 6677 Kirkland office Bully Pulpit TYPE_WORK
44 (212) 555-1234 212 555 1234 NY apartment Alan Vain TYPE_HOME
45 (212) 555-6657 212 555 6657 Downtown office Alan Vain TYPE_MOBILE
53 201.555.4433 201 555 4433 Love Nest Rex Cars TYPE_HOME

    每一个Content Providers都会会对外提供一个URI作为其唯一标识,在与其他程序互动的过程中都会使用到这个常量。URI有三部分组成:

    "content://"

    数据的路径

    ID(可选) 一个ID代表一条记录,ID为空代表表中的全部数据。

    在进行对Content Providers的操作中,使用到一个唯一的ContentResolver接口来使用某个具体的Content Provisers对象。其初始化代码如下:

ContentResolver cr=getContentResolver();

    ContentResolver中定义了对Content Providers中数据操作的方法。主要包括如下几个:

    a. 查询数据

    方法一:使用的ContentResolver.query()方法。在SDK文档中,有如下说明: 

public final Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)

Since: API Level 1

 

Query the given URI, returning a Cursor over the result set.

For best performance, the caller should follow these guidelines:

  • Provide an explicit projection, to prevent reading data from storage that aren't going to be used.

  • Use question mark parameter markers such as 'phone=?' instead of explicit values in the selection parameter, so that queries that differ only by those values will be recognized as the same for caching purposes.

 Parameters

uri

The URI, using the content:// scheme, for the content to retrieve.

projection

A list of which columns to return. Passing null will return all columns, which is inefficient.

selection

A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing null will return all rows for the given URI.

selectionArgs

You may include ?s in selection, which will be replaced by the values from selectionArgs, in the order that they appear in the selection. The values will be bound as Strings.

sortOrder

How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use the default sort order, which may be unordered.

Returns

  • A Cursor object, which is positioned before the first entry, or null

    方法二:使用Activity.managedQuery()方法。需要注意的是它包含了Activity的生命周期,当Activity被暂停后,如果需要重新使用方法返回的Cursor对象,就需要通过Activity.startManagingCursor()方法重新启动。在SDK文档中的说明如下:

public final Cursor managedQuery (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)

Since: API Level 1

Wrapper around query(android.net.Uri, String[], String, String[], String) that gives the resulting Cursor to call startManagingCursor(Cursor) so that the activity will manage its lifecycle for you.

Parameters

uri

The URI of the content provider to query.

projection

List of columns to return.

selection

SQL WHERE clause.

selectionArgs

The arguments to selection, if any ?s are pesent

sortOrder

SQL ORDER BY clause.

Returns

  • The Cursor that was returned by query(). 

    b. 添加和修改数据

    ContentResolver中定义了增加和修改数据的方法,使用起来非常方便,与数据库的操作类似。代码如下:

 
 

       
       
       
       
  1. //1. 增加数据  
  2. //获得ContentValues对象,并构造其中的数据  
  3. ContentValues values = new ContentValues();  
  4. values.put(NotePad.Notes.TITLE, "title1");  
  5. values.put(NotePad.Notes.NOTE, "NOTENOTE1");  
  6. //将数据添加到URI为NotePad.Notes.CONTENT_URI的数据模型中  
  7. getContentResolver().insert(NotePad.Notes.CONTENT_URI, values);  
  8.  
  9. //2. 修改数据  
  10. //获得ContentValues对象,并构造其中的数据  
  11. ContentValues values = new ContentValues();  
  12. values.put(NotePad.Notes.TITLE, "title1");  
  13. values.put(NotePad.Notes.NOTE, "NOTENOTE1");
  14. //定义加入了需要被修改记录ID的URI 
  15. URI uri=contentUris.withAppendedID(NotePad.Notes.CONTENT_URI,id);  
  16. //修改URI为NotePad.Notes.CONTENT_URI的数据模型中ID为id的记录,将其值修改为ContentValue中的值  
  17. getContentResolver().insert(uri, values);  
  18.      

2. 自定义Content Provisers

    可以通过定义一个继承于ContentProvider的类自定义自己开发应用程序的CP。通过重写基类中的方法,可以提供给外部操作的接口。至于在方法内部如何组织和存储数据,则由开发者自定。例如,既可以使用数据库存储,也可使用XML。不管采用哪种机制,外部用户关注的仅仅是可操作的接口。

    在实际的开发中,大多数情况使用的是系统内的CP。由于很少情况自定义CP,而且模式相对较为固定,所以我们在使用时可以参照现有资料或API DEMO即可。