阅读:http://developer.android.com/guide/topics/providers/content-providers.html

When you want to access data in a content provider, you use the ContentResolver object in your application's Context to communicate with the provider as a client. The ContentResolver object communicates with the provider object, an instance of a class that implements ContentProvider. The provider object receives data requests from clients, performs the requested action, and returns the results.

  当我们想获得content provider,可以使用 ContentResolver对象来获得provider object ,继承ContentProvider的一个对象。provider object能够从用户获得请求并返回结果。


// Queries the user dictionary and returns results
mCursor = getContentResolver().query(UserDictionary.Words.CONTENT_URI,   // The content URI of the words tablemProjection,                        // The columns to return for each rowmSelectionClause                    // Selection criteriamSelectionArgs,                     // Selection criteriamSortOrder);                        // The sort order for the returned rows

一般通过ContentResolver的方法来进行请求,相应的参数如下:

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 BY col,col,... sortOrder specifies the order in which rows appear in the returned Cursor.

   content URI是一个在provide里已经定义好的URI,它是用户请求的一个URI。形式像是这样:

content://user_dictionary/words

  


  你还可以通过URI直接连接到_ID为某个值的那行,使用这个方法:

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

  最后的参数为_ID的值。


官方文档中,建议使用异步操作进行数据的请求:


一般数据的请求还要有相关的权限。


/** 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 wordsmSelectionClause = 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 tablemProjection,                       // The columns to return for each rowmSelectionClause                   // Either null, or the word the user enteredmSelectionArgs,                    // Either empty, or the string the user enteredmSortOrder);                       // 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则表示出错,而查询正确则会返回Cursor,如果查询结果为0,那么Cursor.getCount()==0;


// 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 nameUserDictionary.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 = new SimpleCursorAdapter(getApplicationContext(),               // The application's Context objectR.layout.wordlistrow,                  // A layout in XML for one row in the ListViewmCursor,                               // The result from the querymWordListColumns,                      // A string array of column names in the cursormWordListItems,                        // An integer array of view IDs in the row layout0);                                    // 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 the ListView doesn't display it. This restriction also explains why most providers have a _ID column for each of their tables.


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

如果需要获取某列的值,需要先获得某列的index再去获取相关值,关于值的类型可以用 getType()获取。


// 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 URImNewValues                          // the values to insert
);

通过新建一个ContentValues来进行插入数据的存储,然后后面直接用insert插入,注意_ID是自动插入的不需要自己添加,返回的uri可以通过ContentUris.parseId().获取_ID。


// 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 URImUpdateValues                       // the columns to updatemSelectionClause                    // the column to select onmSelectionArgs                      // 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 URImSelectionClause                    // the column to select onmSelectionArgs                      // the value to compare to
);

删除的代码。

接下来谈谈Content-provider如何设计开发

首先,基于这样的需求你才需要CP:

1、与其他的APP有一定数据的交互;

2、需要用到搜索那块;

设计流程:

1、考虑数据形式:如果是文件,建议存放在私有空间,然后通过CP获得手柄去访问,又或者,只是单纯的数据结构,那么就可以通过类似数据库等来解决。

2、实现CP的类;

3、Define the provider's authority string, its content URIs, and column names.

此外,还需要考虑:主键的问题;对于文件数据还是存为文件然后让CP提供访问较好;

接下来,你还要设计名字,权限,结构等问题比较主要的是ID问题。

接下来就是,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.

A content URI pattern matches content URIs using wildcard characters:

  • *: 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:

  • content://com.example.app.provider/table1: A table called table1.
  • content://com.example.app.provider/table2/dataset1: A table called dataset1.
  • content://com.example.app.provider/table2/dataset2: A table called dataset2.
  • content://com.example.app.provider/table3: A table called 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.

The following content URI patterns would be possible:

content://com.example.app.provider/*
Matches any content URI in the provider.
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.
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.

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.

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

public class ExampleProvider extends ContentProvider {
...// Creates a UriMatcher object.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.*/
.../** Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used* in the path*/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.*/sUriMatcher.addURI("com.example.app.provider", "table3/#", 2);
...// Implements 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.*/switch (sUriMatcher.match(uri)) {// If the incoming URI was for all of table3case 1:if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC";break;// If the incoming URI was for a single rowcase 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*/selection = selection + "_ID = " uri.getLastPathSegment();break;default:...// If the URI is not recognized, you should do some error handling here.
        }// call the code to actually do the query}

然后,继承CP需要重写一些方法:

query()

根据所提出的要求返回Cursor。Cursor有可能需要自己去实现

insert()

插入新数据,返回新数据的URI
update()
更新数据,返回更新的数目。
delete()
删除,返回删除数目。
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.
onCreate()

当ContentResolver使用的时候就会启动这个方法,初始化CP吧!

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.
  • 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.
  • 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.

  除了oncreate之外,其他方法都要加上线程安全。

  不要再oncreate执行太多操作。

  并不是每个方法都要很认真的返回所要求的数据,根据需求看吧!

  接下来就是关于CP的权限了,是在manifest立马配置的,而且,有多种类型:

Single read-write provider-level permission
一次性定义读和写权限;
Separate read and write provider-level permission
分开定义android:readPermission and android:writePermission。
Path-level permission
定义特定路径下的路径,详细见官方。
Temporary permission可赋予其他APP临时权限。

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:

Authority (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.
Provider class name ( android:name )
The class that implements ContentProvider. This class is described in more detail in the section Implementing the ContentProvider Class.
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:permission: Single provider-wide read/write permission.
  • android:readPermission: Provider-wide read permission.
  • android:writePermission: Provider-wide write permission.

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:enabled: Flag allowing the system to start the provider.
  • android:exported: Flag allowing other applications to use this provider.
  • android:initOrder: The order in which this provider should be started, relative to other providers in the same process.
  • android:multiProcess: Flag allowing the system to start the provider in the same process as the calling client.
  • android:process: The name of the process in which the provider should run.
  • android:syncable: Flag indicating that the provider's data is to be sync'ed with data on a server.

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

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:label: An informational label describing the provider or its data, or both. The label appears in the list of apps in Settings > Apps > All.

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

转载于:https://www.cnblogs.com/yutoulck/p/3382406.html

content-providers相关推荐

  1. 《Android开发从零开始》——29.Content Providers(1)

    本节课的主要内容有: 1.讲解是什么Content Providers 2.讲解URI对象 3.演示如何使用Content Providers 课程下载地址:http://u.115.com/file ...

  2. Android Content Providers(三)——Contacts Provider

    接着上篇Android Content Providers(二)--Contacts Provider继续,接下来要说明的是顶层的Contacts,Contacts是聚合联系人表,在之前讨论的RawC ...

  3. Android开发学习笔记:浅谈Content Provider

    一.Content Provider的概念介绍 Content Providers是所有应用程序之间数据存储和检索的桥梁,它使得各个应用程序之间实现数据共享.是应用程序间共享数据的唯一途径.Conte ...

  4. android contentprovider api,Content Provider Basics

    一个内容提供者访问数据的中央资源库.提供者是应用程序的一部分,提供自己的操作数据的UI.然而,内容提供者主要是被其他应用程序引用,通过提供者客户对象访问提供者.提供者和提供者客户端为数据提供一个一致的 ...

  5. Android Content Provider基础

    Android Content Provider基础 Content Providers Content providers管理对一个结构化的数据集合的访问.它们封装了数据,并且提供了保护数据安全性的 ...

  6. Content(内容)

    http://www.cnblogs.com/tekkaman/archive/2011/06/09/2075626.html [Content Providers] Content Provider ...

  7. content is king – Bill Gates (1/3/1996) 内容为王 - 比尔盖茨

    以下中文版本由谷歌翻译 内容为王 - 比尔盖茨(1/3/1996) 内容是我期望在互联网上赚取大部分真钱的地方,就像在广播中一样. 半个世纪前开始的电视革命催生了许多行业,包括制造电视机,但长期的赢家 ...

  8. java类安卓app 简介_android.app.Activity 的介绍

    文章可随意转载,但务必注明源地址 发现当前Android的资料不是很多,而且对于Activity的介绍也很少,所以把官方文档的android.app.Activity的介绍翻译了一下,加入了一些自己的 ...

  9. 2019 6月编程语言_今年六月您可以开始学习650项免费的在线编程和计算机科学课程...

    2019 6月编程语言 Seven years ago, universities like MIT and Stanford first opened up free online courses ...

  10. 夏天和空调_您可以在今年夏天开始学习650项免费的在线编程和计算机科学课程...

    夏天和空调 Seven years ago, universities like MIT and Stanford first opened up free online courses to the ...

最新文章

  1. dotNet中,取得指定日期所在月份的最后一天
  2. 堆排序之 大顶堆和小顶堆 c语言
  3. 【Flask项目2】创建用户模块的蓝图(7)
  4. 江西师范大学2017年C语言考试,2018年江西师范大学程序设计(C语言)考研初试大纲...
  5. ubunto中常出现的问题
  6. java JDK 自带的 native2ascii 和它的 reverse 命令
  7. 54 字符流中第一个不重复的字符
  8. 321. 拼接最大数
  9. CNN for Sentence Classification-textcnn阅读笔记
  10. Android 自动接听 adb,GitHub - AndroidMsky/RootPlay: 安卓手机秒变网络摄像头,自动接起QQ视频。欢迎star,fork,Issues。...
  11. C语言 输出乘法口诀表
  12. Hydra暴力破解smb协议(Windows用户名和密码)
  13. Spark 内存管理之Tungsten
  14. 0成本开发一个外卖返利领劵小程序|外卖返利系统
  15. Android开发应用apk文件发送到微信打不开解决方案
  16. matplotlib工具栏源码探析一(禁用工具栏、默认工具栏和工具栏管理器三种模式的差异)
  17. 空气质量等级c语言编程,华中科技大学C语言课设空气质量检测信息管理系统技术分析.docx...
  18. 为什么现在大多数服务器使用linux系统区别的一些总结
  19. 数据分析tableau 和 python的区别_数据分析师综述篇
  20. 浅谈如何使用Google reCAPTCHA进行人机验证

热门文章

  1. 使用template扩展已有的DDX_Text函数,使扩展能够同时支持各种数据类型的一个例子...
  2. 给hadoop 2.7.1 定制树莓派参数
  3. KB/MB/GB/TB之间的换算是乘以1000还是1024?
  4. php-redis中文参考手册_zset
  5. 在 Adobe AIR 中为不同屏幕尺寸的多种设备提供支持
  6. TTS Service Extended (进程:com.google.tts)意外停止 恢复被阉割的TTS文字转语音功能
  7. C#图片处理之:亮度和对比度的校正
  8. c 更新mysql数据_MySQL插入更新删除数据
  9. 计算机网络拓扑分层,计算机网络和工程实践教程讲座主讲内容网络拓扑和分层体系结构.ppt...
  10. arm与linux些许问题,arm-linux中遇到的问题