【翻译】(9-补丁0-2)创建一个内容提供者

 

see

http://developer.android.com/guide/topics/providers/content-provider-creating.html

 

原文见

http://developer.android.com/guide/topics/providers/content-provider-creating.html

 

-------------------------------

 

Creating a Content Provider

 

创建一个内容提供者

 

-------------------------------

 

In this document

 

本文目录

 

* Designing Data Storage 设计数据存储

* Designing Content URIs 设计内容URI

* Implementing the ContentProvider Class 实现ContentProvider类

* Required Methods 必需的方法

* Implementing the query() method 实现query()方法

* Implementing the insert() method 实现insert()方法

* Implementing the delete() method 实现delete()方法

* Implementing the update() method 实现update()方法

* Implementing the onCreate() method 实现onCreate()方法

* Implementing Content Provider MIME Types 实现内容提供者的MIME类型

* MIME types for tables 表的MIME类型

* MIME types for files 文件的MIME类型

* Implementing a Contract Class 实现一个契约类

* Implementing Content Provider Permissions 实现内容提供者权限

* The <provider> Element <provider>元素

* Intents and Data Access 意图和数据访问

 

Key classes

 

关键类

 

ContentProvider

Cursor

Uri

 

Related Samples

 

相关示例

 

Note Pad sample application 记事本示例应用程序

 

See also

 

另见

 

Content Provider Basics 内容提供者基础

Calendar Provider 日历提供者

 

-------------------------------

 

A content provider manages access to a central repository of data. You implement a provider as one or more classes in an Android application, along with elements in the manifest file. One of your classes implements a subclass ContentProvider, which is the interface between your provider and other applications. Although content providers are meant to make data available to other applications, you may of course have activities in your application that allow the user to query and modify the data managed by your provider.

 

一个内容提供者管理对数据的中央仓库的访问。你实现一个提供者作为一个Android应用程序中的一个或多个类,伴随清单文件中的元素。你的类之一实现一个子类ContentProvider,它是你的提供者和其它应用程序之间的接口。尽管内容提供者必定让数据对于其它应用程序可用,当然你可能在你的应用程序中有活动允许用户查询和修改你的提供者管理的数据。

 

The rest of this topic is a basic list of steps for building a content provider and a list of APIs to use.

 

这个主题的其余部分是构建一个内容提供者的步骤的一个基本列表以及要使用的API的列表。

 

-------------------------------

 

Before You Start Building

 

在你开始构建之前

 

Before you start building a provider, do the following:

 

在你开始构建一个提供者之前,做以下事情:

 

1. Decide if you need a content provider. You need to build a content provider if you want to provide one or more of the following features:

 

1. 决定你是否需要一个内容提供者。你需要构建一个内容提供者,如果你希望提供以下特性的一个或多个:

 

* You want to offer complex data or files to other applications.

 

* 你希望提供复杂的数据或文件给其它应用程序。

 

* You want to allow users to copy complex data from your app into other apps.

 

* 你希望允许用户从你的应用中复制复杂数据进其它应用。

 

* You want to provide custom search suggestions using the search framework.

 

* 你希望使用搜索框架提供自定义的搜索建议。

 

You don't need a provider to use an SQLite database if the use is entirely within your own application.

 

你不需要一个提供者使用一个SQLite数据库,如果完全是在你自己的应用程序中使用。

 

2. If you haven't done so already, read the topic Content Provider Basics to learn more about providers.

 

2. 如果你不还没有这样做,请阅读主题内容提供者基础以获知关于提供者的更多信息。

 

Next, follow these steps to build your provider:

 

接下来,遵循这些步骤来构建你的提供者:

 

1. Design the raw storage for your data. A content provider offers data in two ways:

 

1. 为你的数据设计原始存储。一个内容提供者以两种方式提供数据:

 

File data

 

文件数据

 

Data that normally goes into files, such as photos, audio, or videos. Store the files in your application's private space. In response to a request for a file from another application, your provider can offer a handle to the file.

 

通常跑进文件中的数据,诸如照片,音频,或视频。在你的应用程序的私有空间中存储文件。作为来自另一个应用程序对一个文件的请求的响应,你的提供者可以提供一个指向文件的句柄。

 

"Structured" data

 

“被结构化的”数据

 

Data that normally goes into a database, array, or similar structure. Store the data in a form that's compatible with tables of rows and columns. A row represents an entity, such as a person or an item in inventory. A column represents some data for the entity, such a person's name or an item's price. A common way to store this type of data is in an SQLite database, but you can use any type of persistent storage. To learn more about the storage types available in the Android system, see the section Designing Data Storage.

 

通常跑进一个数据库,数组,或一个类似结构的数据。把数据存储为兼容具有多个行和列的表形式。一行代表一个实体,诸如一个人或存货中的一个条目。一列代表对应该实体的一些数据,诸如一个人的名称或一个条目的价格。一种存储此类数据的公共方式是使用一个SQLite数据库,但你可以使用任意类型的持久化存储。要想知道关于在Android系统中可用的存储类型的更多信息,请参见章节设计数据存储

 

2. Define a concrete implementation of the ContentProvider class and its required methods. This class is the interface between your data and the rest of the Android system. For more information about this class, see the section Implementing the ContentProvider Class.

 

2. 定义一个ContentProvider类的具体实现和它必需的方法。这个类是你的数据和Android系统的其它部分之间的接口。想获取关于此类的更多信息,参见章节实现ContentProvider类。

 

3. Define the provider's authority string, its content URIs, and column names. If you want the provider's application to handle intents, also define intent actions, extras data, and flags. Also define the permissions that you will require for applications that want to access your data. You should consider defining all of these values as constants in a separate contract class; later, you can expose this class to other developers. For more information about content URIs, see the section Designing Content URIs. For more information about intents, see the section Intents and Data Access.

 

3. 定义提供者的权力字符串,它的内容URI,以及列名。如果你希望提供者的应用程序处理意图,那么还要定义意图动作,额外数据,以及标志。还要定义为了希望访问你的数据的应用程序你将必需的权限。你应该考虑在一个分离的契约类来定义所有这些值作为常量;稍后,你可以暴露这个类给其它开发者。想获取关于内容URI的更多信息,参见章节设计内容URI。想获取关于意图的更多信息,参见章节意图和数据访问。

 

4. Add other optional pieces, such as sample data or an implementation of AbstractThreadedSyncAdapter that can synchronize data between the provider and cloud-based data.

 

4. 添加其它可选块。诸如示例代码或一个可以在提供者和基于云存储数据之间同步数据的AbstractThreadedSyncAdapter的一个实现。

 

-------------------------------

 

Designing Data Storage

 

设计数据存储

 

A content provider is the interface to data saved in a structured format. Before you create the interface, you must decide how to store the data. You can store the data in any form you like, and then design the interface to read and write the data as necessary.

 

一个内容提供者是对保存为一种结构化格式的数据的接口。在你创建该接口前,你必须决定如何存储该数据。你可以用你喜欢的形式存储该数据,然后在必要时设计接口来读写该数据。

 

These are some of the data storage technologies that are available in Android:

 

