码迷,mamicode.com
首页 > Windows程序 > 详细

API翻译 --- Content Provider Basics

时间:2016-07-19 10:23:53      阅读:246      评论:0      收藏:0      [点我收藏+]

标签:

IN THIS DOCUMENT

  1. Overview           综述                                                       
    1. Accessing a provider           访问一个提供者        
    2. Content URIs                  内容URI
  2. Retrieving Data from the Provider                    检索的数据提供者
    1. Requesting read access permission           请求读访问权限
    2. Constructing the query          构建查询
    3. Displaying query results              显示查询结果
    4. Getting data from query results    从查询结果中获取数据
  3. Content Provider Permissions               内容提供者权限
  4. Inserting, Updating, and Deleting Data   插入、更新和删除数据
    1. Inserting data    添加数据
    2. Updating data    更新数据
    3. Deleting data     删除数据
  5. Provider Data Types      提供者的数据类型
  6. Alternative Forms of Provider Access    替代形式的提供者访问
    1. Batch access   成批存取
    2. Data access via intents        数据访问通过意图
  7. Contract Classes                 合同类
  8. MIME Type Reference       MIME类型引用

KEY CLASSES

  1. ContentProvider
  2. ContentResolver
  3. Cursor
  4. Uri

RELATED SAMPLES

  1. Cursor (People)
  2. Cursor (Phones)

SEE ALSO

  1. Creating a Content Provider
  2. Calendar Provider     日历提供者






A content provider manages access to a central repository of data. A provider is part of an Android application, which often provides its own UI for working with the data. However, content providers are primarily intended to be used by other applications, which access the provider using a provider client object. Together, providers and provider clients offer a consistent, standard interface to data that also handles inter-process communication and secure data access.

一个内容提供者管理的中央存储库数据的访问。提供者是Android应用程序的一部分,通常提供自己的UI处理数据。然而,内容提供商主要是打算使用的其他应用程序,访问提供者使用提供者端对象。客户,供应商和供应商提供一个一致的,数据标准接口,还处理进程间通信和安全的数据访问。

This topic describes the basics of the following:本主题描述的基本知识:

  • How content providers work.内容提供者是如何工作的。
  • The API you use retrieve data from a content provider.您所使用的API检索数据从一个内容提供者。
  • The API you use to insert, update, or delete data in a content provider.API用于插入、更新或删除数据在一个内容提供者
  • Other API features that facilitate working with providers.其他API功能,促进与供应商合作。

Overview


A content provider presents data to external applications as one or more tables that are similar to the tables found in a relational database. A row represents an instance of some type of data the provider collects, and each column in the row represents an individual piece of data collected for an instance.

内容提供者提供数据到外部应用程序作为一个或多个表类似于关系数据库中的表。一行代表一个某种类型的实例数据提供者收集,和行中的每一列代表一个数据收集的一个实例。

For example, one of the built-in providers in the Android platform is the user dictionary, which stores the spellings of non-standard words that the user wants to keep. Table 1 illustrates what the data might look like in this provider‘s table:

例如,Android平台内置的提供者之一是用户词典,商店标准单词的拼写,用户希望保持。表1显示了数据可能看起来像这个提供者的表:

Table 1: Sample user dictionary table.

word app id frequency locale _ID
mapreduce user1 100 en_US 1
precompiler user14 200 fr_FR 2
applet user2 225 fr_CA 3
const user1 255 pt_BR 4
int user5 100 en_UK 5

In table 1, each row represents an instance of a word that might not be found in a standard dictionary. Each column represents some data for that word, such as the locale in which it was first encountered. The column headers are column names that are stored in the provider. To refer to a row‘s locale, you refer to its locale column. For this provider, the _ID column serves as a "primary key" column that the provider automatically maintains.

在表1中,每一行表示一个单词的实例可能不会发现在标准字典。每一列表示一些词的数据,如语言环境中,这是第一次遇到。列标题的列名称存储在提供者。指连续的区域,你参考它的地区列。对于这个提供者,_ID列作为“主键”专栏,提供者自动维护。

Note: A provider isn‘t required to have a primary key, and it isn‘t required to use _ID as the column name of a primary key if one is present. However, if you want to bind data from a provider to a ListView, one of the column names has to be _ID. This requirement is explained in more detail in the section Displaying query results.

注意:提供者不需要有一个主键,并且不需要使用_ID作为一个主键的列名称如果有的话)。然而,如果你想要绑定的数据提供者列表视图,列名必须_ID之一。这个需求更详细地解释中显示查询结果。

Accessing a provider     访问一个提供者

An application accesses the data from a content provider with a ContentResolver client object. This object has methods that call identically-named methods in the provider object, an instance of one of the concrete subclasses of ContentProvider. The ContentResolver methods provide the basic "CRUD" (create, retrieve, update, and delete) functions of persistent storage.

应用程序访问数据从一个内容提供者ContentResolver客户端对象。这个对象方法调用提供者对象名称相同的方法,具体的子类的一个实例ContentProvider。ContentResolver方法提供了基本的CRUD(创建、检索、更新和删除)的持久性存储功能。

The ContentResolver object in the client application‘s process and the ContentProvider object in the application that owns the provider automatically handle inter-process communication. ContentProvideralso acts as an abstraction layer between its repository of data and the external appearance of data as tables.

ContentResolver对象在客户端应用程序的过程和ContentProvider对象在应用程序拥有提供者自动处理进程间通信。ContentProvideralso之间充当一个抽象层的存储库数据和数据表的外观。

Note: To access a provider, your application usually has to request specific permissions in its manifest file. This is described in more detail in the section Content Provider Permissions

For example, to get a list of the words and their locales from the User Dictionary Provider, you call ContentResolver.query(). The query() method calls the ContentProvider.query() method defined by the User Dictionary Provider. The following lines of code show a ContentResolver.query() call:

注意:访问提供者,您的应用程序通常有请求特定的权限清单文件。这是更详细地描述部分内容提供者权限
例如,要获取的单词列表和他们的地区从用户词典提供程序,你叫ContentResolver.query()。查询()方法调用ContentProvider.query()方法定义的用户词典提供程序。下面的代码行显示ContentResolver.query()调用:

// Queries the user dictionary and returns results
mCursor
= getContentResolver().query(
   
UserDictionary.Words.CONTENT_URI,   // The content URI of the words table
    mProjection
,                        // The columns to return for each row
    mSelectionClause                    
// Selection criteria
    mSelectionArgs
,                     // Selection criteria
    mSortOrder
);                        // The sort order for the returned rows

Table 2 shows how the arguments to query(Uri,projection,selection,selectionArgs,sortOrder) match an SQL SELECT statement:

Table 2: Query() compared to SQL query.

query() argument SELECT keyword/parameter Notes
Uri FROM table_name Uri maps to the table in the provider named table_name.
projection col,col,col,... projection is an array of columns that should be included for each row retrieved.
selection WHERE col = value selection specifies the criteria for selecting rows.
selectionArgs (No exact equivalent. Selection arguments replace? placeholders in the selection clause.)
sortOrder ORDER BYcol,col,... sortOrder specifies the order in which rows appear in the returned Cursor.

Content URIs

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 (a path). When you call a client method to access a table in a provider, the content URI for the table is one of the arguments.

In the preceding lines of code, the constant CONTENT_URI contains the content URI of the user dictionary‘s "words" table. The ContentResolver object parses out the URI‘s authority, and uses it to "resolve" the provider by comparing the authority to a system table of known providers. TheContentResolver can then dispatch the query arguments to the correct provider.

The ContentProvider uses the path part of the content URI to choose the table to access. A provider usually has a path for each table it exposes.

内容的URI是一个URI标识数据提供者。内容uri包括整个提供者的符号名(权力)和一个名字指向一个表(路径)。当你调用客户方法访问一个表在一个提供者,内容的表是一个URI参数。
在前面的代码行,不断CONTENT_URI包含内容的URI用户词典的“单词”表。ContentResolver对象解析URI的权威,并使用它来“解决”提供者通过比较系统的权限表的提供者。TheContentResolver可以调度查询参数正确的供应商。

In the previous lines of code, the full URI for the "words" table is:

 在前一行代码,完整的URI的“单词”表:

content://user_dictionary/words

where the user_dictionary string is the provider‘s authority, and words string is the table‘s path. The string content:// (the scheme) is always present, and identifies this as a content URI.

user_dictionary字符串的提供者的权威,和文字字符串表的路径。字符串内容:/ /(计划)总是存在,并确定这是一个URI的内容。

Many providers allow you to access a single row in a table by appending an ID value to the end of the URI. For example, to retrieve a row whose _ID is 4 from user dictionary, you can use this content URI:

许多供应商允许您访问表中的一行通过附加一个ID值的URI。例如,检索一行的_ID 4从用户词典,你可以使用这个URI的内容:

Uri singleUri =ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4);

You often use id values when you‘ve retrieved a set of rows and then want to update or delete one of them.

你经常使用id值,当检索一组行,然后想要更新或删除其中之一。

Note: The Uri and Uri.Builder classes contain convenience methods for constructing well-formed Uri objects from strings. The ContentUris contains convenience methods for appending id values to a URI. The previous snippet uses withAppendedId() to append an id to the UserDictionary content URI.

注意:Uri和Uri。构建器类包含便利方法构造格式良好的Uri对象从字符串。ContentUris包含便利的方法将id值附加到一个URI。前面的代码片段使用withAppendedId()添加一个id UserDictionary内容URI。

Retrieving Data from the Provider


This section describes how to retrieve data from a provider, using the User Dictionary Provider as an example.本节描述如何从提供者检索数据,使用用户词典提供程序作为示例。

For the sake of clarity, the code snippets in this section call ContentResolver.query() on the "UI thread"". In actual code, however, you should do queries asynchronously on a separate thread. One way to do this is to use the CursorLoader class, which is described in more detail in the Loadersguide. Also, the lines of code are snippets only; they don‘t show a complete application.

为了清晰,本节中的代码段调用ContentResolver.query“UI线程上的()。然而,在实际的代码,你应该做一个独立的线程上异步查询。一种方法是使用CursorLoader类,这是Loadersguide更详细地描述。也,行代码片段;他们不显示一个完整的应用程序。

To retrieve data from a provider, follow these basic steps:

检索的数据提供者,遵循这些基本步骤:

  1. Request the read access permission for the provider.供应商请求读访问权限。
  2. Define the code that sends a query to the provider.定义的代码将查询发送到提供者。

Requesting read access permission请求读访问权限

To retrieve data from a provider, your application needs "read access permission" for the provider. You can‘t request this permission at run-time; instead, you have to specify that you need this permission in your manifest, using the <uses-permission> element and the exact permission name defined by the provider. When you specify this element in your manifest, you are in effect "requesting" this permission for your application. When users install your application, they implicitly grant this request.

检索的数据提供者,您的应用程序需要“读访问权限”提供者。你不能请求允许在运行时;相反,您必须指定你需要这个权限清单,使用< uses-permission >元素和确切的权限名称定义的提供者。当你在清单中指定这个元素时,你实际上是“请求”这允许您的应用程序。当用户安装应用程序时,他们隐式授予此请求。

To find the exact name of the read access permission for the provider you‘re using, as well as the names for other access permissions used by the provider, look in the provider‘s documentation.找到准确的读访问权限的名称您所使用的提供者,以及其他访问权限的名称使用的供应商,看看提供者的文档。

The role of permissions in accessing providers is described in more detail in the section Content Provider Permissions.

权限访问提供商的角色是更详细地描述部分内容提供者权限。

The User Dictionary Provider defines the permission android.permission.READ_USER_DICTIONARY in its manifest file, so an application that wants to read from the provider must request this permission.用户词典提供程序定义了android.permission许可。READ_USER_DICTIONARY清单文件,所以想读的应用程序从提供者必须请求许可。

Constructing the query构建查询

