惭愧,现在才接触到ContentResolver的用法

这个类主要是Android用来实现应用程序之间数据共享的

一个应用程序可以将自己的数据完全暴露出去,外界更本看不到,也不用看到这个应用程序暴露的数据是如何存储的,或者是使用数据库还是使用文件,还是通过网上获得,这些一切都不重要,重要的是外界可以通过这一套标准及统一的接口和这个程序里的数据打交道,例如:添加(insert)、删除(delete)、查询(query)、修改(update),当然需要一定的权限才可以。

一个程序可以通过实现一个Content provider的抽象接口将自己的数据完全暴露出去,而且Content providers是以类似数据库中表的方式将数据暴露。Content providers存储和检索数据,通过它可以让所有的应用程序访问到,这也是应用程序之间唯一共享数据的方法。

要想使应用程序的数据公开化,可通过2种 方法:

1)创建一个属于你自己的Content provider

2)将你的数据添加到一个已经存在的Content provider中,前提是有相同数据类型并且有写入Content provider的权限

什么是URI?

在学习如何获取ContentResolver前,有个名词是必须了解的:URI。URI是网络资源的定义,在Android中赋予其更广阔的含义,先看个例子,如下:

将其分为A,B,C,D 4个部分:
A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;

B:URI的标识,它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的   类名。这个标识在<provider> 元素的 authorities属性中说明:
<provider name=”.TransportationProvider”  authorities=”com.example.transportationprovider”  . . .  >

C:路径,Content Provider使用这些路径来确定当前需要生什么类型的数据,URI中可能不包括路径,也可能包括多个;

D:如果URI中包含,表示需要获取的记录的ID;如果没有ID,就表示返回全部;

由于URI通常比较长,而且有时候容易出错,切难以理解。所以,在Android当中定义了一些辅助类,并且定义了一些常量来代替这些长字符串,例如:People.CONTENT_URI

ContentResolver 介绍说明

看完这些介绍,大家一定就明白了,ContentResolver是通过URI来查询ContentProvider中提供的数据。除了URI以 外,还必须知道需要获取的数据段的名称,以及此数据段的数据类型。如果你需要获取一个特定的记录,你就必须知道当前记录的ID,也就是URI中D部分。

前面也提到了Content providers是以类似数据库中表的方式将数据暴露出去,那么ContentResolver也将采用类似数据库的操作来从Content providers中获取数据。现在简要介绍ContentResolver的主要接口,如下:

返回值 函数声明
final Uri insert (Uri url, ContentValues values)Inserts a row into a table at the given URL.
final int delete (Uri url, String where, String[] selectionArgs)Deletes row(s) specified by a content URI.
final Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)Query the given URI, returning a Cursor over the result set.
final int update (Uri uri, ContentValues values, String where, String[] selectionArgs)Update row(s) in a content URI.

可能还有2个问题,是需要关注的。

1. ContentProvider是什么时候创建的,是谁创建的?访问某个应用程序共享的数据,是否需要启动这个应用程序?这个问题在 Android SDK中没有明确说明,但是从数据共享的角度出发,ContentProvider应该是Android在系统启动时就创建了,否则就谈不上数据共享了。 这就要求在AndroidManifest.XML中使用<provider>元素明确定义。

2. 可能会有多个程序同时通过ContentResolver访问一个ContentProvider,会不会导致像数据库那样的“脏数据”?这个问题一方面需要数据库访问的同步 , 尤其是数据写入的同步,在AndroidManifest.XML中定义ContentProvider的时候,需要考虑 是<provider>元素multiprocess属性的值;另外一方面Android在ContentResolver中提供了 notifyChange()接口,在数据改变时会通知其他ContentObserver,这个地方应该使用了观察者模式,在 ContentResolver中应该有一些类似register,unregister的接口。

接触Android有一段时间了,每一个知识点都有涉及,现在觉得重新把知识点理一遍很重要,那么就凭感觉、凭喜好无知识点先后顺序来理清一遍。这篇文章主要叙述了如何来自定义自己的ContentProvider组件,其中涉及到的一些比较重要的知识点也顺带详细分解一下,那么现在就开始吧。

一、SQLiteOpenHelper简介:

SQLiteOpenHelper是Android给我们提供的一个工具,用来和数据库交互的。我们通常使用的方法是自定义一个类来继承于SQLiteOpenHelper,通过它可以得到一个SQLiteDatabase的实例,通过使用此对象的一些方法来与数据库交互。

例如:

