当前位置: 代码迷 >> Android >> Android API Guides-Content Provider Basics
  详细解决方案

Android API Guides-Content Provider Basics

热度:301   发布时间:2016-04-24 11:08:49.0
Android API Guides---Content Provider Basics
内容提供者基础
在该文献
概观
访问提供商
内容的URI
从提供者检索数据
请求读取访问权限
构建查询
显示查询结果
充分利用查询结果数据
内容提供商权限
插入,更新和删除数据
插入数据
更新数据
删除数据
提供数据类型
提供接入的替代形式
访问批
意图通过数据访问
合同类
MIME类型参考
重点班
的ContentProvider
ContentResolver的
光标
乌里
相关样本
光标(人民)
光标(手机)
也可以看看
创建一个内容提供商
日历提供商
内容提供者管理存取数据的中央存储库。提供者是一个Android应用程序,它通常提供自己的用户界面与数据工作的一部分。但是,内容提供者主要是用来由其他应用程序,该访问使用提供商客户对象的提供者使用。总之,供应商和供应商的客户提供一致的,标准的接口将数据,也负责处理进程间通信和安全的数据访问。


本主题介绍了以下的基本知识:


如何内容提供商的工作。
该API使用从内容提供商检索数据。
该API使用的内容提供商插入,更新或删除数据。
促进与提供商合作,其他API功能。
概观


一种内容提供者呈现的数据向外部应用程序作为类似于在关系数据库中找到的表的一个或多个表。中的一行表示某种类型的数据的提供者收集的一个实例,并且该行中的每一列表示收集的实例数据的一个单独的片。


例如,在Android平台内置提供商之一是用户字典,其中存储的该用户想要保持非标准字的拼写。表1列出了数据可能看起来像在此提供的表格:


表1:样本用户字典表。
wordapp idfrequencylocale_ID
mapreduceuser1100en_US1
precompileruser14200fr_FR2
appletuser2225fr_CA3
constuser1255pt_BR4
intuser5100en_UK5

在表1中,每一行代表可能不是标准字典中找到的单词的实例。每一列代表该字的一些数据,如在其被第一次遇到的区域设置。列标题是存储在提供商列名。要引用行的区域,你是指其语言环境列。对于此提供程序,_ID列作为“主键”一栏提供程序自动维护。


注:不是必需的供应商,有一个主键,并且它使用_ID作为主键的列名如果存在不是必需的。但是,如果你想从一个供应商到ListView数据绑定,列名称之一已被_id。此要求中有更详细的部分显示查询结果进行说明。


访问提供者


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


该ContentResolver的对象在客户端应用程序的进程,并在拥有提供商自动处理进程间通信的应用的ContentProvider对象。的ContentProvider也作为其数据的储存库和数据的外观如表之间的抽象层。


注意:要访问提供商,应用程序通常有要求的清单文件中特定的权限。此进行更详细的部分内容提供商权限中所述


例如,要得到的话,并从用户词典提供的语言环境的列表,你叫ContentResolver.query()。查询()方法调用由用户词典提供商所定义的ContentProvider.query()方法。下面的代码行显示一个ContentResolver.query()调用:


// Queries the user dictionary and returns resultsmCursor = 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

表2显示了如何参数查询(URI,投影,选择,selectionArgs两个,中将sortOrder)匹配一个SQL SELECT语句:


query() argumentSELECT keyword/parameterNotes
UriFROM table_nameUri maps to the table in the provider named table_name.
projectioncol,col,col,...projection is an array of columns that should be included for each row retrieved.
selectionWHERE col = valueselection specifies the criteria for selecting rows.
selectionArgs(No exact equivalent. Selection arguments replace? placeholders in the selection clause.)
sortOrderORDER BYcol,col,...sortOrder specifies the order in which rows appear in the returnedCursor.

Content URIs

A含量URI是一个URI,在供应商标识数据。内容的URI包括整个提供商(其权威)的符号名和一个指向表(路径)的名称。当你调用客户端的方法来访问一个供应商一个表,表的内容是URI的参数之一。


在代码的先前行中,恒定CONTENT_URI包含用户辞典的“字”表的内容的URI。该ContentResolver的对象分析了URI的授权,并使用它经权威机构对比已知供应商的系统表来“解决”的提供者。然后,ContentResolver的可以调度查询参数正确的供应商。