The next step in retrieving data a provider is to construct a query. This first snippet defines some variables for accessing the User Dictionary Provider:检索数据提供者的下一步是构建一个查询。第一个片段定义了一些变量来访问用户词典提供程序:


// A "projection" defines the columns that will be returned for each row
String[] mProjection =
{
   
UserDictionary.Words._ID,    // Contract class constant for the _ID column name
   
UserDictionary.Words.WORD,   // Contract class constant for the word column name
   
UserDictionary.Words.LOCALE  // Contract class constant for the locale column name
};

// Defines a string to contain the selection clause
String mSelectionClause =null;

// Initializes an array to contain selection arguments
String[] mSelectionArgs ={""};

The next snippet shows how to use ContentResolver.query(), using the User Dictionary Provider as an example. A provider client query is similar to an SQL query, and it contains a set of columns to return, a set of selection criteria, and a sort order.

下一个代码片段展示了如何使用ContentResolver.query(),使用用户词典提供程序作为示例。提供客户端查询类似于SQL查询,它包含一组列返回,一组选择标准,和排序顺序。

The set of columns that the query should return is called a projection (the variable mProjection).查询的列集应该返回称为投影(变量mProjection)。

The expression that specifies the rows to retrieve is split into a selection clause and selection arguments. The selection clause is a combination of logical and Boolean expressions, column names, and values (the variable mSelectionClause). If you specify the replaceable parameter ? instead of a value, the query method retrieves the value from the selection arguments array (the variablemSelectionArgs).

检索表达式,指定行分为选择条款和选择参数。选择子句的组合逻辑、布尔表达式列名称和值(变量mSelectionClause)。如果你指定可替换的参数?而不是一个值,查询方法检索的值选择参数数组(variablemSelectionArgs)。

In the next snippet, if the user doesn‘t enter a word, the selection clause is set to null, and the query returns all the words in the provider. If the user enters a word, the selection clause is set to UserDictionary.Words.WORD + " = ?" and the first element of selection arguments array is set to the word the user enters.

在下一个代码片段,如果用户不输入一个单词,选择条款设置为空,查询返回所有单词的提供者。如果用户输入一个单词,设置选择条件是UserDictionary.Words.WORD + " = ?"和选择参数数组的第一个元素设置为用户输入这个词。

/*
 * This defines a one-element String array to contain the selection argument.
 */
String[] mSelectionArgs ={""};

// Gets a word from the UI
mSearchString
= mSearchWord.getText().toString();

// Remember to insert code here to check for invalid or malicious input.

// If the word is the empty string, gets everything
if(TextUtils.isEmpty(mSearchString)){
   
// Setting the selection clause to null will return all words
    mSelectionClause
=null;
    mSelectionArgs
[0]="";

}else{
   
// Constructs a selection clause that matches the word that the user entered.
    mSelectionClause
=UserDictionary.Words.WORD +" = ?";

   
// Moves the user‘s input string to the selection arguments.
    mSelectionArgs
[0]= mSearchString;

}

// Does a query against the table and returns a Cursor object
mCursor
= getContentResolver().query(
   
UserDictionary.Words.CONTENT_URI,  // The content URI of the words table
    mProjection
,                       // The columns to return for each row
    mSelectionClause                  
// Either null, or the word the user entered
    mSelectionArgs
,                    // Either empty, or the string the user entered
    mSortOrder
);                       // The sort order for the returned rows

// Some providers return null if an error occurs, others throw an exception
if(null== mCursor){
   
/*
     * Insert code here to handle the error. Be sure not to use the cursor! You may want to
     * call android.util.Log.e() to log this error.
     *
     */
// If the Cursor is empty, the provider found no matches
}elseif(mCursor.getCount()<1){

   
/*
     * Insert code here to notify the user that the search was unsuccessful. This isn‘t necessarily
     * an error. You may want to offer the user the option to insert a new row, or re-type the
     * search term.
     */

}else{
   
// Insert code here to do something with the results

}

This query is analogous to the SQL statement:这个查询的方法是类似于SQL语句

SELECT _ID, word, locale FROM words WHERE word =<userinput> ORDER BY word ASC;

In this SQL statement, the actual column names are used instead of contract class constants.在这个SQL语句,使用实际的列名而不是合同类的常量。

Protecting against malicious input防止恶意输入

If the data managed by the content provider is in an SQL database, including external untrusted data into raw SQL statements can lead to SQL injection.如果由内容提供者的数据是在一个SQL数据库,包括外部不可信数据为原始SQL语句会导致SQL注入。

Consider this selection clause:考虑这个选择条款:

// Constructs a selection clause by concatenating the user‘s input to the column name
String mSelectionClause =  "var = "+ mUserInput;

If you do this, you‘re allowing the user to concatenate malicious SQL onto your SQL statement. For example, the user could enter "nothing; DROP TABLE *;" for mUserInput, which would result in the selection clause var = nothing; DROP TABLE *;. Since the selection clause is treated as an SQL statement, this might cause the provider to erase all of the tables in the underlying SQLite database (unless the provider is set up to catch SQL injection attempts).

如果你这样做,你恶意SQL允许用户连接到您的SQL语句。例如,用户可以输入“什么;删除表*”mUserInput,这将导致选择条款var =什么;表*;下降。自从选择条款被视为一个SQL语句,这可能导致供应商消除底层SQLite数据库中所有的表(除非提供者设置捕获SQL注入的尝试)。

To avoid this problem, use a selection clause that uses ? as a replaceable parameter and a separate array of selection arguments. When you do this, the user input is bound directly to the query rather than being interpreted as part of an SQL statement. Because it‘s not treated as SQL, the user input can‘t inject malicious SQL. Instead of using concatenation to include the user input, use this selection clause:

为了避免这个问题,使用选择条款,使用?作为一个可替换的参数选择和一个单独的数组参数。当你这样做时,用户输入直接绑定到查询而不是被解释为一个SQL语句的一部分。因为它不是作为SQL,用户输入不能注入恶意SQL。而不是使用连接包括用户输入,选择使用这个条款:

