内容提供程序管理对结构化数据集的访问,它们封装数据,并供用于定义数据安全性的机制。内容提供程序是连接一个进程中的数据与另一个进程中运行的代码的标准界面。
将应用的Context中的ContentResolver对象用作客户端来提供程序通信,可以访问内容提供程序中的数据。ContentResolver对象会实现ContentProvider的类实例通信,提供程序对象从客户端接收数据请求,执行请求的操作并返回结果。
内容提供程序以一个或多个表的形式将数据呈现给外部应用,行表示提供程序收集的某种数据类型的实例,行中的每个列表示为实例收集的。
访问提供程序
应用从具有ContentResolver客户端对象的内容提供程序访问数据,此对象具有调用提供程序对象中同名方法的方法,ContentResolver方法可提供程序存储的基本CRUD(创建,检索,更新,删除)功能。客户端应用进程中ContentResolver对象和拥有提供程序的应用中的ContentProvider对象可自动处理跨进程通信,ContentProvider还可充当其数据存储区和表格外部显示之间的抽象层。
内容URI
是用于在提供程序中表示数据的URI,包括整个提供程序的符号名称,和一个指向表的名称(路径)。ContentResolver对象会分析出URI的授权,并通过将该授权与已知提供程序的系统进行比较来解析提供程序,然后,ContentResolver可以将查血的参数分派给正确的提供程序。
ContentProvider使用内容URI的路径部分来选择要访问的表,提供程序通常会为其公开每个表显示一条路径。
例如:content://user_dictionary/words
其中user_dictionary字符串是提供程序的授权,words字符串是表的路径,字符串content://(架构)始终显示,并将此标识为内容URI
许多提供程序都允许通过将ID值追加到URI末尾来访问表中的单个行。在检索到一组行后想要更新或删除其中某一行时通常用到ID值。
Uri和Uri.Builder 类包含根据字符串构建格式规范的URI对象的便利方法,ContentUris包含一些可以将ID值追加到URI后的方法。例如:
Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI, 4);
提供程序检索数据
为了说明,本例在UI线程上调用ContentResolver.query(),但在实际代码中应该在单独线程上异步执行查询,使用CursorLoader类,按照以下两个基本操作执行
1.请求对提供程序的读取访问权限
2.定义将查询发送至提供程序的代码
在清单文件
构建查询
// 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 = {""};
查询应该返回的列集被称为投影(即变量mProjection)
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
} 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
}
如果用户未输入字词,则选择子句将设置为
null
,而且查询会返回提供程序中的所有字词。 如果用户输入了字词,选择子句将设置为
UserDictionary.Words.WORD + " = ?"
且选择参数数组的第一个元素将设置为用户输入的字词。
防止恶意输入
如果内容提供程序管理的数据位于 SQL 数据库中,将不受信任的外部数据包括在原始 SQL 语句中可能会导致 SQL 注入。
String mSelectionClause = "var = " + mUserInput;
如果执行此操作,则会允许用户将恶意SQL串连接到SQL语句上,由于选择子句是作为SQL语句处理,故可能会导致提供程序擦除基础SQLite数据库中的所有表。
String mSelectionClause = "var = ?";
String[] selectionArgs = {""};
selectionArgs[0] = mUserInput;
一个用于将 ? 用作可替换参数的选择子句和一个选择参数数组是指定选择的首选方式,即使提供程序并未基于 SQL 数据库。
如果没有与选择条件匹配的行,则提供程序会返回Cursor.geeCount() 为 0(空游标)的Cursor 对象。
如果出现内部错误,查询结果将取决于具体的提供程序。它可能会选择返回 null,或引发Exception
由于Cursor是行“列表”,因此显示Cursor 内容的良好方式是通过SimpleCursorAdapter将其与ListView 关联。
内容提供程序权限提供程序的应用可以指定其他应用访问提供程序的数据所必需的权限。 这些权限可确保用户了解应用将尝试访问的数据。 根据提供程序的要求,其他应用会请求它们访问提供程序所需的权限。 最终用户会在安装应用时看到所请求的权限。
如果提供程序的应用未指定任何权限,则其他应用将无权访问提供程序的数据。 但是,无论指定权限为何,提供程序的应用中的组件始终具有完整的读取和写入访问权限。
要获取访问提供程序所需的权限,应用将通过其清单文件中的插入、更新、删除数据
与从提供程序检索数据的方式相同,也可以通过提供程序客户端和提供程序ContentProvider之间的交互来修改数据。 您通过传递到ContentProvider的对应方法的参数来调用 ContentResolver方法。 提供程序和提供程序客户端会自动处理安全性和跨进程通信。
// 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
);
更新:
// 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
);
删除:
// 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
);
提供程序访问的替代形式