execSQL(Stringsql).传入一个字符串形式的sql语句来执行等。

insert(String table, String nullColumnHack, ContentValues values)。插入操作,table是表名,values是ContentValues类型用来携带数据的,第二个参数是为了防止values为空时后台创建SQL语句出错。具体的其他方法参考API文档,此处就不做解释。

二、ContentProvider简介:

假如你的应用程序想把一些数据提供给其他的应用程序来使用,那么此时就会用到ContentProvider,有了它你的应用程序就可以在进程间共享数据。使用的时候需要创建一个类来继承ContentProvider,实现里面的方法,这就相当于此应用给其他应用程序提供访问数据的接口。说直观点,Contentprovider就相当于一个中介人,它介于第一个应用程序的数据层和另一应用程序之间。使用了Contentprovider最重要的作用是统一了共享数据时访问数据的方式。

三、ContentResolver简介:

当外部应用程序想对ContentProvider中数据进行操作时可以使用ContentResolver来完成,要获取它的对象可以使用Activity中的getContentResolver方法来完成。

四、Uri简介:

介绍之前默认为大家都了解URL,那么URL就相当于Uri的一个子集。Uri由三部分组成:scheme、authority、path。下面举一个例子来具体介绍。

Uri:    content://com.jm.provider.myprovider/peoples

1    scheme部分:以content://开头,是Android系统定义的,不可更改。

2    authority部分:推荐以域名+provider+类名组成,也可自己定义。

3    path部分:用来表示我们要操作的数据。具体说明如下:

要操作peoples中所有数据可以构建 /peoples

要操作peoples中_id为1的数据可以构建/peoples/1

Uri有两个比较常用方法

1       parse(String uriString)它的作用是将字符型数据转换成Uri类型数据。

2       withAppendedPath(Uri baseUri,String pathSegment)它的作用是将baseUri后面加上pathSegment组成新的Uri。

五、UriMatcher简介:

作用是在ContentProvider中把需要匹配的Uri全部注册上。

UriMatcher.NO_MATCHER表示不匹配任何路径,返回码为-1.

UriMatcher有两个常用方法。

1       match(Uri uri)获取路径的返回码。

2       addURI(String authority, Stringpath, int code)是用来注册需要匹配的路径。具体实例参看下文。

API中推荐把它放在静态块中完成,例如:

  1. private static final UriMatcher mather = new UriMatcher(UriMatcher.NO_MATCH);
  2. static {
  3. mather.addURI(CONTENT_URI.getAuthority(), "peoples", PEOPLE);
  4. mather.addURI(CONTENT_URI.getAuthority(), "peoples/#", PEOPLE_ID);
  5. }

其中要解释的一点是#代表通配符,表示所有数字(will match any number)。*代表所有字符(will match any text)。

六、ContentUris简介:

ContentUris是用来获取uri后面id部分,它有两个比较实用的方法:

1       parseId(Uri contentUri)用来获得contentUri中id部分

2       withAppendedId(Uri contentUri,long id)用来给contentUri添加id组成新的Uri,功能和Uri的withAppendedPath(Uri baseUri,String pathSegment)方法类似。

七、ContentProvider中getType方法中MIME类型讲解:

vnd.android.cursor.dir代表值的集合

vnd.android.cursor.item代表一项值

最好不要默认返回null

结构分析,例如:"vnd.android.cursor.dir/peoplelist" 斜杠前部分可把它比作变量的类型是不能随便定义的,后部分相当于变量名,可自己定义。

当调用增删改查方法时系统会通过getType()进行验证,如果有值并且是系统可识别的类型,那么处理起来比较快。

八、代码示例:

