一、Content Provider概述

Content Provider用于保存和获取数据,并使其对所有应用程序可见,这是不同应用程序之间共享数据的唯一方式,因为在Android中没有提供所有应用可以共同访问的公共存储区域

1、  Content Provider内部的数据如何保存是由其设计者决定的,而所有的的Content Provider都实现一组通用的方法,用来提供数据的增删改查操作

2、  客户端如果要使用这些操作方法,可以通过ContentProvider对象实现对 Content Provider的操作,而开发人员可以通过调用getContentResolver()方法来获得ContentProvider对象

即:ContentResolver cr = getContentProvider();

3、  不同进程之间的通信由ContentResolver类和ContentProvider类处理

二、Content Provider提供数据的数据模型

_ID

NAME

AGE

001

Alice

17

002

Mark

20

003

Tom

11

可以看出使用的是基于数据库模型的简单表格来提供其中的数据 行:记录 列:字段

*每条记录都包含一个_ID字段,用于在表中唯一标识该记录

ID字段前包含一个下划线_ ,这是必须有的,不能不写

三、URI

1、  每个Content Provider提供公共的URI(使用URI类包装)来唯一标识其数据集

2、  URI常量用于所有与Content Provider的交互,每个Content Provider方法都是用URI作为方法的第一个参数,这个参数(URI)用来标识ContentResolver应该使用Content Provider中的哪一个数据表

3、  URI: content://com.xqx.mycontent/dba/010

(1)content:// :标准的前缀,用于标识该数据由Content Provider管理,固定值,不用修改

(2)com.xqx.mycontent :URI的authority部分,用于标识Content Provider,在清单文件的<provider>元素的authority属性中声明该authority ,对于第三方应用,该部分为完整的类名(全部小写字母)

(3)/dba :路径部分,用于决定哪类数据被请求,如果Content Provider只提供一种数据类型,则可省略该部分、如果提供多种类型,则由多部分组成

(4)/010 :被请求的特定记录的ID ,如果请求的记录不限于单条记录(比如查询全部字段),该部分不用写

四、预定义Content Provider

1、  安卓系统提供了很多预定义的Content Provider(声音,联系人,通话记录等)

Eg:

Browser :读取或修改书签,浏览历史或网络搜索

CallLog :查看或更新通话记录

Contacts: :获取修改或保存联系人信息

MediaStore:访问图片视频音乐等

2、  查询数据

如果想查询Content Provider数据,必须需要三个信息

(1)       标识该Content Provider的URI

(2)       需要查询的数据字段的名称

(3)       字段值数据的类型

*如果查询特定的记录,则还需要提供该记录的ID值

为了限制返回一条数据,可以在URI结尾添加要操作记录的ID,

Content://…./003

实现该功能可以使用静态方法ContentUris.withAppendedId(),返回值为一个增加了ID的URI对象

获得数据用Cursor对象处理,它能向前或向后遍历整个查询结果集。

3、  增加记录

(1)       向ContentProvider中添加数据,需要使用ContentValues对象建立键值对映射,键位Content Provider中的字段,值为要添加的值

(2)       调用ContentResolver.insert(URI,value);

第一个参数为要操作的ContentProvider唯一标识的URI,第二个参数为ContentValues映射 ,该方法返回添加记录的完整的URI

4、  删除记录

(1)需要调用int delete (Uri url, String where, String[] selectionArgs)方法 ,第一个为要操作的URI ,第二个为删除的条件,第三个参数为填充值

int delete (Uri url, “_id=?”, 11) 为删除URI 中id为11的记录

五、  自定义Content Provider

1、  我们从上面了解了开发人员可以使用系统给定的ContentProvide

当然我们也可以自定义ContentProvider来共享自己的数据(当然也可以使用系统预定义的ContentProvider,管理相同的数据并且有写入权限,也可修改对应数据)

自定义ContentProvider步骤