该ContentProvider的使用内容的URI的路径部分来选择表格的访问。提供者通常有它暴露了每个表的路径。


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


content://user_dictionary/words

其中user_dictionary字符串是供应商的权力,和文字字符串表的路径。该字符串的内容://(该计划)始终存在,并确定这是一个内容URI。
content:// (the scheme) is always present, and identifies this as a content URI.

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

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

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


注:URI和Uri.Builder类包含从字符串的建设,形成良好的Uri对象的便捷方法。该ContentUris包含附加ID值到URI方便的方法。上面的代码片段使用withAppendedId()以一个id追加到UserDictionary内容URI。


从提供者检索数据


本节将介绍如何从一个供应商使用用户词典提供商作为一个例子检索数据。


为了清楚起见,本节中的代码片段的“UI线程”,“关于调用ContentResolver.query()。在实际的代码,但是,你应该做的查询异步在一??个单独的线程。这样做的一个方法是使用。在CursorLoader类,它被更详细地装载机指南中描述另外,代码行是唯一的代码段;他们不显示完整的应用程序。


从供应商获取数据,请按照下列基本步骤:


请求提供者的读取访问权限。
定义发送一个查询到供应商的代码。
请求读取访问权限


从供应商获取数据,您的应用需求“读访问权限”,为供应商。你不能要求在运行时此权限;相反,你必须指定你需要在你的清单此权限,使用<使用许可权>元素,由提供者定义确切的权限名称。当您在清单中指定此元素,你实际上是“要求”此权限的应用程序。当用户安装应用程序,他们含蓄同意这一请求。


要找到适合你使用的供应商,以及由供应商使用的其他访问权限的名字的读访问权限的确切名称,看供应商的文档中获得。


权限在访问提供商的作用进行更详细的部分内容提供商权限中所述。


用户词典提供者定义在其清单文件的权限android.permission.READ_USER_DICTIONARY,所以希望从提供商读取必须要求此权限的应用程序。


构建查询


在恢复数据的提供者的下一个步骤是建立一个查询。这第一个片段定义了访问用户词典提供一些变量:




// A "projection" defines the columns that will be returned for each rowString[] 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 clauseString mSelectionClause = null;// Initializes an array to contain selection argumentsString[] mSelectionArgs = {""};

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


设定该查询应返回的列被称为凸起(可变mProjection)。


指定的行检索表达式被分成选择条款和选择的参数。在选择条款是合乎逻辑和布尔表达式,列名和值(可变mSelectionClause)的组合。如果指定替换参数?代替一个值,则查询方法检索来自选择参数数组的值(变量mSelectionArgs)。


在接下来的片断,如果用户没有输入一个字,选择子句被设置为null,并且查询返回的供应商的所有单词。如果用户输入一个字,该选择子句设置为UserDictionary.Words.WORD +“=?”和选择参数的数组的第一元素被设置为用户输入的单词。


/* * This defines a one-element String array to contain the selection argument. */String[] mSelectionArgs = {""};// Gets a word from the UImSearchString = mSearchWord.getText().toString();// Remember to insert code here to check for invalid or malicious input.// If the word is the empty string, gets everythingif (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 objectmCursor = 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 exceptionif (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} else if (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}

该查询类似于SQL语句:


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

在这条SQL语句,实际列名来代替合同类常量。


防止恶意输入


如果由内容提供商管理的数据是在SQL数据库中,包括外部不可信数据成原始的SQL语句可导致SQL注入。


考虑这个选择条款:


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

如果你这样做,你让用户来连接恶意SQL到你的SQL语句。例如,用户可以输入“什么; DROP TABLE *;”对于mUserInput,这将导致在选择条款变种=无; DROP TABLE * ;.由于选择子句作为SQL语句处理,这可能会导致供应商删除所有表的底层SQLite数据库(除非提供商设置为捕获SQL注入尝试)。


为了避免这个问题,使用使用选择条款?作为可替换参数和参数选择一个单独的数组。执行此操作时,用户输入直接绑定到查询,而不是被解释为SQL语句的一部分。因为它不是为SQL处理,用户输入无法注入恶意SQL。而不是使用级联包括用户输入,使用此选择条款:


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

设置的参数选择这样的数组:


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

把一个价值选择的参数数组像这样:


// Sets the selection argument to the user's inputselectionArgs[0] = mUserInput;

使用一个选择条款?作为可替换参数和选择参数的数组的数组是优选的方式指定一个选择,即使提供者不是基于SQL数据库上。


显示查询结果


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


注意:提供者可以限制对基于使查询对象的性质列。例如,联系人提供商限制某些列同步适配器接入,所以它不会返回他们的活动或服务。


如果没有相匹配的行的选择标准,提供者将返回一个Cursor对象为其Cursor.getCount()0(空光标)。


如果发生内部错误时,查询的结果取决于特定的提供者。它可能会选择返回null,也可能抛出异常。


由于光标是一个行的“名单”,一个很好的方式来显示光标的内容是通过一个SimpleCursorAdapter将其链接到ListView。


下面的代码片段继续从前面的代码片断中的代码。它创建一个包含查询检索光标一个SimpleCursorAdapter对象,并将该对象是一个ListView适配器:


// Defines a list of columns to retrieve from the Cursor and load into an output rowString[] 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 rowint[] mWordListItems = { R.id.dictWord, R.id.locale};// Creates a new SimpleCursorAdaptermCursorAdapter = new SimpleCursorAdapter(    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 ListViewmWordList.setAdapter(mCursorAdapter);

注意:要备份一个ListView用光标,光标必须包含一个名为列_ID。正因为如此,先前显示的查询检索_ID列中“字”的表,即使在ListView不显示它。此限制也解释了为什么大多数供应商对他们的每一个表的_ID列。


充分利用查询结果数据


而不是简单地显示查询结果,你可以将它们用于其他任务。例如,你可以从用户词典中的拼写,然后看看他们在其他供应商。要做到这一点,你迭代在光标的行:




/
/ 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.}

光标实现包含用于从对象获取不同类型的数据的多个“获取”方法。例如,上面的代码片段使用的getString()。它们也有,它返回说明列的数据类型的值的的getType()方法。


内容提供商权限


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


如果一个提供商的应用程序不指定任何权限,那么其他应用程序的供应商的数据的访问权限。然而,在供应商的应用程序组件总是有充分的读写访问,无论指定的权限。


如前面所指出的,用户字典提供者要求来检索数据的android.permission.READ_USER_DICTIONARY权限。该供应商拥有插入,更新或删除数据单独android.permission.WRITE_USER_DICTIONARY许可。


为了获得访问提供所需的权限,应用程序请求他们在其清单文件中的<使用许可权>元素。当Android的包管理器安装该应用程序,用户必须批准所有权限的应用程序的请求。如果用户批准所有的人,包管理器继续安装;如果用户没有批准它们,包管理中止安装。


以下<permission>元素的请求读取访问用户词典提供者:


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

对供应商的访问权限的影响,在安全性和权限引导更详细地解释。


插入,更新和删除数据


在您从提供商检索数据以同样的方式,也可以使用一个供应商客户和提供者的ContentProvider的之间的交互来修改数据。你叫ContentResolver的与传递给ContentProvider的相应方法参数的方法。供应商和供应商客户端自动处理安全和进程间通信。


插入数据


将数据插入到一个提供者,你调用ContentResolver.insert()方法。这种方法插入一个新行到供应商,并返回该行的内容URI。这个片断显示了如何插入一个新词到用户词典提供者:


// Defines a new Uri object that receives the result of the insertionUri mNewUri;...// Defines an object to contain the new values to insertContentValues 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);

为新的行的数据进入一个单一ContentValues??对象,这是在形式到一行光标类似。在这个对象的列不必有相同的数据类型,如果你不希望在所有指定值,你可以设置一个列使用ContentValues??.putNull为空()。


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


URI中newUri返回的内容标识了新添加行,但有以下格式:


content://user_dictionary/words/<id_value>

在<ID_VALUE>是_ID的新行的内容。大多数提供商可以自动检测这种形式的内容URI,然后在那个特定的行执行所请求的操作。


要获取_ID从返回的URI的值,调用ContentUris.parseId()。


更新数据


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


下面的代码片段改变所有的区域都有语言“EN”到成为空区域的行。返回值是更新行数:


// Defines an object to contain the updated valuesContentValues mUpdateValues = new ContentValues();// Defines selection criteria for the rows you want to updateString mSelectionClause = UserDictionary.Words.LOCALE +  "LIKE ?";String[] mSelectionArgs = {"en_%"};// Defines a variable to contain the number of updated rowsint 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);