在Android中有一些数据存储技术是可用的:

 

* The Android system includes an SQLite database API that Android's own providers use to store table-oriented data. The SQLiteOpenHelper class helps you create databases, and the SQLiteDatabase class is the base class for accessing databases.

 

* Android系统包含一个SQLite数据库API,Android自己的提供者使用它来存储面向表的数据。SQLiteOpenHelper类帮助你创建数据库,而SQLiteDatabase类是用于访问数据库的基类。

 

Remember that you don't have to use a database to implement your repository. A provider appears externally as a set of tables, similar to a relational database, but this is not a requirement for the provider's internal implementation.

 

记住你不必使用一个数据库来实现你的仓库。一个提供者表面上显得如同一组表,类似于一个关系型数据,但这不是提供者内部实现的必需品。

 

* For storing file data, Android has a variety of file-oriented APIs. To learn more about file storage, read the topic Data Storage. If you're designing a provider that offers media-related data such as music or videos, you can have a provider that combines table data and files.

 

* 为了存储文件数据,Android有不同的面向文件的API。要知道关于文件存储的更多信息,请阅读主题数据存储。如果你正在设计一个提供者,它提供媒体相关数据诸如音乐或视频,那么你可以拥有一个结合表数据和文件的提供者。

 

* For working with network-based data, use classes in java.net and android.net. You can also synchronize network-based data to a local data store such as a database, and then offer the data as tables or files. The Sample Sync Adapter sample application demonstrates this type of synchronization.

 

* 要想用基于网络的数据工作,请使用java.net和android.net里的类。你还可以同步基于网络的数据到本地数据存储诸如一个数据库,然后提供数据作为表和文件。示例同步适配器的示例程序演示此类同步。

 

Data design considerations

 

数据设计考虑

 

Here are some tips for designing your provider's data structure:

 

这里有用于设计你的提供者的数据结构的一些提示:

 

* Table data should always have a "primary key" column that the provider maintains as a unique numeric value for each row. You can use this value to link the row to related rows in other tables (using it as a "foreign key"). Although you can use any name for this column, using BaseColumns._ID is the best choice, because linking the results of a provider query to a ListView requires one of the retrieved columns to have the name _ID.

 

* 表数据应该总是拥有一个“主键”列,提供者维护它作为每行的一个唯一数值。你可以使用这个值来链接行到其它表中的多个相关行(使用它作为一个“外键”)。虽然你可以对这个列使用任意名称,然而使用BaseColumns._ID是最佳选择,因为链接一个提供者查询的结果到一个ListView需要取出列中的一个拥有名称_ID。

 

* If you want to provide bitmap images or other very large pieces of file-oriented data, store the data in a file and then provide it indirectly rather than storing it directly in a table. If you do this, you need to tell users of your provider that they need to use a ContentResolver file method to access the data.

 

* 如果你希望提供位图图片或其它非常大块的面向文件的数据,存储文件中的数据,然后间接地提供它而非把它直接地把它存储进一个表中。如果你这样做,你需要告诉你的提供者的用户他们需要使用一个ContentResolver的文件方法来访问数据。

 

* Use the Binary Large OBject (BLOB) data type to store data that varies in size or has a varying structure. For example, you can use a BLOB column to store a protocol buffer or JSON structure.

 

* 使用二进制大对象(BLOB)数据类型来存储大小不同的或有不同结构的数据。例如,你可以使用一个BLOB列来存储一个协议缓冲或JSON结构(注:Goolgle Protocol Buffer,即protobuf,是Google的开源数据交换格式,而JSON是JavaScript Object Notation的缩写,一种轻量级的数据交换格式)。

 

You can also use a BLOB to implement a schema-independent table. In this type of table, you define a primary key column, a MIME type column, and one or more generic columns as BLOB. The meaning of the data in the BLOB columns is indicated by the value in the MIME type column. This allows you to store different row types in the same table. The Contacts Provider's "data" table ContactsContract.Data is an example of a schema-independent table.

 

你还可以使用一个BLOB来实现一个模式独立的表。在这类表格中,你定义一个主键列,一个MIME类型列,以及一个或多个普通的列作为BLOB。在BLOB列中数据的含义是由MIME类型列中的值指示。这允许你在相同的表中存储不同的行类型。电话簿提供者的“数据”表ContactsContract.Data是一个模式独立的表的示例。

 

-------------------------------

 

Designing Content URIs

 

设计内容URI

 

A content URI is a URI that identifies data in a provider. Content URIs include the symbolic name of the entire provider (its authority) and a name that points to a table or file (a path). The optional id part points to an individual row in a table. Every data access method of ContentProvider has a content URI as an argument; this allows you to determine the table, row, or file to access.

 

一个内容URI是一个URI,它标识提供者中的数据。内容URI包括整个提供者的符号名称(它的权力)以及指向一个表或文件的名称(一个路径)。可选的id部分指向一个表中的一个单独的行。ContentProvider的每个数据访问方法有一个内容URI作为一个参数;它允许你决定要访问的表、行或文件。

 

The basics of content URIs are described in the topic Content Provider Basics.

 

在主题内容提供者基础中描述内容URI的基础。

 

Designing an authority

 

设计一个权力

 

A provider usually has a single authority, which serves as its Android-internal name. To avoid conflicts with other providers, you should use Internet domain ownership (in reverse) as the basis of your provider authority. Because this recommendation is also true for Android package names, you can define your provider authority as an extension of the name of the package containing the provider. For example, if your Android package name is com.example.<appname>, you should give your provider the authority com.example.<appname>.provider.

 

一个提供者通常有一个担当它的Android内部名称的单一权力。为了避免与其它提供者冲突,你应该使用互联网域所有权(反过来)作为你的提供者权力的基础。因为这个建议对于Android包名也是真的,所以你可以定义你的提供者权力作为一个包含提供者的包的名称的扩展。例如,如果你的Android包名是com.example.<应用名>,那么你应该给你的提供者的权力是com.example.<应用名>.provider。

 

Designing a path structure

 

设计一个路径结构

 

Developers usually create content URIs from the authority by appending paths that point to individual tables. For example, if you have two tables table1 and table2, you combine the authority from the previous example to yield the content URIs com.example.<appname>.provider/table1 and com.example.<appname>.provider/table2. Paths aren't limited to a single segment, and there doesn't have to be a table for each level of the path.

 

开发者通常从权力中通过尾加指向单独表的路径来创建内容URI。例如,如果你有两个表table1和table2,那么你组合前一个示例中的权力以产生内容URI com.example.<应用名>.provider/table1和com.example.<应用名>.provider/table2。不限制路径为一个单一的段,并且对于每个级别的路径不必有一个表。

 

Handling content URI IDs

 

处理内容URI的ID

 

By convention, providers offer access to a single row in a table by accepting a content URI with an ID value for the row at the end of the URI. Also by convention, providers match the ID value to the table's _ID column, and perform the requested access against the row that matches.

 

根据约定,提供者通过接受一个带对应该行的ID值在URI结尾的内容URI,提供对一个表中的单一行的访问权。同时根据约定,提供者匹配ID值到表的_ID列,并且对匹配的行执行请求的访问。

 