// Constructs a selection clause with a replaceable parameter
String mSelectionClause =  "var = ?";

Set up the array of selection arguments like this:建立了一系列的选择参数如下:

// Defines an array to contain the selection arguments
String[] selectionArgs ={""};

Put a value in the selection arguments array like this:把选择的参数数组中的值如下:

// Sets the selection argument to the user‘s input
selectionArgs
[0]= mUserInput;

A selection clause that uses ? as a replaceable parameter and an array of selection arguments array are preferred way to specify a selection, even if the provider isn‘t based on an SQL database.选择使用条款?作为一个可替换的参数和选择参数数组的数组是首选方法指定一个选择,即使提供者不是基于SQL数据库。

Displaying query results显示查询结果

The ContentResolver.query() client method always returns a Cursor containing the columns specified by the query‘s projection for the rows that match the query‘s selection criteria. A Cursor object provides random read access to the rows and columns it contains. Using Cursor methods, you can iterate over the rows in the results, determine the data type of each column, get the data out of a column, and examine other properties of the results. Some Cursor implementations automatically update the object when the provider‘s data changes, or trigger methods in an observer object when the Cursor changes, or both.

ContentResolver.query()客户机方法总是返回包含指定的列的游标查询的行投影匹配查询的选择标准。一个游标对象提供了随机读取访问它所包含的行和列。使用光标的方法,可以遍历行结果,确定每一列的数据类型,获取数据的列,并检查其他属性的结果。一些指针实现自动更新对象当提供者的数据发生变化时,或触发方法在一个观察者对象当光标变化时,或两者兼而有之。

Note: A provider may restrict access to columns based on the nature of the object making the query. For example, the Contacts Provider restricts access for some columns to sync adapters, so it won‘t return them to an activity or service.

注意:提供者可能限制列基于对象的性质进行查询。例如,联系供应商限制访问一些列同步适配器,所以它不会返回一个活动或服务。

If no rows match the selection criteria, the provider returns a Cursor object for whichCursor.getCount() is 0 (an empty cursor).

如果没有行匹配选择条件,提供程序返回一个游标对象whichCursor.getCount()0(空指针)。

If an internal error occurs, the results of the query depend on the particular provider. It may choose to return null, or it may throw an Exception.如果发生内部错误,查询的结果依赖于特定的提供者。它可以选择返回null,或者它可能抛出异常。

Since a Cursor is a "list" of rows, a good way to display the contents of a Cursor is to link it to a ListView via a SimpleCursorAdapter.

The following snippet continues the code from the previous snippet. It creates a SimpleCursorAdapterobject containing the Cursor retrieved by the query, and sets this object to be the adapter for aListView:由于一个游标是一个“列表”的行,显示游标的内容的一个好方法是通过SimpleCursorAdapter链接到列表视图。
以下代码片段继续前面的代码片段。它创建一个包含光标SimpleCursorAdapterobject检索查询,并设置该对象为aListView适配器:

// Defines a list of columns to retrieve from the Cursor and load into an output row
String[] mWordListColumns =
{
   
UserDictionary.Words.WORD,   // Contract class constant containing the word column name
   
UserDictionary.Words.LOCALE  // Contract class constant containing the locale column name
};

// Defines a list of View IDs that will receive the Cursor columns for each row
int[] mWordListItems ={ R.id.dictWord, R.id.locale};

// Creates a new SimpleCursorAdapter
mCursorAdapter
=newSimpleCursorAdapter(
    getApplicationContext
(),               // The application‘s Context object
    R
.layout.wordlistrow,                  // A layout in XML for one row in the ListView
    mCursor
,                               // The result from the query
    mWordListColumns
,                      // A string array of column names in the cursor
    mWordListItems
,                        // An integer array of view IDs in the row layout
   
0);                                    // Flags (usually none are needed)

// Sets the adapter for the ListView
mWordList
.setAdapter(mCursorAdapter);

Note: To back a ListView with a Cursor, the cursor must contain a column named _ID. Because of this, the query shown previously retrieves the _ID column for the "words" table, even though theListView doesn‘t display it. This restriction also explains why most providers have a _ID column for each of their tables.

注:支持列表视图与光标,光标必须包含一个列名叫_ID。正因为如此,先前的查询检索_ID列“单词”表,即使theListView不会显示它。这种限制也解释了为什么大多数供应商都有_ID为每个表的列。

Getting data from query results  获取数据的查询结果

Rather than simply displaying query results, you can use them for other tasks. For example, you can retrieve spellings from the user dictionary and then look them up in other providers. To do this, you iterate over the rows in the Cursor:

而不是简单地显示查询结果,您可以使用它们为其他任务。例如,您可以从用户检索拼写字典,然后看他们在其他供应商。要做到这一点,您遍历游标的行:

// Determine the column index of the column named "word"  确定列索引的列命名为“单词”
int index = mCursor.getColumnIndex(UserDictionary.Words.WORD);

/*
 * Only executes if the cursor is valid. The User Dictionary Provider returns null if
 * an internal error occurs. Other providers may throw an Exception instead of returning null.
 */

if (mCursor != null) {
    /*
     * Moves to the next row in the cursor. Before the first movement in the cursor, the
     * "row pointer" is -1, and if you try to retrieve data at that position you will get an
     * exception.
     */
    while (mCursor.moveToNext()) {

        // Gets the value from the column.
        newWord = mCursor.getString(index);

        // Insert code here to process the retrieved word.

        ...

        // end of while loop
    }
} else {

    // Insert code here to report an error if the cursor is null or the provider threw an exception.
}

Cursor implementations contain several "get" methods for retrieving different types of data from the object. For example, the previous snippet uses getString(). They also have a getType() method that returns a value indicating the data type of the column.

游标实现包含多个“获得”的方法获取不同类型的数据对象。例如,前面的代码片段使用getString()。他们也有一个方法()方法,它返回一个值指示该列的数据类型。

Content Provider Permissions


A provider‘s application can specify permissions that other applications must have in order to access the provider‘s data. These permissions ensure that the user knows what data an application will try to access. Based on the provider‘s requirements, other applications request the permissions they need in order to access the provider. End users see the requested permissions when they install the application.