(1)、建立数据存储系统

    Android提供了SQLiteOpenHelper 类帮助创建数据库,SQLiteDatabase类帮助管理数据库

(2)、继承ContentProvider

    需要重写6个抽象方法

    

方法

说明

  • onCreate()

用于初始化provider

query()

返回数据给调用者

insert()

插入新数据到ContentProvider

updata()

更新数据

delete()

从ContentProvider中删除数据

getType()

返回CntentProvider数据的MIME类型

  eg:

  1. package com.example.mycontentprovider;
  2.  
  3. import android.content.Context;
  4. import android.database.sqlite.SQLiteDatabase;
  5. import android.database.sqlite.SQLiteOpenHelper;
  6.  
  7. public class DBhelper extends SQLiteOpenHelper{
  8. public DBhelper(Context context) {
  9. super(context, "users.db", null, );
  10. }
  11.  
  12. @Override
  13. public void onCreate(SQLiteDatabase db) {
  14. // TODO 初始化数据库
  15. db.execSQL("create table t_user(_id integer primary key,uname,upass,money)");
  16.  
  17. db.execSQL("create table t_order(_id integer primary key,user_id,price,productname)");
  18.  
  19. db.execSQL("insert into t_user(uname,upass,money) values('lisi','123',200)");
  20.  
  21. db.execSQL("insert into t_user(uname,upass,money) values('zhangsi','1234',2000)");
  22.  
  23. }
  24.  
  25. @Override
  26. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  27. // TODO 数据库升级时执行该方法
  28. if(newVersion>oldVersion)
  29. {
  30. db.execSQL("drop table if exists t_user");
  31. db.execSQL("drop table if exists t_order");
  32.  
  33. onCreate(db);
  34. }
  35.  
  36. }
  37.  
  38. }

DBhelper类 继承SQLiteOpenHelper

  1. package com.example.mycontentprovider;
  2.  
  3. import android.content.ContentProvider;
  4. import android.content.ContentUris;
  5. import android.content.ContentValues;
  6. import android.content.UriMatcher;
  7. import android.database.Cursor;
  8. import android.database.sqlite.SQLiteDatabase;
  9. import android.net.Uri;
  10.  
  11. public class UserContentProvider extends ContentProvider{
  12. /*
  13. * 这里有两个数据表t_user t_order
  14. * 给t_user Code标识1
  15. * 给t_order Code标识2
  16. * 假设当前只对表t_user操作
  17. *
  18. */
  19.  
  20. //声明该ContentProvider的唯一标识
  21. public static final String AUTHORITY="com.xqx_mydatabase";
  22. //为该组件中可以被外界访问 数据库中的资源定义Code标识
  23. public static final int CODE_USER = ;
  24. public static final int CODE_ORDER = ;
  25. //定义访问资源的URI匹配器,使用该类生成被访问的资源的URI
  26. private static UriMatcher uriMather;
  27. private DBhelper dbhelper;
  28. static {
  29. uriMather = new UriMatcher(UriMatcher.NO_MATCH);
  30. //CODE_USER(1)对应的URI:content://com.xqx_mydatabase/user
  31. uriMather.addURI(AUTHORITY, "user", CODE_USER);
  32. //CODE_USER(2)对应的URI:content://com.xqx_mydatabase/order
  33. uriMather.addURI(AUTHORITY, "order", CODE_ORDER);
  34. }
  35.  
  36. //删除返回删除成功记录的条数
  37. @Override
  38. public int delete(Uri uri, String selection, String[] selectionArgs) {
  39. // TODO Auto-generated method stub
  40. SQLiteDatabase db = dbhelper.getWritableDatabase();
  41. if(uriMather.match(uri)==CODE_USER)
  42. {
  43. //删除t_user表中的数据,返回删除记录的条数
  44. int num = db.delete("t_user", selection, selectionArgs);
  45. return num;
  46. }
  47. return ;
  48. }
  49.  
  50. @Override
  51. public String getType(Uri uri) {
  52. // TODO Auto-generated method stub
  53. return null;
  54. }
  55.  
  56. //插入记录
  57. @Override
  58. public Uri insert(Uri uri, ContentValues values) {
  59. // TODO Auto-generated method stub
  60. SQLiteDatabase db = dbhelper.getWritableDatabase();
  61. if(uriMather.match(uri)==CODE_USER)
  62. {
  63. //得到插入记录的ID
  64. long id = db.insert("t_user", null, values);
  65. //返回新插入记录的URI
  66. return ContentUris.withAppendedId(uri, id);
  67. }
  68. return null;
  69. }
  70.  
  71. //创建DBhelper对象
  72. @Override
  73. public boolean onCreate() {
  74. // TODO Auto-generated method stub
  75. dbhelper = new DBhelper(getContext());
  76. return false;
  77. }
  78.  
  79. //查询,返回Cursor对象
  80. @Override
  81. public Cursor query(Uri uri, String[] projection, String selection,
  82. String[] selectionArgs, String sortOrder) {
  83. // TODO Auto-generated method stub
  84. SQLiteDatabase db = dbhelper.getReadableDatabase();
  85. //得到uri对应的Code
  86. int code = uriMather.match(uri);
  87. Cursor cursor = null;
  88. switch (code) {
  89. //如果匹配CODE_USER 操作数据表t_user
  90. case CODE_USER:
  91. //查询数据表t_user
  92. cursor = db.query("t_user", projection, selection, selectionArgs, null, null, sortOrder);
  93. break;
  94. case CODE_ORDER:
  95. break;
  96. default:
  97. break;
  98. }
  99.  
  100. return cursor;
  101. }
  102.  
  103. //修改数据表中的数据,返回修改记录的条数
  104. @Override
  105. public int update(Uri uri, ContentValues values, String selection,
  106. String[] selectionArgs) {
  107. // TODO Auto-generated method stub
  108. SQLiteDatabase db = dbhelper.getWritableDatabase();
  109. if(uriMather.match(uri)==CODE_USER)
  110. {
  111. return db.update("t_user", values, selection, selectionArgs);
  112. }
  113.  
  114. return ;
  115. }
  116.  
  117. }