This convention facilitates a common design pattern for apps accessing a provider. The app does a query against the provider and displays the resulting Cursor in a ListView using a CursorAdapter. The definition of CursorAdapter requires one of the columns in the Cursor to be _ID

 

这个约定有助于一个让应用访问一个提供者的通用设计模式。应用对提供者执行查询并且使用一个CursorAdapter在一个ListView中显示结果Cursor。CursorAdapter的定义需要Cursor中其中一个列是_ID。

 

The user then picks one of the displayed rows from the UI in order to look at or modify the data. The app gets the corresponding row from the Cursor backing the ListView, gets the _ID value for this row, appends it to the content URI, and sends the access request to the provider. The provider can then do the query or modification against the exact row the user picked.

 

然后用户从用户界面中拾取显示行的其中一行以便查看或修改数据。应用从Cursor获取相应行返回ListView,获得这一行的_ID,尾加它到内容URI,并且发送访问请求给提供者。然后提供者可以对用户拾取的具体行执行查询或修改。

 

Content URI patterns

 

内容URI模式

 

To help you choose which action to take for an incoming content URI, the provider API includes the convenience class UriMatcher, which maps content URI "patterns" to integer values. You can use the integer values in a switch statement that chooses the desired action for the content URI or URIs that match a particular pattern.

 

为了帮助你为一个输入的内容URI选择采取哪个动作,提供者API包含便利类UriMatcher,它映射内容URI“模式”到整型值。你可以在一个switch语句中使用整型值,那个switch语句为匹配一个特殊模式的一个或多个内容URI选择期待的动作。

 

A content URI pattern matches content URIs using wildcard characters:

 

一个内容URI模式使用通配字符匹配内容URI:

 

*) *: Matches a string of any valid characters of any length.

 

*) *:匹配一个任意长度任意可用字符的字符串。

 

*) #: Matches a string of numeric characters of any length.

 

*) #:匹配一个任意长度数字字符的字符串。

 

As an example of designing and coding content URI handling, consider a provider with the authority com.example.app.provider that recognizes the following content URIs pointing to tables:

 

作为设计和编码内容URI处理的示例,考虑一个带有权力com.example.app.provider的提供者,它认识以下指向表的内容URI。

 

* content://com.example.app.provider/table1: A table called table1.

 

* content://com.example.app.provider/table1:一个被称为talbe1的表

 

* content://com.example.app.provider/table2/dataset1: A table called dataset1.

 

* content://com.example.app.provider/table2/dataset1:一个被称为dataset1的表。

 

* content://com.example.app.provider/table2/dataset2: A table called dataset2.

 

* content://com.example.app.provider/table2/dataset2:一个被称为dataset2的表。

 

* content://com.example.app.provider/table3: A table called table3.

 

* content://com.example.app.provider/table3:一个被称为table3的表。

 

The provider also recognizes these content URIs if they have a row ID appended to them, as for example content://com.example.app.provider/table3/1 for the row identified by 1 in table3.

 

提供者还认识这些内容URI,如果它们有一个行ID尾加到它们后面,例如content://com.example.app.provider/table3/1表示在table3中用1标识的行那样。

 

The following content URI patterns would be possible:

 

以下内容URI模式将是可能的:

 

content://com.example.app.provider/*

 

Matches any content URI in the provider.

 

匹配提供者内的任意内容URI。

 

content://com.example.app.provider/table2/*:

 

Matches a content URI for the tables dataset1 and dataset2, but doesn't match content URIs for table1 or table3.

 

匹配表dataset1和dataset2的内容URI,但不匹配表table1或table3的内容URI。

 

content://com.example.app.provider/table3/#: Matches a content URI for single rows in table3, such as content://com.example.app.provider/table3/6 for the row identified by 6.

 

content://com.example.app.provider/table3/#:匹配table3中单一行的内容URI,诸如content://com.example.app.provider/table3/6对应被6标识的行。

 

The following code snippet shows how the methods in UriMatcher work. This code handles URIs for an entire table differently from URIs for a single row, by using the content URI pattern content://<authority>/<path> for tables, and content://<authority>/<path>/<id> for single rows.

 

以下代码片段展示UriMatcher里的方法如何工作。这段代码处理整个表的URI而不同于单一行的URI,通过使用内容URI模式content://<权力>/<路径>用于多个表,而content://<权力>/<路径>/<id>用于单一行。

 

The method addURI() maps an authority and path to an integer value. The method android.content.UriMatcher#match(Uri) match()} returns the integer value for a URI. A switch statement chooses between querying the entire table, and querying for a single record:

 

方法addURI()映射一个权力和路径到一个整型值。方法android.content.UriMatcher#match(Uri) match()}(注:此处待考)返回对应一个URI的整型值。一个switch语句在查询整个表和查询单一记录之间选择:

 

-------------------------------

 

public class ExampleProvider extends ContentProvider {

...

    // Creates a UriMatcher object.

    // 创建一个UriMatcher对象。

    private static final UriMatcher sUriMatcher;

...

    /*

     * The calls to addURI() go here, for all of the content URI patterns that the provider

     * should recognize. For this snippet, only the calls for table 3 are shown.

     * 对addURI()的调用跑到这里,对于提供者应该认识的所有内容URI模式。

     * 对于这个代码片段,只有表3的调用被展示。

     */

...

    /*

     * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used

     * in the path

     * 为表3中多个行设置整型值为1。注意在路径中没有通配符被使用

     */

    sUriMatcher.addURI("com.example.app.provider", "table3", 1);

 

    /*

     * Sets the code for a single row to 2. In this case, the "#" wildcard is

     * used. "content://com.example.app.provider/table3/3" matches, but

     * "content://com.example.app.provider/table3 doesn't.

     * 设置单一行的代码为2。在这种情况下,使用"#"通配符

     * "content://com.example.app.provider/table3/3"匹配,

     * 但"content://com.example.app.provider/table3"(注:此处少一个引号)不匹配。

     */

    sUriMatcher.addURI("com.example.app.provider", "table3/#", 2);

...

    // Implements ContentProvider.query()

    // 实现ContentProvider.query()