1、继承SQLiteOpenHelper

  1. package com.jm.my.provider;
  2. import android.content.ContentValues;
  3. import android.content.Context;
  4. import android.database.sqlite.SQLiteDatabase;
  5. import android.database.sqlite.SQLiteOpenHelper;
  6. /**
  7. * 继承于SQLiteOpenHelper,用于和数据库交互
  8. * @author jinmeng
  9. * @date 2012-7-25
  10. * @version 1.0
  11. */
  12. public class MyHelper extends SQLiteOpenHelper {
  13. //数据库名字,可在文件目录下找到
  14. private static final String DATABASE_NAME = "mydb";
  15. //数据库版本号
  16. private static final int MYDATABASE_VERSION = 1;
  17. //数据库表名
  18. public static final String TABLE_NAME = "peoples";
  19. //数据库的一些基本字段
  20. public static final String COL_NAME = "name";
  21. public static final String COL_AGE = "age";
  22. public static final String COL_BIRTHDAY = "birthday";
  23. //创建数据库时的SQL语句
  24. public static final String CREATEDATABASE = "CREATE TABLE " + TABLE_NAME
  25. + " (_id INTEGER PRIMARY KEYAUTOINCREMENT, " + COL_NAME
  26. + " TEXT, " + COL_AGE + " INTEGER, " + COL_BIRTHDAY + " DATE);";
  27. public MyHelper(Context context) {
  28. super(context, DATABASE_NAME, null, MYDATABASE_VERSION);
  29. }
  30. /**
  31. * 当数据库被创建的时候执行SQL语句
  32. */
  33. @Override
  34. public void onCreate(SQLiteDatabase db) {
  35. db.execSQL(CREATEDATABASE);
  36. ContentValues cv = new ContentValues();
  37. cv.put(COL_NAME, "jinmeng");
  38. cv.put(COL_AGE, 22);
  39. String str = new String("1990-03-09");
  40. cv.put(COL_BIRTHDAY, str);
  41. db.insert(TABLE_NAME, null, cv);
  42. }
  43. /**
  44. * 当数据库版本号更新的时候回调此方法。
  45. */
  46. @Override
  47. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  48. db.execSQL("DROP TABLE IF EXIST" + TABLE_NAME);
  49. onCreate(db);
  50. }
  51. }

2、为示例添加ContentProvider类:

  1. package com.jm.my.provider;
  2. import android.content.ContentProvider;
  3. import android.content.ContentUris;
  4. import android.content.ContentValues;
  5. import android.content.UriMatcher;
  6. import android.database.Cursor;
  7. import android.database.sqlite.SQLiteDatabase;
  8. import android.net.Uri;
  9. /**
  10. * 继承于ContentProvider,提供外接访问接口
  11. *
  12. * @author jinmeng
  13. * @date 2012-7-25
  14. * @version 1.0
  15. */
  16. public class MyProvider extends ContentProvider {
  17. // 和Authority相关
  18. public static final Uri CONTENT_URI = Uri
  19. .parse("content://com.jm.provider.myprovider/peoples");
  20. // 数据库表名
  21. private static final String TABLE_NAME = "peoples";
  22. // 注册和解析路径时的返回码
  23. private static final int PEOPLE = 1;
  24. private static final int PEOPLE_ID = 2;
  25. // 注册需要的路径
  26. private static final UriMatcher mather = new UriMatcher(UriMatcher.NO_MATCH);
  27. static {
  28. mather.addURI(CONTENT_URI.getAuthority(), "peoples", PEOPLE);
  29. mather.addURI(CONTENT_URI.getAuthority(), "peoples/#", PEOPLE_ID);
  30. }
  31. private MyHelper helper;
  32. /**
  33. * 基本表结构
  34. *
  35. * @author jinmeng
  36. *
  37. */
  38. public static final class Mydata {
  39. public static final String COL_ID = "_id";
  40. public static final String COL_NAME = "name";
  41. public static final String COL_AGE = "age";
  42. public static final String COL_BIRTHDAY = "birthday";
  43. }
  44. @Override
  45. public boolean onCreate() {
  46. this.helper = new MyHelper(this.getContext());
  47. if (helper != null) {
  48. return true;
  49. } else {
  50. return false;
  51. }
  52. }
  53. /**
  54. * 启动时涉及到的MIME类型值: vnd.android.cursor.dir代表值的集合 vnd.android.cursor.item代表一项值
  55. * 最好不要默认返回空
  56. */
  57. @Override
  58. public String getType(Uri uri) {
  59. switch (mather.match(uri)) {
  60. case PEOPLE:
  61. return "vnd.android.cursor.dir/peoplelist";
  62. case PEOPLE_ID:
  63. return "vnd.android.cursor.item/peopleitem";
  64. default:
  65. throw new IllegalArgumentException("uri Illegal" + uri);
  66. }
  67. }
  68. /**
  69. * 具体的查询方法
  70. */
  71. @Override
  72. public Cursor query(Uri uri, String[] projection, String selection,
  73. String[] selectionArgs, String sortOrder) {
  74. SQLiteDatabase db = helper.getWritableDatabase();
  75. switch (mather.match(uri)) {
  76. case PEOPLE:
  77. return db.query(TABLE_NAME, projection, selection, selectionArgs,
  78. null, null, sortOrder);
  79. case PEOPLE_ID:
  80. long id = ContentUris.parseId(uri);
  81. String where = "_id=" + id;
  82. if ((selection != null) && (!"".equals(selection))) {
  83. where = where + " and " + selection;
  84. }
  85. return db.query(TABLE_NAME, projection, where, selectionArgs, null,
  86. null, sortOrder);
  87. default:
  88. throw new IllegalArgumentException("uri Illegal" + uri);
  89. }
  90. }
  91. /**
  92. * 具体的插入方法
  93. */
  94. @Override
  95. public Uri insert(Uri uri, ContentValues values) {
  96. SQLiteDatabase db = helper.getWritableDatabase();
  97. long id;
  98. switch (mather.match(uri)) {
  99. case PEOPLE:
  100. id = db.insert(TABLE_NAME, "_id", values);
  101. return ContentUris.withAppendedId(uri, id);
  102. case PEOPLE_ID:
  103. id = db.insert(TABLE_NAME, "_id", values);
  104. String uriPath = uri.toString();
  105. String path = uriPath.substring(0, uriPath.lastIndexOf("/")) + id;
  106. return Uri.parse(path);
  107. default:
  108. throw new IllegalArgumentException("uri Illegal" + uri);
  109. }
  110. }
  111. /**
  112. * 具体的删除方法
  113. */
  114. @Override
  115. public int delete(Uri uri, String selection, String[] selectionArgs) {
  116. SQLiteDatabase db = helper.getWritableDatabase();
  117. switch (mather.match(uri)) {
  118. case PEOPLE:
  119. return db.delete(TABLE_NAME, selection, selectionArgs);
  120. case PEOPLE_ID:
  121. long id = ContentUris.parseId(uri);
  122. String where = "_id=" + id;
  123. if ((selection != null) && (!"".equals(selection))) {
  124. where = where + " and " + selection;
  125. }
  126. return db.delete(TABLE_NAME, where, selectionArgs);
  127. default:
  128. throw new IllegalArgumentException("uri Illegal" + uri);
  129. }
  130. }
  131. /**
  132. * 具体的更新方法
  133. */
  134. @Override
  135. public int update(Uri uri, ContentValues values, String selection,
  136. String[] selectionArgs) {
  137. SQLiteDatabase db = helper.getWritableDatabase();
  138. switch (mather.match(uri)) {
  139. case PEOPLE:
  140. return db.update(TABLE_NAME, values, selection, selectionArgs);
  141. case PEOPLE_ID:
  142. long id = ContentUris.parseId(uri);
  143. String where = "_id=" + id;
  144. if ((selection != null) && (!"".equals(selection))) {
  145. where = where + " and " + selection;
  146. }
  147. return db.update(TABLE_NAME, values, where, selectionArgs);
  148. default:
  149. throw new IllegalArgumentException("uri Illegal" + uri);
  150. }
  151. }
  152. }