UserContentProvider.class 继承ContentProvider

(3)、在应用程序的AndroidManifest文件中注册Content Provider

  1. <!-- 注册 ContentProvider组件
  2. android:authorities:声明该组件的唯一标识
  3. android:permission:声明该组件的权限
  4. android:exported="true":声明该组件可以被外界应用访问
  5. -->
  6. <provider
  7. android:name="com.xqx.UserContentProvider"
  8. android:authorities="com.xqx.users"
  9. android:permission="com.xqx.READ_WRITE"
  10. android:exported="true"
  11. />

-----------------------------------------------------------------------------------------------

安卓开发_深入理解Content Provider的更多相关文章

  1. 安卓开发_深入理解Handler消息传递机制

    一.概述 因为子线程的run()方法无法修改UI线程(主线程)的UI界面,所以Android引入了Handler消息传递机制,实现在新创建的线程中操作UI界面 二.消息类(Message) 消息类是存 ...

  2. 安卓开发_深入理解Activity和Fragment的关系

    Fragment(碎片)是必须嵌入在 Activity(活动) 中使用的.Fragment的生命周期随着Activity的生命周期的变化而变化 一.首先让我们看下Activity和Fragment的生 ...

  3. 安卓开发_浅谈ListView(SimpleAdapter数组适配器)

    安卓开发_浅谈ListView(ArrayAdapter数组适配器) 学习使用ListView组件和SimapleAdapter适配器实现一个带图标的ListView列表 总共3部分 一.MainAc ...

  4. 安卓开发_数据存储技术_sqlite

    一.SQLite SQLite第一个Alpha版本诞生于2000年5月,它是一款轻量级数据库,它的设计目标是嵌入式的,占用资源非常的低,只需要几百K的内存就够了.SQLite已经被多种软件和产品使用 ...

  5. 安卓开发_浅谈ListView(自定义适配器)

    ListView作为一个实际开发中使用率非常高的视图,一般的系统自带的适配器都无法满足开发中的需求,这时候就需要开发人员来自定义适配器使得ListView能够有一个不错的显示效果 有这样一个Demo ...

  6. 安卓开发_数据存储技术_SharedPreferences类

    SharedPreferences类 供开发人员保存和获取基本数据类型的键值对. 该类主要用于基本类型,例如:booleans,ints,longs,strings.在应用程序结束后,数据仍旧会保存. ...

  7. 安卓开发_深入学习ViewPager控件

    一.概述 ViewPager是android扩展包v4包(android.support.v4.view.ViewPager)中的类,这个类可以让用户左右切换当前的view. ViewPager特点: ...

  8. 安卓开发_浅谈Android动画(四)

    Property动画 概念:属性动画,即通过改变对象属性的动画. 特点:属性动画真正改变了一个UI控件,包括其事件触发焦点的位置 一.重要的动画类及属性值: 1.  ValueAnimator 基本属 ...

  9. 安卓开发_浅谈Fragment之ListFragment

    ListFragment,即Fragment的一个子类,当我们用的一个Fragment只需要一个listview视图的时候使用 该类有几个特点: 1.ListFragment 本身具只有一个ListV ...