    public Cursor query(

        Uri uri,

        String[] projection,

        String selection,

        String[] selectionArgs,

        String sortOrder) {

...

        /*

         * Choose the table to query and a sort order based on the code returned for the incoming

         * URI. Here, too, only the statements for table 3 are shown.

         * 选择要查询的表和一个基于对输入URI返回的代码的排序次序。

         * 还有,在这里只展示对应表3的语句。

         */

        switch (sUriMatcher.match(uri)) {

 

 

            // If the incoming URI was for all of table3

            // 如果输入URI对应table3的全部

            case 1:

 

                if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC";

                break;

 

            // If the incoming URI was for a single row

            // 如果输入URI对应单一行

            case 2:

 

                /*

                 * Because this URI was for a single row, the _ID value part is

                 * present. Get the last path segment from the URI; this is the _ID value.

                 * Then, append the value to the WHERE clause for the query

                 * 因为这个URI对应单一行,所以存在_ID值部分。

                 * 从URI中获得最后的路径段;它是_ID值。

                 * 然后,尾加值到查询的WHERE子句

                 */

                selection = selection + "_ID = " uri.getLastPathSegment();

                break;

 

            default:

            ...

                // If the URI is not recognized, you should do some error handling here.

                // 如果URI不被识别,你应该在这里做一些错误处理。

        }

        // call the code to actually do the query

        // 调用代码以实际地执行查询

    }

 

-------------------------------

 

Another class, ContentUris, provides convenience methods for working with the id part of content URIs. The classes Uri and Uri.Builder include convenience methods for parsing existing Uri objects and building new ones.

 

另一个类,ContentUris,提供便利方法以用内容URI的id部分来工作。类Uri和Uri.Builder包含便利方法用于解析现存Uri对象和构建新的对象。

 

-------------------------------

 

Implementing the ContentProvider Class

 

实现ContentProvider类

 

The ContentProvider instance manages access to a structured set of data by handling requests from other applications. All forms of access eventually call ContentResolver, which then calls a concrete method of ContentProvider to get access.

 

ContentProvider实例通过处理来自其它应用程序的请求来管理对一个结构化数据集的访问。所有访问形式最终会调用ContentResolver,然后它会调用ContentProvider的一个具体方法来获取访问权。

 

Required methods

 

必需的方法

 

The abstract class ContentProvider defines six abstract methods that you must implement as part of your own concrete subclass. All of these methods except onCreate() are called by a client application that is attempting to access your content provider:

 

抽象类ContentProvider定义六个abstract方法,你必须实现它们作为你自己的具体子类的一部分。所有这些方法除了onCreate()外被一个尝试访问你的内容提供者的客户端应用程序调用。

 

query()

 

Retrieve data from your provider. Use the arguments to select the table to query, the rows and columns to return, and the sort order of the result. Return the data as a Cursor object.

 

从你的提供者中取出数据。使用参数来选择要查询的表,要返回的行和列,以及结果的排列次序。返回数据作为一个Cursor对象。

 

insert()

 

Insert a new row into your provider. Use the arguments to select the destination table and to get the column values to use. Return a content URI for the newly-inserted row.

 

插入一个新行进你的提供者。使用参数来选择目标表和得到要使用的列的值。返回新插入行的一个内容URI。

 

update()

 

Update existing rows in your provider. Use the arguments to select the table and rows to update and to get the updated column values. Return the number of rows updated.

 

更新你的提供者中的现存行。使用参数来选择要更新的表和行并且获得更新列的值。返回被更新行的数量。

 

delete()

 

Delete rows from your provider. Use the arguments to select the table and the rows to delete. Return the number of rows deleted.

 

从你的提供者中删除行。使用参数来选择要删除的表和行。返回被删除行的数量。

 

getType()

 

Return the MIME type corresponding to a content URI. This method is described in more detail in the section Implementing Content Provider MIME Types.

 

返回对应一个内容URI的MIME类型。在章节实现内容提供者MIME类型中更详细地描述这个方法。

 

onCreate()

 

Initialize your provider. The Android system calls this method immediately after it creates your provider. Notice that your provider is not created until a ContentResolver object tries to access it.

 

初始化你的提供者。Android系统在它创建你的提供者后立即调用这个方法。注意你的提供者不被创建,直至一个ContentResolver对象尝试访问它。

 

Notice that these methods have the same signature as the identically-named ContentResolver methods.

 

注意这些方法和相同命名的ContentResolver方法拥有相同的签名。

 

Your implementation of these methods should account for the following:

 

你对这些方法的实现应该负责以下事情:

 

* All of these methods except onCreate() can be called by multiple threads at once, so they must be thread-safe. To learn more about multiple threads, see the topic Processes and Threads.

 

* 所有这些方法除了onCreate()以外可以同时被多个线程调用,所以它们必须是线程安全的。要知道关于多线程的更多信息,参见主题进程与线程。

 

* Avoid doing lengthy operations in onCreate(). Defer initialization tasks until they are actually needed. The section Implementing the onCreate() method discusses this in more detail.

 

* 避免在onCreate()中执行过长的操作。延迟初始化任务直至实际地需要它们。章节实现onCreate()方法会更详细地讨论它。

 

* Although you must implement these methods, your code does not have to do anything except return the expected data type. For example, you may want to prevent other applications from inserting data into some tables. To do this, you can ignore the call to insert() and return 0.

 

* 虽然你必须实现这些方法,你的代码不必做任何事情除了返回期待的数据类型。例如,你可能希望阻止其它应用程序插入数据进一些表。为了做到这点,你可以忽略对insert()的调用并且返回0。

 

Implementing the query() method

 

实现query()方法

 

The ContentProvider.query() method must return a Cursor object, or if it fails, throw an Exception. If you are using an SQLite database as your data storage, you can simply return the Cursor returned by one of the query() methods of the SQLiteDatabase class. If the query does not match any rows, you should return a Cursor instance whose getCount() method returns 0. You should return null only if an internal error occurred during the query process.

 

ContentProvider.query()方法必须返回一个Cursor对象,或者如果它失败,则抛出一个Exception。如果你正在使用一个SQLite数据库作为你的数据存储,你可以简单地返回由SQLiteDatabase类的query()方法之一返回的Cursor。如果查询不匹配任意行,你应该返回一个Cursor实例,它的getCount()方法返回0。你应该返回null,仅当在查询过程中一个内部错误发生。

 

If you aren't using an SQLite database as your data storage, use one of the concrete subclasses of Cursor. For example, the MatrixCursor class implements a cursor in which each row is an array of Object. With this class, use addRow() to add a new row.

 

如果你不是正在使用一个SQLite数据库作为你的数据存储,请使用Cursor具体子类之一。例如,MatrixCursor类实现一个游标,在它里面每行是一个Object数组。利用此类,使用addRow()来添加一个新行。

 

Remember that the Android system must be able to communicate the Exception across process boundaries. Android can do this for the following exceptions that may be useful in handling query errors:

 

记住Android系统必须有能力跨进程边界传递Exception。对于以下可能对处理查询错误有用的异常,Android可以做到这点:

 

* IllegalArgumentException (You may choose to throw this if your provider receives an invalid content URI)

 

* IllegalArgumentException(你可能选择抛出它,如果你的提供者接收一个不可用的内容URI)

 

* NullPointerException

 

* NullPointerException(空指针异常)

 

Implementing the insert() method

 

实现insert()方法

 

The insert() method adds a new row to the appropriate table, using the values in the ContentValues argument. If a column name is not in the ContentValues argument, you may want to provide a default value for it either in your provider code or in your database schema.

 

insert()方法添加一个新行到合适的表,使用ContentValues参数中的值。如果一个列名不在ContentValues参数中,你可能希望在你的提供者代码中或在你的数据库模式中为它提供一个默认值。

 

This method should return the content URI for the new row. To construct this, append the new row's _ID (or other primary key) value to the table's content URI, using withAppendedId().

 

这个方法应该返回新行的内容URI。要构造它,请尾加新行的_ID(或其它主键)值到表的内容URI后面,使用withAppendedId()。

 

Implementing the delete() method

 

实现delete()方法

 

The delete() method does not have to physically delete rows from your data storage. If you are using a sync adapter with your provider, you should consider marking a deleted row with a "delete" flag rather than removing the row entirely. The sync adapter can check for deleted rows and remove them from the server before deleting them from the provider.

 

delete()方法不必物理地从你的数据存储中删除行。如果你正在用你的提供者使用一个同步适配器,你应该考虑用一个“删除”标志标记一个被删除的行而非整个地移除行。同步适配器可以检查被删除行和在从提供者中删除它们前从服务器中移除它们。

 

Implementing the update() method

 

实现update()方法

 

The update() method takes the same ContentValues argument used by insert(), and the same selection and selectionArgs arguments used by delete() and ContentProvider.query(). This may allow you to re-use code between these methods.

 

update()方法带insert()使用的相同的ContentValues参数,以及delete()和ContentProvider.query()使用的相同的selection和selectionArgs参数。它可能允许你在这些方法之间重用代码。

 

Implementing the onCreate() method

 

实现onCreate()方法

 

The Android system calls onCreate() when it starts up the provider. You should perform only fast-running initialization tasks in this method, and defer database creation and data loading until the provider actually receives a request for the data. If you do lengthy tasks in onCreate(), you will slow down your provider's startup. In turn, this will slow down the response from the provider to other applications.

 

当它启动内容提供者时Android系统调用onCreate()。在这个方法里你应该只执行快速运行的初始化任务,并且延迟数据库创建和数据加载直至提供者实际地接收一个对数据的请求。如果你在onCreate()中执行过长的任务,你将减慢你的提供者的启动。反过来,它将减慢从提供者到其它应用程序的响应。

 

For example, if you are using an SQLite database you can create a new SQLiteOpenHelper object in ContentProvider.onCreate(), and then create the SQL tables the first time you open the database. To facilitate this, the first time you call getWritableDatabase(), it automatically calls the SQLiteOpenHelper.onCreate() method.

 

例如,如果你正在使用一个SQLite数据库,你可以在ContentProvider.onCreate()中创建一个新的SQLiteOpenHelper对象,然后在你第一次打开该数据库时你创建SQL表。为了方便它,第一次时你调用getWritableDatabase(),它自动地调用SQLiteOpenHelper.onCreate()方法。

 

The following two snippets demonstrate the interaction between ContentProvider.onCreate() and SQLiteOpenHelper.onCreate(). The first snippet is the implementation of ContentProvider.onCreate():

 

以下两个代码片段演示ContentProvider.onCreate()和SQLiteOpenHelper.onCreate()之间的交互。第一个代码片段是ContentProvider.onCreate()的实现:

 

-------------------------------

 

public class ExampleProvider extends ContentProvider

 