提供商的应用程序可以指定权限,其他应用程序必须以访问提供者的数据。这些权限,确保用户知道数据应用程序将尝试访问。根据供应商的要求,其他应用程序请求所需的权限来访问提供者。最终用户安装应用程序时看到请求的权限。

If a provider‘s application doesn‘t specify any permissions, then other applications have no access to the provider‘s data. However, components in the provider‘s application always have full read and write access, regardless of the specified permissions.

As noted previously, the User Dictionary Provider requires the android.permission.READ_USER_DICTIONARY permission to retrieve data from it. The provider has the separate android.permission.WRITE_USER_DICTIONARY permission for inserting, updating, or deleting data.

如果一个供应商的应用程序不指定任何权限,然后其他应用程序没有对提供者的数据的访问。然而,组件提供商的应用程序总是完整的读和写访问,无论指定的权限。
如前所述,用户词典提供程序需要android.permission。READ_USER_DICTIONARY许可从中检索数据。供应商有android.permission分开。WRITE_USER_DICTIONARY允许插入、更新或删除数据。

To get the permissions needed to access a provider, an application requests them with a <uses-permission> element in its manifest file. When the Android Package Manager installs the application, a user must approve all of the permissions the application requests. If the user approves all of them, Package Manager continues the installation; if the user doesn‘t approve them, Package Manager aborts the installation.

获得所需的权限访问提供者,一个应用程序请求他们< uses-permission >元素的清单文件。Android包管理器安装应用程序时,用户必须批准所有的应用程序请求的权限。如果用户批准所有的包管理器继续安装;如果用户不批准,包管理器中止安装。

The following <uses-permission> element requests read access to the User Dictionary Provider:

以下< uses-permission >元素请求读访问权的用户词典提供程序:

    <uses-permission android:name="android.permission.READ_USER_DICTIONARY">

The impact of permissions on provider access is explained in more detail in the Security and Permissions guide.

提供者访问权限的影响将更加详细地解释安全和权限指南。

Inserting, Updating, and Deleting Data


In the same way that you retrieve data from a provider, you also use the interaction between a provider client and the provider‘s ContentProvider to modify data. You call a method of ContentResolver with arguments that are passed to the corresponding method of ContentProvider. The provider and provider client automatically handle security and inter-process communication.

以同样的方式,你从提供者检索数据,您还可以使用提供者之间的交互的客户端和提供者的ContentProvider修改数据。您调用ContentResolver方法参数传递到相应的方法的内容提供者。提供者和提供者端自动处理安全与进程间通信。

Inserting data

To insert data into a provider, you call the ContentResolver.insert() method. This method inserts a new row into the provider and returns a content URI for that row. This snippet shows how to insert a new word into the User Dictionary Provider:

将数据插入一个提供者,你叫ContentResolver.insert()方法。这种方法将一个新行插入该行的内容提供者和返回一个URI。这个代码片段展示了如何将一个新单词插入到用户词典提供程序:

// Defines a new Uri object that receives the result of the insertion
Uri mNewUri;

...

// Defines an object to contain the new values to insert
ContentValues mNewValues = new ContentValues();

/*
 * Sets the values of each column and inserts the word. The arguments to the "put"
 * method are "column name" and "value"
 */
mNewValues.put(UserDictionary.Words.APP_ID, "example.user");
mNewValues.put(UserDictionary.Words.LOCALE, "en_US");
mNewValues.put(UserDictionary.Words.WORD, "insert");
mNewValues.put(UserDictionary.Words.FREQUENCY, "100");

mNewUri = getContentResolver().insert(
    UserDictionary.Word.CONTENT_URI,   // the user dictionary content URI
    mNewValues                          // the values to insert
);

The data for the new row goes into a single ContentValues object, which is similar in form to a one-row cursor. The columns in this object don‘t need to have the same data type, and if you don‘t want to specify a value at all, you can set a column to null using ContentValues.putNull().

的数据进入一个新行ContentValues对象,在形式上类似于一行光标。这个对象不需要的列有相同的数据类型,如果你不想指定一个值,您可以使用ContentValues.putNull列设置为null()。

The snippet doesn‘t add the _ID column, because this column is maintained automatically. The provider assigns a unique value of _ID to every row that is added. Providers usually use this value as the table‘s primary key.

代码片段不添加_ID列,因为这列是自动维护。_ID的提供者分配一个独特的价值,每一行添加。供应商通常使用该值作为表的主键。

The content URI returned in newUri identifies the newly-added row, with the following format:

内容的URI中返回(newUri识别新添加的行,使用以下格式:

content://user_dictionary/words/<id_value>

The <id_value> is the contents of _ID for the new row. Most providers can detect this form of content URI automatically and then perform the requested operation on that particular row.

< id_value >的内容是_ID新行。大多数提供者可以探测到这种形式的内容自动URI,然后执行所请求的操作,特定的行。

To get the value of _ID from the returned Uri, call ContentUris.parseId().

获得的价值_ID从返回的Uri,叫ContentUris.parseId()。

Updating data

To update a row, you use a ContentValues object with the updated values just as you do with an insertion, and selection criteria just as you do with a query. The client method you use is ContentResolver.update(). You only need to add values to the ContentValues object for columns you‘re updating. If you want to clear the contents of a column, set the value to null.

更新一行,您使用一个ContentValues对象与更新的值就像你插入,和选择标准,正如你查询。客户端使用方法ContentResolver.update()。你只需要将值添加到ContentValues对象列你更新。如果你想清楚的列的内容,将值设置为null。

The following snippet changes all the rows whose locale has the language "en" to a have a locale of null. The return value is the number of rows that were updated:

以下代码片段变化的地区语言的所有行“en”有一个空的区域。返回值是被更新的行数:

// Defines an object to contain the updated values
ContentValues mUpdateValues = new ContentValues();

// Defines selection criteria for the rows you want to update
String mSelectionClause = UserDictionary.Words.LOCALE +  "LIKE ?";
String[] mSelectionArgs = {"en_%"};

// Defines a variable to contain the number of updated rows
int mRowsUpdated = 0;

...

/*
 * Sets the updated value and updates the selected words.
 */
mUpdateValues.putNull(UserDictionary.Words.LOCALE);

mRowsUpdated = getContentResolver().update(
    UserDictionary.Words.CONTENT_URI,   // the user dictionary content URI
    mUpdateValues                       // the columns to update
    mSelectionClause                    // the column to select on
    mSelectionArgs                      // the value to compare to
);

You should also sanitize user input when you call ContentResolver.update(). To learn more about this, read the section Protecting against malicious input.

你也应该当你叫ContentResolver.update清洁用户输入()。要了解更多,请阅读部分防止恶意的输入。

Deleting data

Deleting rows is similar to retrieving row data: you specify selection criteria for the rows you want to delete and the client method returns the number of deleted rows. The following snippet deletes rows whose appid matches "user". The method returns the number of deleted rows.

删除行类似于检索行数据:你指定行你想删除的选择标准和客户方法返回删除的行数。以下代码片段删除行appid匹配的“用户”。该方法返回删除的行数。
// Defines selection criteria for the rows you want to delete
String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?";
String[] mSelectionArgs = {"user"};

// Defines a variable to contain the number of rows deleted
int mRowsDeleted = 0;

...

// Deletes the words that match the selection criteria
mRowsDeleted = getContentResolver().delete(
    UserDictionary.Words.CONTENT_URI,   // the user dictionary content URI
    mSelectionClause                    // the column to select on
    mSelectionArgs                      // the value to compare to
);

You should also sanitize user input when you call ContentResolver.delete(). To learn more about this, read the section Protecting against malicious input.

你也应该当你叫ContentResolver.delete清洁用户输入()。要了解更多,请阅读部分防止恶意的输入。

Provider Data Types


Content providers can offer many different data types. The User Dictionary Provider offers only text, but providers can also offer the following formats:

内容提供商可以提供许多不同的数据类型。用户词典提供程序只提供文本,供应商也可以提供以下格式:

  • integer 
  • long integer (long)
  • floating point
  • long floating point (double)

Another data type that providers often use is Binary Large OBject (BLOB) implemented as a 64KB byte array. You can see the available data types by looking at the Cursor class "get" methods.

另一个供应商经常使用的数据类型是二进制大对象(BLOB)实现为一个64 kb的字节数组。你可以看到可用的数据类型通过查看光标类“获得”方法。

The data type for each column in a provider is usually listed in its documentation. The data types for the User Dictionary Provider are listed in the reference documentation for its contract class UserDictionary.Words (contract classes are described in the section Contract Classes). You can also determine the data type by calling Cursor.getType().

每一列的数据类型提供者通常列在其文档。数据类型为用户词典提供程序中列出UserDictionary合同类的参考文档。单词(合同类所描述的部分合同类)。您也可以通过调用Cursor.getType确定数据类型()。

Providers also maintain MIME data type information for each content URI they define. You can use the MIME type information to find out if your application can handle data that the provider offers, or to choose a type of handling based on the MIME type. You usually need the MIME type when you are working with a provider that contains complex data structures or files. For example, the ContactsContract.Data table in the Contacts Provider uses MIME types to label the type of contact data stored in each row. To get the MIME type corresponding to a content URI, call ContentResolver.getType().

提供者也维护MIME数据类型信息为每个URI定义内容。您可以使用MIME类型信息找出如果您的应用程序可以处理的数据提供者提供,或选择一个类型的处理基于MIME类型。你通常需要MIME类型正在与一个提供者,其中包含复杂的数据结构或文件。例如,ContactsContract。数据表中的联系人提供程序使用MIME类型标签接触每一行中存储的数据的类型。MIME类型的对应内容URI,叫ContentResolver.getType()。

The section MIME Type Reference describes the syntax of both standard and custom MIME types.

MIME类型引用部分描述的语法标准和定制的MIME类型。

Alternative Forms of Provider Access


Three alternative forms of provider access are important in application development:

三个可选形式的提供者访问是重要的在应用程序开发:

  • Batch access: You can create a batch of access calls with methods in the ContentProviderOperation class, and then apply them with ContentResolver.applyBatch().
  • 批量访问:您可以创建一个批处理ContentProviderOperation访问调用方法的类,然后将它们应用ContentResolver.applyBatch()。
  • Asynchronous queries: You should do queries in a separate thread. One way to do this is to use a CursorLoader object. The examples in the Loaders guide demonstrate how to do this.
  • 你要做异步查询:查询在一个单独的线程。一种方法是使用一个CursorLoader对象。加载器指南中的示例演示如何做到这一点。
  • Data access via intents: Although you can‘t send an intent directly to a provider, you can send an intent to the provider‘s application, which is usually the best-equipped to modify the provider‘s data.
  • 数据访问通过意图:虽然你不能发送一个意图直接提供者,您可以发送一个意图提供者的应用程序中,这通常是装备修改提供者的数据。

Batch access and modification via intents are described in the following sections.

批通过意图访问和修改以下部分中描述。

Batch access

Batch access to a provider is useful for inserting a large number of rows, or for inserting rows in multiple tables in the same method call, or in general for performing a set of operations across process boundaries as a transaction (an atomic operation).

批量访问提供者用于插入大量的行,或者在多个表中插入行相同的方法调用,或一般跨进程执行的一组操作作为一个事务(一个原子操作)。

To access a provider in "batch mode", you create an array of ContentProviderOperation objects and then dispatch them to a content provider with ContentResolver.applyBatch(). You pass the content provider‘s authority to this method, rather than a particular content URI. This allows each ContentProviderOperation object in the array to work against a different table. A call to ContentResolver.applyBatch() returns an array of results.

访问供应商在“批处理模式”,你创建ContentProviderOperation对象数组,然后分派到内容提供商与ContentResolver.applyBatch()。您通过此方法的内容提供者的权威,而不是一个特定的内容URI。这允许每个ContentProviderOperation对象数组中针对不同的工作表。调用ContentResolver.applyBatch()返回一个数组的结果。

The description of the ContactsContract.RawContacts contract class includes a code snippet that demonstrates batch insertion. The Contact Manager sample application contains an example of batch access in its ContactAdder.java source file.

ContactsContract的描述。RawContacts合同类包含一个代码片段,展示了批量插入。联系人管理器的示例应用程序包含一个例子ContactAdder批访问。java源文件。

Displaying data using a helper app

If your application does have access permissions, you still may want to use an intent to display data in another application. For example, the Calendar application accepts an ACTION_VIEW intent, which displays a particular date or event. This allows you to display calendar information without having to create your own UI. To learn more about this feature, see the Calendar Provider guide.

如果您的应用程序有访问权限,你仍然可能想要使用一个意图在另一个应用程序来显示数据。例如,日历应用程序接受一个ACTION_VIEW意图,它显示一个特定的日期或事件。这允许您显示日历信息,而不必创建您自己的用户界面。更多地了解这一特性,看到日历提供指南。

The application to which you send the intent doesn‘t have to be the application associated with the provider. For example, you can retrieve a contact from the Contact Provider, then send an ACTION_VIEW intent containing the content URI for the contact‘s image to an image viewer.

您的应用程序发送目的不一定要与提供者相关联的应用程序。例如,您可以检索一个联系人的联系供应商,然后发送一个ACTION_VIEW意图包含URI的内容联系到一个图像查看器的形象。

Data access via intents

Intents can provide indirect access to a content provider. You allow the user to access data in a provider even if your application doesn‘t have access permissions, either by getting a result intent back from an application that has permissions, or by activating an application that has permissions and letting the user do work in it.

意图可以提供间接访问内容提供者。你允许用户访问数据的应用程序提供者即使没有访问权限,通过获得一个结果意图从一个应用程序,该应用程序权限,或通过激活的应用程序的权限,让用户完成工作。

Getting access with temporary permissions

You can access data in a content provider, even if you don‘t have the proper access permissions, by sending an intent to an application that does have the permissions and receiving back a result intent containing "URI" permissions. These are permissions for a specific content URI that last until the activity that receives them is finished. The application that has permanent permissions grants temporary permissions by setting a flag in the result intent:

您可以访问的数据在一个内容提供者,即使你没有适当的访问权限,通过发送一个意图有权限的应用程序和接收返回结果的意图包含“URI”权限。这些权限具体内容URI持续到接收完成他们的活动。永久权限授予临时权限的应用程序通过设置一个标记在结果的意图:

  • Read permission: FLAG_GRANT_READ_URI_PERMISSION
  • Write permission: FLAG_GRANT_WRITE_URI_PERMISSION

Note: These flags don‘t give general read or write access to the provider whose authority is contained in the content URI. The access is only for the URI itself.

注意:这些旗帜不给一般读或写访问提供者的权威是URI中包含的内容。的访问只是URI本身。

A provider defines URI permissions for content URIs in its manifest, using the android:grantUriPermission attribute of the<provider> element, as well as the <grant-uri-permission> child element of the <provider> element. The URI permissions mechanism is explained in more detail in the Security and Permissions guide, in the section "URI Permissions".

提供者定义URI URI的权限内容清单,使用android:grantUriPermission <供应商>元素的属性,以及< grant-uri-permission > <供应商>元素的子元素。URI的权限机制更详细地解释在安全性和权限指引,在部分“URI权限”。

For example, you can retrieve data for a contact in the Contacts Provider, even if you don‘t have the READ_CONTACTS permission. You might want to do this in an application that sends e-greetings to a contact on his or her birthday. Instead of requesting READ_CONTACTS, which gives you access to all of the user‘s contacts and all of their information, you prefer to let the user control which contacts are used by your application. To do this, you use the following process:

例如,您可以检索数据的接触联系供应商,即使你没有READ_CONTACTS许可。你可能想这样做在一个应用程序,该应用程序发送e-greetings联系在他或她的生日。而不是请求READ_CONTACTS,它给你访问所有用户的接触和他们所有的信息,你喜欢让用户控制哪些联系人使用您的应用程序。要做到这一点,您使用以下过程:

  1. Your application sends an intent containing the action ACTION_PICK and the "contacts" MIME type CONTENT_ITEM_TYPE, using the method startActivityForResult().
  2. 您的应用程序发送一个包含动作的意图ACTION_PICK CONTENT_ITEM_TYPE“联系人”MIME类型,使用方法startActivityForResult()。
  3. Because this intent matches the intent filter for the People app‘s "selection" activity, the activity will come to the foreground.
  4. 因为这个目的与意图过滤器匹配的人应用的“选择”的活动,活动将出现在前台。
  5. In the selection activity, the user selects a contact to update. When this happens, the selection activity callssetResult(resultcode, intent) to set up a intent to give back to your application. The intent contains the content URI of the contact the user selected, and the "extras" flags FLAG_GRANT_READ_URI_PERMISSION. These flags grant URI permission to your app to read data for the contact pointed to by the content URI. The selection activity then calls finish() to return control to your application.
  6. 在选择活动,用户选择一个联系人更新。当这一切发生的时候,选择活动callssetResult(resultcode意图)建立一个意图回馈您的应用程序。目的包含的内容URI联系用户选中,和“临时演员”旗帜FLAG_GRANT_READ_URI_PERMISSION。这些旗帜格兰特URI允许应用程序读取数据的接触URI指向的内容。选择活动然后调用完成()返回控制您的应用程序。
  7. Your activity returns to the foreground, and the system calls your activity‘s onActivityResult() method. This method receives the result intent created by the selection activity in the People app.
  8. 活动回到前台,和系统调用活动的onActivityResult()方法。这个方法接收结果的意图由人民选择活动应用程序。
  9. With the content URI from the result intent, you can read the contact‘s data from the Contacts Provider, even though you didn‘t request permanent read access permission to the provider in your manifest. You can then get the contact‘s birthday information or his or her email address and then send the e-greeting.
  10. 内容从结果URI的意图,你可以阅读从联系人联系的数据提供者,即使你没有请求永久读访问权限清单中的供应商。然后您可以获取联系人的生日信息或他或她的电子邮件地址,然后发送e-greeting。

Using another application

A simple way to allow the user to modify data to which you don‘t have access permissions is to activate an application that has permissions and let the user do the work there.

一个简单的方法,以允许用户修改数据,你没有访问权限是激活的应用程序的权限,让用户做这项工作。

For example, the Calendar application accepts an ACTION_INSERT intent, which allows you to activate the application‘s insert UI. You can pass "extras" data in this intent, which the application uses to pre-populate the UI. Because recurring events have a complex syntax, the preferred way of inserting events into the Calendar Provider is to activate the Calendar app with anACTION_INSERT and then let the user insert the event there.

例如,日历应用程序接受一个ACTION_INSERT意图,它允许您启动应用程序的UI插入。你可以通过“临时演员”数据在这个意图,该应用程序使用预填充UI。因为重复事件有一个复杂的语法,将事件插入日历提供者的首选方法是激活anACTION_INSERT的日历应用程序,然后让用户插入事件。

Contract Classes


A contract class defines constants that help applications work with the content URIs, column names, intent actions, and other features of a content provider. Contract classes are not included automatically with a provider; the provider‘s developer has to define them and then make them available to other developers. Many of the providers included with the Android platform have corresponding contract classes in the package android.provider.

合同类定义常量,帮助应用程序与内容uri,列名,意图行动,内容提供商和其他特性。合同类不包括自动与提供者;提供者的开发人员定义他们,然后让他们提供给其他开发人员。许多Android平台的提供者包括类的包android.provider相应合同。

For example, the User Dictionary Provider has a contract class UserDictionary containing content URI and column name constants. The content URI for the "words" table is defined in the constant UserDictionary.Words.CONTENT_URI. The UserDictionary.Words class also contains column name constants, which are used in the example snippets in this guide. For example, a query projection can be defined as:

例如,用户词典提供程序有一个合同类UserDictionary URI和列名称常量包含内容。URI的内容“单词”表中定义的常数UserDictionary.Words.CONTENT_URI。UserDictionary。文字类还包含列名常量,用于本指南中的示例代码片段。例如,一个查询投影可以定义为:

String[] mProjection =
{
    UserDictionary.Words._ID,
    UserDictionary.Words.WORD,
    UserDictionary.Words.LOCALE
};

Another contract class is ContactsContract for the Contacts Provider. The reference documentation for this class includes example code snippets. One of its subclasses, ContactsContract.Intents.Insert, is a contract class that contains constants for intents and intent data.

另一个合同类是接触ContactsContract提供者。这个类的参考文档包括示例代码片段。它的一个子类,ContactsContract.Intents。插入、是一个合同类,包含意图和目的的常量数据。

MIME Type Reference


Content providers can return standard MIME media types, or custom MIME type strings, or both.

MIME types have the format

内容提供者可以返回标准的MIME媒体类型,或自定义MIME类型字符串,或两者兼而有之。
MIME类型的格式

type/subtype

For example, the well-known MIME type text/html has the text type and the html subtype. If the provider returns this type for a URI, it means that a query using that URI will return text containing HTML tags.

例如,著名的MIME类型text / html文本类型和子类型的html。如果提供者返回这种类型的URI,它意味着一个查询使用这个URI将返回包含HTML标记文本。

Custom MIME type strings, also called "vendor-specific" MIME types, have more complex type and subtype values. The type value is always

定制的MIME类型字符串,也称为“特定于供应商的”MIME类型,有更复杂的类型和子类型值。值类型总是

vnd.android.cursor.dir

for multiple rows, or

vnd.android.cursor.item

for a single row.

单个行。

The subtype is provider-specific. The Android built-in providers usually have a simple subtype. For example, the when the Contacts application creates a row for a telephone number, it sets the following MIME type in the row:

特定于提供程序的子类型。Android内置提供者通常有一个简单的亚型。例如,当联系人应用程序创建一行电话号码,它集以下行MIME类型:

vnd.android.cursor.item/phone_v2

Notice that the subtype value is simply phone_v2.

注意,只是phone_v2子类型值。

Other provider developers may create their own pattern of subtypes based on the provider‘s authority and table names. For example, consider a provider that contains train timetables. The provider‘s authority is com.example.trains, and it contains the tables Line1, Line2, and Line3. In response to the content URI

其他供应商开发人员可以创建自己的模式基于提供者的亚型的权威和表名。例如,考虑一个提供者包含列车时刻表。是com.example提供者的权威。火车,它包含表Line1期,Line3。为了应对内容URI

content://com.example.trains/Line1

for table Line1, the provider returns the MIME type

对于表Line1,提供者返回的MIME类型

vnd.android.cursor.dir/vnd.example.line1

In response to the content URI

为了应对内容URI

content://com.example.trains/Line2/5

for row 5 in table Line2, the provider returns the MIME type

表5为行Line2,提供者返回的MIME类型

vnd.android.cursor.item/vnd.example.line2

Most content providers define contract class constants for the MIME types they use. The Contacts Provider contract class ContactsContract.RawContacts, for example, defines the constant CONTENT_ITEM_TYPE for the MIME type of a single raw contact row.

大部分内容提供商为MIME类型定义合同类常量。联系人ContactsContract提供者契约类。RawContacts,例如,定义了常数CONTENT_ITEM_TYPE MIME类型的单个原始行联系。

Content URIs for single rows are described in the section Content URIs.

内容uri uri单一行部分所描述的内容。

Except as noted, this content is licensed under Creative Commons Attribution 2.5. For details and restrictions, see the Content License.
除了如上所述,这个内容是2.5使用Creative Commons许可的归因。和限制的详细信息,请参见内容许可证。

About Android  |  Legal  |  Support

API翻译 --- Content Provider Basics

标签:

原文地址:http://blog.csdn.net/mikky_android/article/details/51943689

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!