你也应该过滤用户输入,当你调用ContentResolver.update()。要了解更多关于这一点,阅读部分保护儿童不受恶意输入。


删除数据


删除行类似于检索行数据:您指定选择标准要删除的行和客户端方法返回删除的行数。下面的代码片段删除行的APPID匹配“用户”。该方法返回删除的行的数量。




// Defines selection criteria for the rows you want to deleteString mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?";String[] mSelectionArgs = {"user"};// Defines a variable to contain the number of rows deletedint mRowsDeleted = 0;...// Deletes the words that match the selection criteriamRowsDeleted = getContentResolver().delete(    UserDictionary.Words.CONTENT_URI,   // the user dictionary content URI    mSelectionClause                    // the column to select on    mSelectionArgs                      // the value to compare to);

你也应该过滤用户输入,当你调用ContentResolver.delete()。要了解更多关于这一点,阅读部分保护儿童不受恶意输入。


提供数据类型


内容提供商可以提供很多不同的数据类型。用户词典提供商只提供文字,而且供应商也可以提供以下格式:


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

该供应商经常使用的另一个数据类型是作为一个64KB字节数组执行二进制大对象(BLOB)。您可以通过查看Cursor类“得”的方法查看可用的数据类型。


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


供应商还保持每个内容的URI它们定义的MIME数据类型信息。您可以使用MIME类型的信息,以找出是否您的应用程序能够处理的数据提供程序提供,还是要选择一个类型的处理基于MIME类型的。你通常需要MIME类型,当你正在使用包含复杂的数据结构或文件的供应商合作。例如,在联系人提供的ContactsContract.Data表使用MIME类型来标记存储在每行中的联系人数据的类型。为了获得对应于内容的URI的MIME类型,调用ContentResolver.getType()。


本节MIME类型参考描述了标准和自定义MIME类型的语法。


提供接入的替代形式


供应商接入三种可供选择的形式在应用发展的重要:


批量访问:您可以创建一个批次的ContentProviderOperation类中的方法访问调用,然后用ContentResolver.applyBatch应用它们()。
异步查询:你应该做的查询,在一个单独的线程。这样做的一种方式是使用一个CursorLoader对象。装载机指南中的示例演示如何做到这一点。
通过意向数据访问:虽然你不能直接发送意图提供商,您可以发送意图供应商的应用程序,它通常是最好的装备来修改供应商的数据。
通过批量意图访问和修改在下面的章节中描述。


访问批


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


要访问“批处理模式”的供应商,创建ContentProviderOperation对象的数组,然后将它们分发到内容提供商与ContentResolver.applyBatch()。传递内容提供者的权威该方法,而不是一个特定的内容的URI。这允许阵列中的每个ContentProviderOperation目的是针对不同的表工作。到ContentResolver.applyBatch()的调用返回结果的数组。


该合同ContactsContract.RawContacts类的描述包含的代码片段演示批量插入。联系人管理器示例应用程序包含在其ContactAdder.java源文件批量访问的示例。


使用一个辅助的应用程序中显示数据


如果您的应用程序确实有访问权限,你可能仍然要使用意图在其他应用程序中显示的数据。例如,日历应用程序接受一个ACTION_VIEW意图,其中显示在特定日期或事件。这可以让你无需创建自己的UI显示日历信息。要了解更多关于此功能,请参阅日历提供指南。


向其发送的意图的应用程序不具有要与提供商相关联的应用。例如,你可以从联系人提供联系人,然后发送包含内容的URI联系人的图像的图像浏览器的ACTION_VIEW意图。
意图通过数据访问


意图可以提供给内容提供商间接访问。您让用户,可以通过得到的结果意图从具有权限的应用程序恢复访问数据提供者,即使你的应用程序没有访问权限,或激活具有权限的应用程序,让用户做工作,它。


获得临时访问权限


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


阅读权限:FLAG_GRANT_READ_URI_PERMISSION
写权限:FLAG_GRANT_WRITE_URI_PERMISSION
注意:这些标志不给一般的读取或写入访问其权威的内容中包含的URI的提供者。接入仅用于该URI本身。
提供者定义的URI权限在其清单内容的URI,使用了android:在<provider>元素的属性grantUriPermission,以及在<provider>元素的<赠款URI的权限>子元素。该URI的权限机制,在安全性和权限引导更详细的解释,参见“URI权限”。