    /*

     * Defines a handle to the database helper object. The MainDatabaseHelper class is defined

     * in a following snippet.

     * 定义一个指向数据库辅助对象的句柄。MainDatabaseHelper在以下代码片段中被定义。

     */

    private MainDatabaseHelper mOpenHelper;

 

    // Defines the database name

    // 定义数据库名称

    private static final String DBNAME = "mydb";

 

    // Holds the database object

    // 持有数据库对象

    private SQLiteDatabase db;

 

    public boolean onCreate() {

 

        /*

         * Creates a new helper object. This method always returns quickly.

         * Notice that the database itself isn't created or opened

         * until SQLiteOpenHelper.getWritableDatabase is called

         * 创建一个新的辅助对象。这个方法总是快速地返回。

         * 注意数据库自身不被创建或打开,直至

         * SQLiteOpenHelper.getWritableDatabase被调用

         */

        mOpenHelper = new SQLiteOpenHelper(

            getContext(),        // the application context 应用程序上下文

            DBNAME,              // the name of the database) 数据库的名称(注:此处多了个右括号)

            null,                // uses the default SQLite cursor 使用默认的SQLite游标

            1                    // the version number 版本号

        );

 

        return true;

    }

 

    ...

 

    // Implements the provider's insert method

    // 实现提供者的insert方法

    public Cursor insert(Uri uri, ContentValues values) {

        // Insert code here to determine which table to open, handle error-checking, and so forth

        // 在这里插入代码来决定要打开哪个表,处理错误检查,等等

 

        ...

 

        /*

         * Gets a writeable database. This will trigger its creation if it doesn't already exist.

         * 获得一个可写数据库。它将触发它的创建如果它还没有存在。

         * 

         */

        db = mOpenHelper.getWritableDatabase();

    }

}

 

-------------------------------

 

The next snippet is the implementation of SQLiteOpenHelper.onCreate(), including a helper class:

 

以下代码片段是SQLiteOpenHelper.onCreate()的实现,包括一个辅助类:

 

-------------------------------

 

...

// A string that defines the SQL statement for creating a table

// 一个定义用于创建一个表的SQL语句的一个字符串

private static final String SQL_CREATE_MAIN = "CREATE TABLE " +

    "main " +                       // Table's name 表名

    "(" +                           // The columns in the table 表中的列

    " _ID INTEGER PRIMARY KEY, " +

    " WORD TEXT"

    " FREQUENCY INTEGER " +

    " LOCALE TEXT )";

...

/**

 * Helper class that actually creates and manages the provider's underlying data repository.

 */

protected static final class MainDatabaseHelper extends SQLiteOpenHelper {

 

    /*

     * Instantiates an open helper for the provider's SQLite data repository

     * Do not do database creation and upgrade here.

     * 为提供者的SQLite数据仓库实例化一个开放(注:待考)的辅助器

     * 不要在这里执行数据库创建和更新。

     */

    MainDatabaseHelper(Context context) {

        super(context, DBNAME, null, 1);

    }

 

    /*

     * Creates the data repository. This is called when the provider attempts to open the

     * repository and SQLite reports that it doesn't exist.

     * 创建数据仓库。当提供者尝试打开该仓库时它被调用,而SQLite报告它不存在。(注:此处待考)

     */

    public void onCreate(SQLiteDatabase db) {

 

        // Creates the main table

        // 创建主表

        db.execSQL(SQL_CREATE_MAIN);

    }

}

 

-------------------------------

 

-------------------------------

 

Implementing ContentProvider MIME Types

 

实现ContentProvider的MIME类型

 

The ContentProvider class has two methods for returning MIME types:

 

ContentProvider类拥有两个返回MIME类型的方法:

 

getType()

 

One of the required methods that you must implement for any provider.

 

其中一个必需的方法,你必须为任何提供者实现它。

 

getStreamTypes()

 

A method that you're expected to implement if your provider offers files.

 

一个期待你实现的方法,如果你的提供者提供文件。

 

MIME types for tables

 

表的MIME类型

 

The getType() method returns a String in MIME format that describes the type of data returned by the content URI argument. The Uri argument can be a pattern rather than a specific URI; in this case, you should return the type of data associated with content URIs that match the pattern.

 

getType()方法返回一个MIME格式的String,它描述被内容URI参数返回的数据类型。Uri参数可以是一个模式而非一个特定的URI;在这种情况下,你应该返回与匹配该模式的内容URI关联的数据类型。

 

