Content Provider Basics

来源:互联网 发布:阿里云应用镜像是什么 编辑:程序博客网 时间:2024/06/06 00:04

Android API Guides


Content Provider 负责管理访问结构化数据集,encapsulate 数据,提供安全访问数据机制。
访问数据的Client 与 提供数据的Provider 处于两个进程。

Client 使用ContentResolver, 负责与实现ContentProvider接口的实例进行进程间通信IPC。
一般来讲,无需开发provider,除非需要与其他应用共享数据,如提供自定义的搜索建议,复制或者粘贴复杂的数据或者文件到其他应用。

ContntResolver.query()会调用ContentProvider.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

其中,

query args select keyword/parameters 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 BY col,col,… sortOrder specifies the order in which rows appear in the returned Cursor.

ContentURI 标示一个数据Provider。由sybolic name(authority) 和 table name(path)组成。
content://user_dictionary/words
其中content://是scheme, user_dictionary 是authority, words是table.
许多provider允许访问单行数据,附上一个_ID。
Uri singleUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI,4);
通常是在获取一系列数据后,然后想要更新某条数据或者删除某条数据。

Retriving Data From the provider

For the sake of clarity, 为清晰起见,演示的代码都在UI线程中。但在实际的代码中,一般都在子线程中采用异步查询等操作。也可以使用CursorLoader。

从provider中获取数据,一般有两步:
1. 请求read access permission
2. 编写代码发送查询请求。

1. 请求Read Permission

不可在运行时请求,只能在Manifest中静态指定, 和 exact permission name defined by provider.
当用户安装应用时,用户就会 implicitly grant(隐式授权)这个权限请求。

如用户词典User Dictionary Provider在其Manifest中定义了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 = {""};

mSelectionClause 是查询条件
而mSelectionArgs则是查询条件的参数,比如下面的代码。

/* * 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 = ORDER BY word ASC; .query() projection content_uri selection selectionArgs orderby

避免注入,推荐在selection使用?来代替。

// Constructs a selection clause with a replaceable parameterString mSelectionClause =  "var = ?";// Sets the selection argument to the user's inputselectionArgs[0] = mUserInput;

CAUTION:若要使用Cursor备份一个ListView,该Cursor必须包含_ID列,即使ListView并没有显示_ID列。
To back a ListView with a Cursor, the cursor must contain a column named _ID.

从Cursor中获取数据
newWord = mCursor.getString(index);
或者是其他的getInteger等等类型。

Content Provider Permissions

指定权限以便于控制数据的访问。
另外,若是一个Provider什么权限都不指定,则其它应用将不可访问,但是该Provider所在的应用具有完全的访问读写能力。

读使能权限
android.permission.READ_USER_DICTIONARY
插入删除更新使能权限
android.permission.WRITE_USER_DICTIONARY

Inserting, Updating, and Deleting Data

插入数据,调用ContentResolver.insert()
使用ContentValues 封装KV值,调用插入方法即可。

// 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);

更新
需要query的selectionClause, selectionArgs 和 insert的content values.

// 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);

删除
需要SelectionClause, selectionArgs, 方法返回被删除的行数。

// 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);

Provider Data Types

  • String
  • integer
  • long integer (long)
  • floating point
  • long floating point (double)
  • BLOB, Binary Large OBject implemented as a 64KB byte array.

Provide也同样支持MIME类型,支持使用MIME指定一个类的格式,
MIME data type information for each content URI they define.

Alternative Forms of Provider Access

  • 批访问Batch Access: You can create a batch of access calls with methods in the ContentProviderOperation class, and then apply them with ContentResolver.applyBatch().

  • Asynchronous queries: 使用CursorLoader进行异步查询。

  • Data access via intents: 通过Intents访问数据,使用Intent发送请求到Provider所在Application,然后Application解析intent,返回相应的数据。best-equipped to modify the provider’s data.

    1. Batch Access
      create ContentProviderOperation 类的数组,然后调用 ContentResolver.applyBatch()。只需要传递authority,不需要特定的path.

      这允许数组中的每个ContentProviderOperation对象都能够工作在各自的table,并且Content.applyBatch()将返回一个结果数组。
      This allows each ContentProviderOperation object in the array to work against a different table. A call to ContentResolver.applyBatch() returns an array of results.

    2. Asynchrounous queries
      使用方法如CursorLoader中的Example.

    3. Data Access via intents

  • 从具有权限的应用获得result intent back
  • 激活一个具有权限的应用,并且用户操作它。

临时权限访问和写入
Read permission: FLAG_GRANT_READ_URI_PERMISSION
Write permission: FLAG_GRANT_WRITE_URI_PERMISSION

Provider在< provider>元素下定义android:grantUriPermission属性,以及 < grant-uri-permission> 子元素。

  • 发送ACTION_PICK并制定MIME type, 然后发送Intent。Your application sends an intent containing the action ACTION_PICK and the “contacts” MIME type CONTENT_ITEM_TYPE, using the method startActivityForResult().
  • Intent被匹配。Because this intent matches the intent filter for the People app’s “selection” activity, the activity will come to the foreground.
  • 返回结果并给予临时读取权限。In the selection activity, the user selects a contact to update. When this happens, the selection activity calls setResult(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.
  • 调用onActivtyResult()。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.
  • 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.

使用另一个具有权限的应用
例如:Calendar应用允许其他应用发送ACTION_INSERT,启动Calendar的插入UI.
the Calendar application accepts an ACTION_INSERT intent, which allows you to activate the application’s insert UI.

Contract Classes

设定变量帮助应用与ContentProvider的content URIs, column names, intent actions, and other features 更好的交互。一般在android.provider下。

UserDictionary.Words.CONTENT_URI

MIME Type Reference

用法 type/subtype, 常见的有text/html
自定义的MIME类型,vendor-specific 具有更复杂的类型和子类型。
多行
vnd.android.cursor.dir
单行
vnd.android.cursor.item

再比如:子类型的值
vnd.android.cursor.item/phone_v2

0 0
原创粉丝点击