例如,您可以在联系人提供的联系人检索数据,即使你没有READ_CONTACTS权限。您可能要为此在发送电子贺卡给他或她的生日联系人的应用程序。相反,要求READ_CONTACTS,这使您可以访问到所有用户的联系人和所有他们的信息,你宁愿让这些联系人应用程序所使用的用户控件。要做到这一点,您可以使用以下过程:


您的应用程序发送一个包含动作ACTION_PICK和“人脉”MIME类型CONTENT_ITEM_TYPE意图,使用方法startActivityForResult()。
由于这种意图对联系人应用的“评选”活动的意图过滤器相匹配,该活动将来到前台。
在选择活动,用户选择联系人更新。发生这种情况时,该评选活动调用的setResult(resultCode为,意图)建立一个意图退给你的应用程序。意图包含用户选择的接触,并且“额外”标志FLAG_GRANT_READ_URI_PERMISSION的内容的URI。这些标志授予URI允许你的应用程序的联系人指向的内容URI读取数据。然后,评选活动结束调用()将控制返回给应用程序。
您的活动返回到前台,系统调用你的活动的的onActivityResult()方法。这个方法接收由评选活动在人民创建的应用程序的结果意图。
从结果意图内容URI,您可以从联系人提供读取联系人数据,即使你没有请求永久读取访问权限,以在清单中的供应商。然后,您可以得到联系人的生日信息,或者他或她的电子邮件地址,然后发送电子贺卡。
使用其他应用程序


一个简单的方法,让用户修改到您没有访问权限的数据是激活具有权限的应用程序,让用户做的工作有。


例如,日历应用程序接受一个ACTION_INSERT意图,它允许您激活应用程序的插入UI。你可以通过“额外”数据在这个意图,该应用程序使用预先填充的UI。由于经常性的事件有复杂的语法,插入事件到日历提供商的最佳方法是使用ACTION_INSERT激活日历应用,然后让用户插入事件出现。


合同类


合同类定义帮助应用程序与内容的URI,列名,故意行为,和内容提供商等功能的工作常量。合同类不与提供者自动包括;供应商的开发人员来定义它们,然后将它们提供给其他开发商。许多包含在Android平台上的供应商在包装android.provider相应的合同类。


例如,用户词典提供具有包含内容的URI和列名常量合同类UserDictionary。对于“词”表中的内容URI在不断UserDictionary.Words.CONTENT_URI定义。该UserDictionary.Words类也包含列名的常量,这是在例如段所使用本指南的例如,查询的投影可被定义为:


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

另一份合同类是ContactsContract的联系人提供商。这个类的参考文档包括示例代码片段。它的一个子类,ContactsContract.Intents.Insert,是包含意图和意图数据常量合同类。


MIME类型参考


内容提供商可以返回标准MIME媒体类型,或自定义的MIME类型的字符串,或两者。


MIME类型的格式


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


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


vnd.android.cursor.dir
多行或


vnd.android.cursor.item
为单行。


子类型是供应商特定的。而Android内置的供应商通常有一个简单的子类型。例如,当联系人应用程序创建一个电话号码一排,它设置该行中的下列MIME类型:


vnd.android.cursor.item / phone_v2
请注意,子类值只是phone_v2。


其他供应商的开发人员可以创建自己的基于供应商的权威和表名亚型的格局。例如,考虑包含列车时刻表的供应商。提供者的权威是com.example.trains,它包含的表1号线,2号线,3号线和。响应于内容的URI


内容://com.example.trains/Line1
为表1号线,提供者将返回的MIME类型


vnd.android.cursor.dir / vnd.example.line1
响应于内容的URI


content://com.example.trains/Line2/5
在2号线表列5,提供者将返回的MIME类型


vnd.android.cursor.item / vnd.example.line2
大多数内容提供商定义他们所使用的MIME类型合同类常量。联系人提供合同类ContactsContract.RawContacts,例如,定义了MIME类型的单一原料接触行的恒定CONTENT_ITEM_TYPE。


单行内容的URI中的部分内容的URI描述。































{
    
    
    
};





































































  相关解决方案