随机推荐

  1. Eclipse中java内存溢出

    1.点击Window --->Preferences,如下图  

  2. Liferay的一些应用领域

    Liferay的用途是快速的部署内外站点,统一权限管理,开发Web热插拔插件,并不是所有系统都适合 不适合Liferay的一些应用领域: 1.独立认证.简单的系统,比如一些简单的增删改查:2.复杂业务 ...

  3. “大话架构”阿里架构师分享Java程序员需要突破的技术要点

    一.源码分析 源码分析是一种临界知识,掌握了这种临界知识,能不变应万变,源码分析对于很多人来说很枯燥,生涩难懂. 源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心. 我认为是阅读源码的最核心 ...

  4. can only concatenate tuple (not "int") to tuple问题原因

    #测试程序 import os from pydub import AudioSegment #已经确定, # enPath = "%s%s/%s"%(enDir,file,enf ...

  5. 使用Charles抓取APP之HTTPS请求

    Charles是一款非常好用的抓包工具,通常使用它来进行APP开发抓包调试,尤其是HTTPS请求. 一.安装Charles 去官网(https://www.charlesproxy.com/)下载软件 ...

  6. webpack-loader是怎样炼成的

    目录 啰嗦两句 loader 是干什么的 loader 的工具箱 --context loader 实战 啰嗦两句 学习这件事从学习动机上来看,可以分成两种情况:主动学习和被动学习.主动学习就是,某天 ...

  7. postgres 更新数据表

    新增非空列: alter table t_test add column user_id integer; update t_test set user_id=0; alter table t_tes ...

  8. WinForm版图像编辑小程序(实现图像拖动、缩放、旋转、抠图)

    闲暇之余,开发一个图片编辑小程序.程序主要特点就是可方便的对多个图像编辑,实现了一些基本的操作.本文主要介绍一下程序的功能.设计思路. 执行程序 下载地址: 百度网盘.https://pan.baid ...

  9. SQL 必知必会·笔记<11>创建高级联结

    1. 使用表别名 SQL 除了可以对列名和计算字段使用别名,还允许给表名起别名.这样 做有两个主要理由: 缩短SQL 语句: 允许在一条SELECT 语句中多次使用相同的表. 使用表别名示例: SEL ...

  10. docker学习系列(四):数据持久化

    需要搞清楚一个概念的是,docker的容器设计理念是可以即开即用,用完可以随意删除,而新建容器是根据镜像进行渲染,容器的修改是不会影响到镜像,但是有时候容器里面运行的产生的数据(如mysql)或者配置 ...