For common types of data such as as text, HTML, or JPEG, getType() should return the standard MIME type for that data. A full list of these standard types is available on the IANA MIME Media Types website.

 

对于通用数据类型诸如文本,HTML,或JPEG,getType()应该返回那个数据的标准MIME类型。这些标准类型的完全列表在IANA MIME媒体类型网站上可用。(注:IANA,Internet Assigned Numbers Authority,互联网号码分配局)

 

For content URIs that point to a row or rows of table data, getType() should return a MIME type in Android's vendor-specific MIME format:

 

对于指向表数据的一个或多个行的内容URI,getType()应该以Android的供应商特定的MIME格式来返回一个MIME类型:

 

* Type part: vnd

 

* 类型部分:vnd

 

* Subtype part:

 

* 子类型部分:

 

* If the URI pattern is for a single row: android.cursor.item/

 

* 如果URI模式是对应一个单一行:android.cursor.item/

 

* If the URI pattern is for more than one row: android.cursor.dir/

 

* 如果URI模式是对应多于一行:android.cursor.dir/

 

* Provider-specific part: vnd.<name>.<type>

 

* 提供者特定部分:vnd.<名称>.<类型>

 

You supply the <name> and <type>. The <name> value should be globally unique, and the <type> value should be unique to the corresponding URI pattern. A good choice for <name> is your company's name or some part of your application's Android package name. A good choice for the <type> is a string that identifies the table associated with the URI.

 

你提供<名称>和<类型>,<名称>值应该是全局唯一的,而<类型>值应该是对于相应的URI模式是唯一的。对于<名称>的一个好选择是你的公司名或你的应用程序的Android包名的一些部分。对于<类型>的一个好选择是标识与该URI关联的表的字符串。

 

For example, if a provider's authority is com.example.app.provider, and it exposes a table named table1, the MIME type for multiple rows in table1 is:

 

例如,如果一个提供者的权力是com.example.app.provider,而且它暴露一个名为table1的表,那么对于table1中多行的MIME类型是:

 

-------------------------------

 

vnd.android.cursor.dir/vnd.com.example.provider.table1

 

-------------------------------

 

For a single row of table1, the MIME type is:

 

对于table1的一个单一行,MIME类型是:

 

-------------------------------

 

vnd.android.cursor.item/vnd.com.example.provider.table1

 

-------------------------------

 

MIME types for files

 

文件的MIME类型

 

If your provider offers files, implement getStreamTypes(). The method returns a String array of MIME types for the files your provider can return for a given content URI. You should filter the MIME types you offer by the MIME type filter argument, so that you return only those MIME types that the client wants to handle.

 

如果你的提供者提供文件,请实现getStreamTypes()。该方法返回你的提供者可以返回的对应一个给定内容URI的文件的MIME类型String数组。你应该通过MIME类型过滤器参数过滤你提供的MIME类型,致使你只返回那些客户端希望处理的MIME类型。

 