3、添加contentProvider配置:

此处定义的

  1. android:authorities

和代码中CONTENT_URI保持一致

  1. <providerandroid:name=".MyProvider"
  2. android:authorities="com.jm.provider.myprovider"/>

4、测试ContentProvider的示例程序:

ContentProvider是给其他应用程序提供数据的接口,那么测试工程新建,以下只给出insert的测试。

  1. package com.jm.test;
  2. import android.app.Activity;
  3. import android.content.ContentResolver;
  4. import android.database.Cursor;
  5. import android.net.Uri;
  6. import android.os.Bundle;
  7. import android.util.Log;
  8. /**
  9. * 用来测试ContentProvider
  10. * @author jinmeng
  11. * @date 2012-7-25
  12. * @version 1.0
  13. */
  14. public class MainActivity extends Activity {
  15. @Override
  16. public void onCreate(Bundle savedInstanceState) {
  17. super.onCreate(savedInstanceState);
  18. //获取ContentResolver实例
  19. ContentResolver contentResolver = MainActivity.this
  20. .getContentResolver();
  21. //访问数据的Uri地址
  22. Uri uri = Uri.parse("content://com.jm.provider.myprovider/peoples");
  23. //通过ContentResolver来获取Cursor
  24. Cursor cursor = contentResolver.query(uri, new String[] { "_id",
  25. "name", "age" }, null, null, "_id desc");
  26. //遍例输出结果
  27. while (cursor.moveToNext()) {
  28. Log.i("jm",
  29. "_id=" + cursor.getInt(0) + ",name=" + cursor.getString(1)
  30. + ",age=" + cursor.getString(2));
  31. }
  32. }
  33. }

ContentResolver + SqliteOpenHelper + ContentProvider 理解的更多相关文章

  1. 解读ContentResolver和ContentProvider

    转自:http://cthhqu.blog.51cto.com/7598297/1281217 1. ContentProvider的概述 ContentProvider: (Official Def ...

  2. SQLiteOpenHelper+ContentProvider的使用

    效果图: PetDbHelper package com.example.admin.pets; import android.content.Context;import android.datab ...

  3. ContentProvider与ContentResolver使用【转】

    这篇文章被转载而转载者未注明原文出处,在此未加上原文地址链接,本人向原作者致以歉意. 下面是文章内容: 使用ContentProvider共享数据: 当应用继承ContentProvider类,并重写 ...

  4. ContentProvider与ContentResolver使用

    例如以下内容为从网络转载: 使用ContentProvider共享数据: 当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就能够向其它应用共享其数据.虽然使用其它方 ...

  5. ContentProvider和ContentResolver的使用

    ContentProvider ContentProvider 在android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通 ...

  6. ContentProvider与ContentResolver

    使用ContentProvider共享数据: 当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据.虽然使用其他方法也可以对外共享数据,但数据 ...

  7. ContentProvider数据访问详解

    ContentProvider数据访问详解 Android官方指出的数据存储方式总共有五种:Shared Preferences.网络存储.文件存储.外储存储.SQLite,这些存储方式一般都只是在一 ...

  8. Android ContentProvider和getContentResolver

    安卓系统中的数据库SqlLite操作和java中mysql的数据库操作很不一样,造成这样的原因是因为在安卓中数据库是属于进程的不存在数据库客户端,也不存在数据库服务器. 关于SqlLite数据库的文章 ...

  9. Android四大组件--ContentProvider详解(转)

    一.相关ContentProvider概念解析: 1.ContentProvider简介在Android官方指出的Android的数据存储方式总共有五种,分别是:Shared Preferences. ...

随机推荐

  1. sgu 194 被动散热器具有最大流量的上限和下限(最大流量模板dinic加上优化)

    模板类型的题详细參考国家集训队论文:http://wenku.baidu.com/view/0f3b691c59eef8c75fbfb35c.html 參考博客:http://blog.csdn.ne ...

  2. 【百度地图API】如何调整结果面板的样式?如何获取指定页码的结果?

    原文:[百度地图API]如何调整结果面板的样式?如何获取指定页码的结果? 摘要: 1.你是否想自定义查询后,结果面板的显示样式? 2.数据接口每次只返回10条结果,如何取到单独每一页的结果? ---- ...

  3. POJ1719- Shooting Contest(二分图最大匹配)

    题目链接 题意:给定一个矩阵,每列有两个白点,其它都是黑点,如今要求每列选一个白点,使得每一行至少包括一个白点被选中 思路:利用白点所在的位置用行指向列建图,用行去匹配列,最大匹配数假设不等于行数的话 ...

  4. file 上传文件后缀名 限制

    比如: 要求只能上传Excel <input type="file" accept="application/vnd.ms-excel,application/vn ...

  5. DbModel

    DbModel 前言 我们都知道EF可以生成Dbmodel,系统生成的Model有时候并不是我们想要的,如何我们要生成自己的Model,那么久需要我们手动的去修改T4模版,T4是对“Text Temp ...

  6. sql点滴41—mysql常见sql语法

    原文:sql点滴41-mysql常见sql语法 ALTER TABLE:添加,修改,删除表的列,约束等表的定义. 查看列:desc 表名; 修改表名:alter table t_book rename ...

  7. MySQL之GROUP BY用法误解

    1.说明  “Group By”从字面意义上理解就是根据“By”指定的规则对数据进行分组,所谓的分组就是将一个“数据集”划分成若干个“小区域”,然后针对若干个“小区域”进行数据处理.(只是简单说明这个 ...

  8. 机器学习学习-Types of learning

    Types of learning 基于个人理解.于我们在面对一个详细的问题时.可以依据要达到的目标选择合适的机器学习算法来得到想要的结果.比方,推断一封电子邮件是否是垃圾邮件,就要使用分类(clas ...

  9. LINUX下FD_SET介绍

    刚刚了解了linux下select系统调用,函数原型是 #include <sys/select.h> #include <sys/time.h> int select(int ...

  10. 在Android中自动实现横竖屏切换的问题

    http://developer.android.com/training/basics/supporting-devices/screens.html参照Google推荐的做法 在你项目的res 文 ...