For example, consider a provider that offers photo images as files in .jpg, .png, and .gif format. If an application calls ContentResolver.getStreamTypes() with the filter string image/* (something that is an "image"), then the ContentProvider.getStreamTypes() method should return the array:

 

例如,考虑一个提供者,它提供照片图片作为.jpg,.png,和.gif格式的文件。如果一个应用程序用过滤器字符串image/*(一些是“图片”的东西)调用ContentResolver.getStreamTypes(),那么ContentProvider.getStreamTypes()方法应该返回数组:

 

-------------------------------

 

{ "image/jpeg", "image/png", "image/gif"}

 

-------------------------------

 

If the app is only interested in .jpg files, then it can call ContentResolver.getStreamTypes() with the filter string *\/jpeg, and ContentProvider.getStreamTypes() should return:

 

如果应用只对.jpg文件感兴趣,那么它可以用过滤器字符串*\/jpeg调用ContentResolver.getStreamTypes(),而且ContentProvider.getStreamTypes()应该返回:

 

-------------------------------

 

{"image/jpeg"}

 

-------------------------------

 

If your provider doesn't offer any of the MIME types requested in the filter string, getStreamTypes() should return null.

 

如果你的提供者不提供在过滤器字符串中请求的任意MIME类型,那么getStreamTypes()应该返回null。

 

-------------------------------

 

Implementing a Contract Class

 

实现一个契约类

 

A contract class is a public final class that contains constant definitions for the URIs, column names, MIME types, and other meta-data that pertain to the provider. The class establishes a contract between the provider and other applications by ensuring that the provider can be correctly accessed even if there are changes to the actual values of URIs, column names, and so forth.

 

一个契约类是一个public final类,它包含用于URI、列名、MIME类型,以及其它涉及到提供者的元数据的常量定义。该类通过确保即便URI、列名等等的实际值有一些改变,提供者仍可以正确地被访问,来建立提供者和其它应用程序之间的一个契约。

 

A contract class also helps developers because it usually has mnemonic names for its constants, so developers are less likely to use incorrect values for column names or URIs. Since it's a class, it can contain Javadoc documentation. Integrated development environments such as Eclipse can auto-complete constant names from the contract class and display Javadoc for the constants.

 

一个契约类还有助于开发者,因为它通常有它的常量的助记符名称,使开发者较少可能地使用列名或URI的不正确值。因为它是一个类,所以它可以包含Javadoc文档。集成开发环境(注:简称IDE)诸如Eclipse可以自动补全来自契约类的常量名并且显示常量的Javadoc。

 

Developers can't access the contract class's class file from your application, but they can statically compile it into their application from a .jar file you provide.

 

开发者不允许从你的应用程序中访问契约类的类文件,但它们可以从你提供的一个.jar文件中静态地编译它进它们的应用程序。

 

The ContactsContract class and its nested classes are examples of contract classes.

 

ContactsContract类和它的内嵌类是示例的契约类。

 

-------------------------------

 

Implementing Content Provider Permissions

 

实现内容提供者权限

 

Permissions and access for all aspects of the Android system are described in detail in the topic Security and Permissions. The topic Data Storage also described the security and permissions in effect for various types of storage. In brief, the important points are:

 

在主题安全和权限中详细地描述权限和对Android系统的所有方面的访问。主题数据存储也描述对不同类型存储有效的安全与权限。简单来说,重要点是:

 

* By default, data files stored on the device's internal storage are private to your application and provider.

 

* 默认,存储在设备的内部存储上的数据文件对于你的应用程序和提供者是私有的。

 

* SQLiteDatabase databases you create are private to your application and provider.

 

* 你创建的SQLiteDatabase数据库对于你的应用程序和提供者是私有的。

 

* By default, data files that you save to external storage are public and world-readable. You can't use a content provider to restrict access to files in external storage, because other applications can use other API calls to read and write them.

 

* 默认,你保存到外部存储的数据文件是私有的和全局可读的。你不能使用一个内容提供者来限制对内部存储中文件的访问,因为其它应用程序可以使用其它API调用来读写它们。

 

* The method calls for opening or creating files or SQLite databases on your device's internal storage can potentially give both read and write access to all other applications. If you use an internal file or database as your provider's repository, and you give it "world-readable" or "world-writeable" access, the permissions you set for your provider in its manifest won't protect your data. The default access for files and databases in internal storage is "private", and for your provider's repository you shouldn't change this.

 

* 用于在你的设备的内部存储上打开或创建文件或SQLite数据库的方法调用可以隐式地给予读和写访问权给其它所有应用程序。如果你使用一个内部文件或数据库作为你的提供者的仓库,而且你给予它“全局可读”或“全局可写”访问权,那么在它的清单中你为你的提供者设置的权限将不保护你的数据。对内部存储中文件和数据库的默认访问权是“私有的”,而对于你的提供者的仓库你不应该改变它。

 

If you want to use content provider permissions to control access to your data, then you should store your data in internal files, SQLite databases, or the "cloud" (for example, on a remote server), and you should keep files and databases private to your application.

 

如果你希望使用内容提供者权限来控制对你的数据的访问,那么你应该在内部文件,SQLite数据库,或“云存储”(例如,在一个远程服务器上)中存储你的数据,而你应该保持文件和数据库对你的应用程序是私有。

 

Implementing permissions

 

实现权限

 

All applications can read from or write to your provider, even if the underlying data is private, because by default your provider does not have permissions set. To change this, set permissions for your provider in your manifest file, using attributes or child elements of the <provider> element. You can set permissions that apply to the entire provider, or to certain tables, or even to certain records, or all three.

 

所有应用程序可以读取或写入你的提供者,即便底层数据是私有的,因为默认你的提供者没有设置权限。为了改变它,在你的清单文件中为你的提供者设置权限,使用<provider>元素的属性或子元素。你可以设置权限,它应用到整个提供者,或某些表,或甚至是某些记录,或所有三者。

 

You define permissions for your provider with one or more <permission> elements in your manifest file. To make the permission unique to your provider, use Java-style scoping for the android:name attribute. For example, name the read permission com.example.app.provider.permission.READ_PROVIDER.

 

你在你的清单文件中用一个或多个<permission>元素为你的提供者定义权限。为了让权限对于你的提供者是唯一的,请对android:name属性使用Java风格作用域。例如,命名读权限为com.example.app.provider.permission.READ_PROVIDER。

 

The following list describes the scope of provider permissions, starting with the permissions that apply to the entire provider and then becoming more fine-grained. More fine-grained permissions take precedence over ones with larger scope:

 

以下列表描述提供者权限的作用域,从应用到整个提供者的权限开始,然后变得更细粒度。更细粒度的权限持有高于带有较大作用域的权限的优先级。

 

Single read-write provider-level permission

 

单一读写提供者级权限

 

One permission that controls both read and write access to the entire provider, specified with the android:permission attribute of the <provider> element.

 

控制对整个提供者的读写访问权的一个权限,用<provider>元素的android:permission属性指定。

 

Separate read and write provider-level permission

 

分离读和写提供者级权限

 

A read permission and a write permission for the entire provider. You specify them with the android:readPermission and android:writePermission attributes of the <provider> element. They take precedence over the permission required by android:permission.

 

对整个提供者的一个读权限和一个写权限。你用<provider>元素的android:readPermission和android:writePermission属性指定它们。它们持有高于android:permission所需权限的优先级。

 

Path-level permission

 

路径级权限

 

Read, write, or read/write permission for a content URI in your provider. You specify each URI you want to control with a <path-permission> child element of the <provider> element. For each content URI you specify, you can specify a read/write permission, a read permission, or a write permission, or all three. The read and write permissions take precedence over the read/write permission. Also, path-level permission takes precedence over provider-level permissions.

 

在你的提供者中对一个内容URI的读,写,或读/写权限。你用<provider>元素的<path-permission>子元素来指定你希望控制的每个URI。对于你指定的每个内容URI,你可以指定一个读/写权限,一个读权限,或一个写权限,或所有三者。读和写权限持有高于读/写权限的优先级。另外,路径级权限持有高于提供者级权限的优先级。

 

Temporary permission

 

临时权限

 

A permission level that grants temporary access to an application, even if the application doesn't have the permissions that are normally required. The temporary access feature reduces the number of permissions an application has to request in its manifest. When you turn on temporary permissions, the only applications that need "permanent" permissions for your provider are ones that continually access all your data.

 

授权临时访问权给一个应用程序的一个权限级,即便应用程序没有正常情况下必需的权限。临时访问权特性降低一个应用程序不得不在它的清单中请求的权限的数量。当你打开临时权限时,需要你的提供者的“永久”权限的应用程序只是那些不断地访问你的所有数据的应用程序。

 

Consider the permissions you need to implement an email provider and app, when you want to allow an outside image viewer application to display photo attachments from your provider. To give the image viewer the necessary access without requiring permissions, set up temporary permissions for content URIs for photos. Design your email app so that when the user wants to display a photo, the app sends an intent containing the photo's content URI and permission flags to the image viewer. The image viewer can then query your email provider to retrieve the photo, even though the viewer doesn't have the normal read permission for your provider.

 

考虑你需要用来实现一个电子邮件提供者和应用的权限,当你希望允许一个外部图片查看器应用程序显示来自你的提供者的照片附件。为了给予图片查看器必需的访问权而不需要权限,请为照片的内容URI配置临时权限。设计你的电子邮件应用致使当用户希望显示一个照片时,应用发送一个包含图片的内容URI和权限标志的意图到图片查看器。然后图片查看器可以查询你的电子邮件提供者以取出照片,即便查看器没有对你的提供者的正常的读权限。

 

To turn on temporary permissions, either set the android:grantUriPermissions attribute of the <provider> element, or add one or more <grant-uri-permission> child elements to your <provider> element. If you use temporary permissions, you have to call Context.revokeUriPermission() whenever you remove support for a content URI from your provider, and the content URI is associated with a temporary permission.

 

为了打开临时权限,或者设置<provider>元素的android:grantUriPermissions属性,或者添加一个或多个<grant-uri-permission>子元素到你的<provider>元素。如果你使用临时权限,你不得不调用Context.revokeUriPermission(),每当你从你的提供者中移除对一个内容URI的支持,而内容URI被关联到一个临时权限。

 

The attribute's value determines how much of your provider is made accessible. If the attribute is set to true, then the system will grant temporary permission to your entire provider, overriding any other permissions that are required by your provider-level or path-level permissions.

 

该属性值决定让你的提供者有多少程度的可访问。如果该属性被设置为true,那么系统将授权临时权限给你的整个提供者,覆盖你的提供者级或路径级权限所需的其它任意权限。

 

If this flag is set to false, then you must add <grant-uri-permission> child elements to your <provider> element. Each child element specifies the content URI or URIs for which temporary access is granted.

 

如果这个标志被设置为false,那么你必须添加<grant-uri-permission>子元素到你的<provider>元素。每个子元素指定一个或多个内容URI,临时访问权被授权给它们。

 

To delegate temporary access to an application, an intent must contain the FLAG_GRANT_READ_URI_PERMISSION or the FLAG_GRANT_WRITE_URI_PERMISSION flags, or both. These are set with the setFlags() method.

 

为了委托临时访问权给一个应用程序,一个意图必须包含FLAG_GRANT_READ_URI_PERMISSION或FLAG_GRANT_WRITE_URI_PERMISSION标志,或两者都有。用setFlags()方法设置它们。

 

If the android:grantUriPermissions attribute is not present, it's assumed to be false.

 

如果android:grantUriPermissions不存在,那么它假设是false。

 

-------------------------------

 

The <provider> Element

 

<provider>元素

 

Like Activity and Service components, a subclass of ContentProvider must be defined in the manifest file for its application, using the <provider> element. The Android system gets the following information from the element:

 

像Activity和Service组件,一个ContentProvider子类必须被定义在清单文件中对应它的应用程序,使用<provider>元素。Android系统从该元素中获得以下信息:

 

Authority (android:authorities)

 

权力(android:authorities)

 

Symbolic names that identify the entire provider within the system. This attribute is described in more detail in the section Designing Content URIs.

 

在系统中标识整个提供者的符号名。在章节设计内容URI中更详细地描述这个属性。

 

Provider class name ( android:name )

 

提供者类型(android:name)

 

The class that implements ContentProvider. This class is described in more detail in the section Implementing the ContentProvider Class.

 

实现ContentProvider的类。在章节实现ContentProvider类中更详细地描述这个类。

 

Permissions

 

权限

 

Attributes that specify the permissions that other applications must have in order to access the provider's data:

 

属性,它指定其它应用程序必须拥有的权限以访问提供者的数据:

 

* android:grantUriPermssions: Temporary permission flag.

 

* android:grantUriPermssions:临时权限标志。

 

* android:permission: Single provider-wide read/write permission.

 

* android:permission:单一提供者范围的读/写权限。

 

* android:readPermission: Provider-wide read permission.

 

* android:readPermission:提供者范围的读权限。

 

* android:writePermission: Provider-wide write permission.

 

* android:writePermission:提供者范围的写权限。

 

Permissions and their corresponding attributes are described in more detail in the section Implementing Content Provider Permissions.

 

在章节实现内容提供者权限中更详细地描述权限和它们相应属性。

 

Startup and control attributes

 

启动和控制属性

 

These attributes determine how and when the Android system starts the provider, the process characteristics of the provider, and other run-time settings:

 

这些属性决定Android系统如何和何时启动提供者,提供者的进程特性,以及其它运行时设置:

 

* android:enabled: Flag allowing the system to start the provider.

 

* android:enabled:允许系统启动提供者的标志。

 

* android:exported: Flag allowing other applications to use this provider.

 

* android:exported:允许其它应用程序使用这个提供者的标志。

 

* android:initOrder: The order in which this provider should be started, relative to other providers in the same process.

 

* android:initOrder:这个提供者相对于同一个进程中的其它提供者应该被启动的次序。

 

* android:multiProcess: Flag allowing the system to start the provider in the same process as the calling client.

 

* android:multiProcess:允许系统启动相同进程中的提供者作为调用方客户端的标志。

 

* android:process: The name of the process in which the provider should run.

 

* android:process:提供者应该运行在的进程的名称。

 

* android:syncable: Flag indicating that the provider's data is to be sync'ed with data on a server.

 

* android:syncable:指示提供者的数据将被服务其上的数据同步的标志。

 

The attributes are fully documented in the dev guide topic for the <provider> element.

 

这些属性在开发指引的<provider>元素的主题中完全地被文档化。

 

Informational attributes

 

带信息的属性

 

An optional icon and label for the provider:

 

一个用于提供者的可选图标和标签:

 

* android:icon: A drawable resource containing an icon for the provider. The icon appears next to the provider's label in the list of apps in Settings > Apps > All.

 

* android:icon:一个包含一个用于提供者的图标的可绘画对象资源。在设置>应用>全部中的应用列表中,图标显示在提供者的标签旁边。

 

* android:label: An informational label describing the provider or its data, or both. The label appears in the list of apps in Settings > Apps > All.

 

* android:label:一个描述提供者或它的数据或两者都有的带信息标签。标签显示在设置>应用>全部中的应用列表中。

 

The attributes are fully documented in the dev guide topic for the <provider> element.

 

属性在开发指引的<provider>元素的主题中完全被文档化。

 

-------------------------------

 

Intents and Data Access

 

意图和数据访问

 

Applications can access a content provider indirectly with an Intent. The application does not call any of the methods of ContentResolver or ContentProvider. Instead, it sends an intent that starts an activity, which is often part of the provider's own application. The destination activity is in charge of retrieving and displaying the data in its UI. Depending on the action in the intent, the destination activity may also prompt the user to make modifications to the provider's data. An intent may also contain "extras" data that the destination activity displays in the UI; the user then has the option of changing this data before using it to modify the data in the provider.

 

应用程序可以用一个Intent间接地访问一个内容提供者。应用程序不调用ContentResolver或ContentProvider的任何方法。取而代之,它发送一个启动一个活动的意图,那个活动经常是提供者自己的应用程序的一部分。目标活动负责在它的用户界面中取出和显示数据。依赖于意图里的动作,目标活动还可能提示用户对提供者的数据作出修改。一个意图还可能包含“额外”数据,目标活动在用户界面中显示它;然后用户拥有在使用它来修改提供者中的数据之前改变这个数据的选择权。

 

You may want to use intent access to help ensure data integrity. Your provider may depend on having data inserted, updated, and deleted according to strictly defined business logic. If this is the case, allowing other applications to directly modify your data may lead to invalid data. If you want developers to use intent access, be sure to document it thoroughly. Explain to them why intent access using your own application's UI is better than trying to modify the data with their code.

 

你可能希望使用意图访问来帮助确保数据的完整性。你的提供者可能依赖于让数据严格地根据已定义的业务逻辑来被插入,更新,以及删除。如果是这种情况的话,允许其它应用程序直接地修改你的数据可能导致不可用的数据。如果你希望开发者使用意图访问,请确保彻底地文档化它。向他们解释为什么意图访问使用你自己的应用程序的用户界面优于用他们的代码来尝试修改数据。

 

Handling an incoming intent that wishes to modify your provider's data is no different from handling other intents. You can learn more about using intents by reading the topic Intents and Intent Filters.

 

处理一个希望修改你的提供者的数据的输入意图和处理其他意图没有不同。你可以通过阅读主题意图和意图过滤器来知道关于使用意图的更多信息。

 

Except as noted, this content is licensed under Apache 2.0. For details and restrictions, see the Content License.

 

除特别说明外,本文在Apache 2.0下许可。细节和限制请参考内容许可证。

 

Android 4.0 r1 - 01 Feb 2012 20:50

 

-------------------------------

 

Portions of this page are modifications based on work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.

 

(此页部分内容基于Android开源项目,以及使用根据创作公共2.5来源许可证描述的条款进行修改)

 

(本人翻译质量欠佳,请以官方最新内容为准,或者参考其它翻译版本:

* ソフトウェア技術ドキュメントを勝手に翻訳

http://www.techdoctranslator.com/android

* Ley's Blog

http://leybreeze.com/blog/

* 农民伯伯

http://www.cnblogs.com/over140/

* Android中文翻译组

http://androidbox.sinaapp.com/


Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