`

Android4开发入门经典 之 第九部分:Content Provider【私塾在线原创】

 
阅读更多

Content Provider基础知识

http://sishuok.com/forum/blogPost/list/0/2749.html#7733

Content Provider介绍

Android中的Content Provider机制可以支持在多个应用中存储和读取数据。这也是跨应用共享数据的唯一方式。在android系统中,没有一个公共的内存区域,供多个应用共享存储数据,要在多个应用中共享数据,就需要使用Content Provider。
Android提供了一些常用数据类型的Contentprovider,比如音频、视频、图片和私人通讯录等。可在android.provider包下面找到一些android提供的Content Provider。

公开应用私有数据的两种方式

1:创建自己的Content Provider,需要继承ContentProvider类,让其他应用来访问自己的Content Provider。
2:把自己的数据通过Content Provider添加到其他应用中去,这样所有的应用都可以通过那个Content Provider来访问这些数据。
所有Content Provider都需要实现相同的接口,通过这个接口来进行数据的增加、修改、删除和查询的功能。

要使用Content Provider是非常简单的,只需要获得ContentResolver对象,然后通过这个对象进行数据的CRUD操作。获得ContentResolver的方式如下:ContentResolver cr = getContentResolver();

Android系统负责初始化所有的Content Provider,不需要用户自己去创建。实际上,Content Provider的用户都不可能直接访问到Content Provider实例,只能通过ContentResolver在中间代理。
Content Provider展示数据类似一个数据库的表。其中:每行有个值唯一的数字字段,名为_ID,可用于对表中指定记录的定位;Content Provider返回的数据结构,类似JDBC的ResultSet,在Android中,是Cursor对象。

理解URI

1:每个Content Provider定义一个唯一的公开的URI,用于指定到它的数据集。一个Content Provider可以包含多个数据集,这样,就需要有多个URI与每个数据集相对应。
2:URI的格式,标准的格式分成了四个部分,示例如下:
content://     cn.javass.users     /students       /12
(1)content://:标准前缀,用来说明一个Content Provider控制这些数据
(2)cn.javass.users:URI的标识,它定义了是哪个Content Provider的实现来提供这些数据。为了保证URI标识的唯一性,它必须是一个完整的、小写的、ContentProvider实现类名。这个标识在<provider> 元素的 authorities属性中说明: <provider name=”.Users”  authorities=”cn.javass.users”>
(3)/students :路径,Content Provider用来确定当前需要什么类型的数据,URI中可能包括0到多个路径
(4)12:具体某条数据的标识,如果URI中包含,表示需要获取的记录的ID;如果没有ID,就表示返回全部。

ContentResolver的使用

1:ContentResolver通过URI来操作ContentProvider提供的数据。因此你必须知道要操作数据的URI,除此之外,还必须知道要操作的数据段的名称,以及此数据段的数据类型。如果你想要获取一个特定的记录,你还必须知道此记录的ID
2: ContentResolver的常用方法是完全类似于数据库操作的,如下:
(1)新增:insert(Uri url, ContentValues values),返回Uri
(2)删除:delete(Uri url, String where, String[] selectionArgs),返回操作的记录条数
(3)修改:update(Uri uri, ContentValues values, String where, String[] selectionArgs) ,返回操作的记录条数
(4)查询:query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder),返回Cursor

创建自己的Content Provider

UriMatcher:用于匹配Uri,基本用法如下:

1:注册能匹配的Uri
(1)常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码(-1)。
 UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
(2)如果match()方法匹配某个路径,设置一个返回的值。
例如匹配content://com.android.calendar/calendars路径,返回匹配码为1。uriMatcher.addURI(“content://com.android.calendar”, “calendars”, 1);
(3)如果match()方法匹配某个URI,设置一个返回的值。例如匹配
content://com.android.calendar/calendars/11这个URI,返回匹配码为2。uriMatcher.addURI(“content://com.android.calendar”, “calendars/#”, 2);
2:注册完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法对输入的Uri进行匹配,如果匹 配就返回匹配码。

ContentUris:用于操作Uri路径后面的ID部分,它有两个比较实用的方法:

1:withAppendedId(uri, id)用于为路径加上ID部分
2:parseId(uri)方法用于从路径中获取ID部分
 

创建自己的Content Provider,基本步骤如下:

1:写一个类继承ContentProvider,就需要实现相应的方法
2: Content Provider通常需要对外提供:CONTENT_URI、URI_AUTHORITY,对外的数据字段常量等,例如:

java代码:
  1. public static final String URI_AUTHORITY = "cn.javass.mycp";  
  2. public static final String URI_PATH = "Users";  
  3. public static final String URI_PATH2 = "Users/#";  
  4. public static final Uri CONTENT_URI = Uri.parse("content://"  
  5. + URI_AUTHORITY + "/" + URI_PATH);  
  6. //对外的数据字段  
  7. public static final String COLUMN_UUID = "uuid";  
  8. public static final String COLUMN_NAME = "name";  
3:提供UriMatcher,用来判断外部传入的Uri是否带有id,好区分处理:

java代码:
  1. public static final int ALL_RECORDS = 1;  
  2. public static final int SINGLE_RECORD = 2;  
  3. public static UriMatcher sMatcher = null;  
  4. static {  
  5. sMatcher = new UriMatcher(UriMatcher.NO_MATCH);  
  6. sMatcher.addURI(URI_AUTHORITY, URI_PATH, ALL_RECORDS);  
  7. sMatcher.addURI(URI_AUTHORITY, URI_PATH2, SINGLE_RECORD);  
  8. }  
然后就是根据自己保存数据的具体实现,来实现Content Provider的方法,这里以前面SQLite的示例来演示如何实现这些方法。

新增功能的简单实现


java代码:
  1. public Uri insert(Uri uri, ContentValues values) {  
  2. Uri retUri = null;  
  3. if(sMatcher.match(uri)==ALL_RECORDS){  
  4. //判断是否需要处理,只有符合的才处理  
  5. SQLiteDatabase db = dh.getWritableDatabase();  
  6. long id = db.insert("tbl_user",null, values);  
  7. retUri = ContentUris.withAppendedId(uri, id);  
  8. }  
  9. return retUri;  
  10. }  

查询功能的简单实现


java代码:
  1. public Cursor query(Uri uri, String[] projection, String selection,  
  2. String[] selectionArgs, String sortOrder) {  
  3. if(sMatcher.match(uri)==ALL_RECORDS){  
  4. SQLiteDatabase db = dh.getWritableDatabase();  
  5.    
  6. Cursor c = db.query("tbl_user", projection,  
  7. selection,selectionArgs, """", sortOrder,"");  
  8.    
  9. return c;  
  10. }else if(sMatcher.match(uri)==SINGLE_RECORD){  
  11. //这里应该处理带id的uri,省略了.....  
  12. }  
  13. return null;  
  14. }  

修改功能的简单实现


java代码:
  1. public int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) {  
  2. int ret = 0;  
  3. if(sMatcher.match(uri)==ALL_RECORDS){  
  4. //判断是否需要处理,只有符合的才处理  
  5. SQLiteDatabase db = dh.getWritableDatabase();  
  6. ret = db.update("tbl_user",values,selection, selectionArgs);  
  7. }else if(sMatcher.match(uri)==SINGLE_RECORD){//这里应该处理带id的uri,省略了.....}  
  8. return ret;  
  9. }  

删除功能的简单实现


java代码:
  1. public int delete(Uri uri, String selection, String[] selectionArgs) {  
  2. int ret = 0;  
  3. if(sMatcher.match(uri)==ALL_RECORDS){  
  4. //判断是否需要处理,只有符合的才处理  
  5. SQLiteDatabase db = dh.getWritableDatabase();  
  6. ret = db.delete("tbl_user", selection, selectionArgs);  
  7. }else if(sMatcher.match(uri)==SINGLE_RECORD){//这里应该处理带id的uri,省略了.....}  
  8. return ret;  
  9. }  

getType的简单实现,getType方法返回数据的MIME type

 

java代码:
  1. public String getType(Uri uri) {  
  2. switch (sMatcher.match(uri)) {  
  3.       case ALL_RECORDS:  
  4.           return "vnd.android.cursor.dir/vnd.cn.javass.users";  
  5.       case SINGLE_RECORD:  
  6.           return "vnd.android.cursor.item/vnd.cn.javass.users";  
  7.       default:  
  8.           throw new IllegalArgumentException("unknown URI " + uri);  
  9. }  
  10. }  

onCreate方法的简单实现


java代码:
  1. public boolean onCreate() {  
  2. if (mContext == null) {mContext = this.getContext();}  
  3. if(dh==null){  
  4. dh = new DBHelper(mContext,"testDB1",null,1);  
  5. }  
  6. return true;  
  7. }  
 

使用自己的Content Provider

有了自己实现的Content Provider后,要使用就很简单了。首先要在AndroidManifest.xml文件中注册自己的Content Provider,示例如下:


java代码:
  1. <provider android:name=".MyCP"          
  2. android:authorities="cn.javass.mycp"></provider>   

使用新增的功能,先示范单条新增:


java代码:
  1. ContentValues values = new ContentValues();  
  2. values.put(MyCP.COLUMN_UUID, "test1");  
  3. values.put(MyCP.COLUMN_NAME,"cc1");  
  4. Uri uri = getContentResolver().insert(MyCP.CONTENT_URI, values);   

还可以使用批处理的方式来使用新增的功能,示例如下:


java代码:
  1. ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();  
  2. ops.add(ContentProviderOperation.newInsert(MyCP.CONTENT_URI)  
  3. .withValue(MyCP.COLUMN_UUID, "test2")  
  4. .withValue(MyCP.COLUMN_NAME, "cc2")  
  5. .build());  
  6. ops.add(ContentProviderOperation.newInsert(MyCP.CONTENT_URI)  
  7. .withValue(MyCP.COLUMN_UUID, "test3")  
  8. .withValue(MyCP.COLUMN_NAME, "cc3")  
  9. .build());  
  10. try {  
  11. getContentResolver().applyBatch(MyCP.URI_AUTHORITY,ops);  
  12. catch (Exception e) {  
  13. e.printStackTrace();  
  14. }  

使用查询的功能:


java代码:
  1. Cursor c = getContentResolver().query(MyCP.CONTENT_URI,           
  2. new String[] {MyCP.COLUMN_UUID, MyCP.COLUMN_NAME}, null,nullnull);  
  3. while (c.moveToNext()) {  
  4. String dId = ""+c.getString(c.getColumnIndex(MyCP.COLUMN_UUID));  
  5. String name = c.getString(c.getColumnIndex(MyCP.COLUMN_NAME));  
  6. Log.i("now query","dataId="+dId+",name="+name);  
  7. }  

使用修改的功能,这里只示例单条的处理,批处理的方式参见前面新增的实现:


java代码:
  1. ContentValues values = new ContentValues();  
  2. values.put(MyCP.COLUMN_UUID, "test1");  
  3. values.put(MyCP.COLUMN_NAME,"cc1update");  
  4. getContentResolver().update(MyCP.CONTENT_URI, values,MyCP.COLUMN_UUID+"=?",new String[]{"test1"});  

使用删除的功能:


java代码:
  1. getContentResolver().delete(MyCP.CONTENT_URI, MyCP.COLUMN_UUID + "=?",new String[] { "test2" });   

几点说明

1:这里创建的自己的Content Provider是非常简单的,主要是沿用了前面SQLite的示例,当然也可以使用文件操作的示例
2:一般来说,提供Content Provider的数据,应该有一个long型的id字段,由于前面的示例没有,所以上面的示例没有提供
3:在自己的Content Provider实现里面,应该根据Uri是否带有id的情况进行相应的处理,为了示例的简单,就没有那么实现了
4:由于Content Provider可能被多个应用同时使用,因此需要在实现Content Provider的时候进行多线程控制,目前并没有实现这样的功能
5:处理多线程的一个好方式就是,当数据发生改变的时候,通知所有相关的数据改变,比如在新增、修改、删除方法里面提供:

java代码:
  1. getContext().getContentResolver().notifyChange(Uri, null);  

操作通讯录

要使用其他应用提供的Content Provider是非常简单的,只需要获取ContentResolver对象,然后使用它的方法操作数据即可。
这里以最常见的功能:操作通讯录 为例来示范如何使用Content Provider。
记得添加操作Contacts需要的权限

java代码:
  1. <uses-permission android:name="android.permission.WRITE_CONTACTS"/>  
  2. <uses-permission android:name="android.permission.READ_CONTACTS"/>  

先看看新增的功能实现,先以单独操作的方式来示范:


java代码:
  1. //1:添加原始的帐号信息  
  2. ContentValues values = new ContentValues();  
  3. values.put(RawContacts.ACCOUNT_TYPE, "userAccount");  
  4. values.put(RawContacts.ACCOUNT_NAME, "cc");  
  5. Uri rawContactUri = getContentResolver().insert(RawContacts.CONTENT_URI, values);  
  6. long rawContactId = ContentUris.parseId(rawContactUri);  
  7. //2:添加账户人员的姓名  
  8. values.clear();  
  9. values.put(Data.RAW_CONTACT_ID, rawContactId);  
  10. values.put(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);  
  11. values.put(StructuredName.DISPLAY_NAME, "cc1Name");  
  12. getContentResolver().insert(Data.CONTENT_URI, values);  
  13.    
 

 

java代码:
  1. //3:添加电话信息  
  2. values.clear();  
  3. values.put(Data.RAW_CONTACT_ID, rawContactId);  
  4. values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);  
  5. values.put(Phone.NUMBER, "13567890987");  
  6. values.put(Phone.TYPE, Phone.TYPE_CUSTOM);  
  7. values.put(Phone.LABEL, "cc1");  
  8. Uri dataUri = getContentResolver().insert(Data.CONTENT_URI,values);  
  9. //同理,还可以添加Email等等信息  

新增的功能实现,以批处理操作的方式来示范:

前面第一步,添加原始的帐号信息的过程是一样的,批处理最好用在后面都是对Data进行操作的过程中,示例如下:
 

java代码:
  1. ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();  
  2. ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)  
  3. .withValue(Data.RAW_CONTACT_ID, rawContactId)  
  4. .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)  
  5. .withValue(StructuredName.DISPLAY_NAME, "cc1Name")  
  6. .build());  
  7. ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)  
  8. .withValue(Data.RAW_CONTACT_ID, rawContactId)  
  9. .withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)  
  10. .withValue(Phone.NUMBER, "13567890989")  
  11. .withValue(Phone.TYPE, Phone.TYPE_CUSTOM)  
  12. .withValue(Phone.LABEL, "cc1").build());  
  13. try {  
  14. getContentResolver().applyBatch(ContactsContract.AUTHORITY,ops);  
  15. catch (Exception e) {  
  16. e.printStackTrace();  
  17. }  

查询功能的实现,示例如下:


java代码:
  1. //1:得到要操作的原始帐号信息  
  2. Cursor c = getContentResolver().query(RawContacts.CONTENT_URI,  
  3. new String[]{RawContacts._ID},RawContacts.ACCOUNT_NAME+"=? ",new String[]{"cc"}, null);  
  4. long rawContactId = 0L;  
  5. while(c.moveToNext()){  
  6. rawContactId = c.getLong(c.getColumnIndex(RawContacts._ID));  
  7. }  
  8. c.close();  
  9. //然后开始获取你需要的数据,这里示范读取电话数据,同理可以读取其他的数据,如Email数据  
  10. c = getContentResolver().query(Data.CONTENT_URI,           
  11. new String[] {Data._ID, Phone.NUMBER, Phone.TYPE, Phone.LABEL},  
  12. Data.RAW_CONTACT_ID+"=?"+" and "+Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'",  
  13.                new String[]{""+rawContactId}, null);  
  14. while (c.moveToNext()) {  
  15. String dId = ""+c.getInt(c.getColumnIndex(Data._ID));  
  16. String name = c.getString(c.getColumnIndex(Phone.LABEL));  
  17. String num = c.getString(c.getColumnIndex(Phone.NUMBER));  
  18. String type = c.getString(c.getColumnIndex(Phone.TYPE));  
  19. Log.i("now query","dataId="+dId+",name="+name+",name="+num+", type="+type);  
  20. }  

修改功能的实现,示例如下:


java代码:
  1. //1:应该要先得到要修改的Data数据,这里为了示范简单,就直接改了  
  2.    
  3. //2:设置修改的值  
  4. ContentValues values = new ContentValues();  
  5. values.put(Data.RAW_CONTACT_ID, 3);//测试时的数据是3  
  6. values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);  
  7. values.put(Phone.NUMBER, “13567890981”);//修改了  
  8. values.put(Phone.TYPE, Phone.TYPE_CUSTOM);  
  9. values.put(Phone.LABEL, “upuser1”);//修改了  
  10.    
  11. getContentResolver().update(Data.CONTENT_URI, values,  
  12. Data._ID + "=?",  
  13. new String[] { “31” });//测试时的id是31  
修改也可以使用批处理的功能来实现,可以参考前面新增的批处理实现。

删除功能的实现,示例如下:


java代码:
  1. //1:应该要先得到要删除的Data数据,这里为了示范简单,就直接改了  
  2. //2:删除数据,直接删除原始的内容  
  3. getContentResolver().delete(RawContacts.CONTENT_URI, Data._ID + "=?",  
  4. new String[] { "31" });  
只要删除了原始的帐号数据,那么所有与它附属的数据,比如电话、Email等都会被自动删除。如果一个Contact对应的所有原始帐号数据都被删除掉了,那么Contact会被自动删除掉。
 
视频配套PPT,视频地址【 Android4开发入门经典独家视频课程
4
0
分享到:
评论

相关推荐

    android一步一步最基础学习__新手

    第一讲:Android开发环境的搭建 第二讲:Android系统构架分析和应用程序目录结构分析 第三讲:Android模拟器的使用 emulator 第四讲:Activity入门指南 Activity 第五讲:用户界面 View(一) FrameLayout, ...

    android content provider示例程序(简单记账)

    博文《android基础知识05:四大组件之content provider》的示例程序,实现了content provider 的基本功能。

    android.support.v4.jar android.support.v7.appcompat.jar

    两个java库,Unity发布安卓项目经常会有需要。 发包时遇到报错: Didn't find class "androidx.core.content.FileProvider" on path... ...&lt;provider android:name="androidx.core.content.FileProvider

    Android Content Provider Demo

    Android Content Provider Demo

    Android基础 Content Provider

    1、什么是内容提供者 2、怎样创建内容提供者 3、通过内容提供者完成CRUD操作 4、访问内容提供者 5、监听内容提供者数据变化 6、两个案例:监听短信以及操作联系人 最最重要的是包含了源码

    《Google Android开发入门与实战》.pdf

     本书内容上涵盖了用android开发的大部分场景,从android基础介绍、环境搭建、sdk介绍、market使用,到应用剖析、组件介绍、实例演示等方面。从技术实现上,讲解了5个android平台下的完整综合实例及源代码分析,...

    Android新手Content Provider获取通讯录,短信,通话记录

    理解Content Uri的概念和作用,掌握通过Content Provider访问联系人的方法,掌握通过Content Provider访问通话记录的方法,掌握通过Content Provider访问短信的方法。

    android中Content Provider

    NULL 博文链接:https://dampce032.iteye.com/blog/975663

    系统集成继续教育课程11 201708 考试题

    4 播放课后练习查看答案 相关技术及应用 Android 应用开发实践 第十九节:Content Provider(三) 5 播放课后练习查看答案 相关技术及应用 Android 应用开发实践 第二十一节:Broadcast Receiver和Notification(一...

    老罗android开发视频教程全集百度网盘下载

    【第一版第九章】老罗Android开发视频--存储数据和文件(7集) 【第一版第十章】老罗Android开发视频--对话框介绍(4集) 【第一版第十一章】老罗Android开发视频--通知的使用(2集) 【第一版第十二章】老罗...

    《Android应用开发详解》源码_文档讲解

    第8章 Android广播事件处理 Broadcast Receiver 第9章 Android中的数据存取 第10章 Content Provider 第11章 Android中的多媒体应用 第12章 Android中的图形图像 第13章 Android中的互联网应用 第14章 Android中的...

    《Android开发案例驱动教程》源码

    《Android开发案例驱动教程》部分源码 目 录 出版说明 前言 第1章 Android操作系统概述 1 第2章 Android开发环境搭建 3章 第一个Android程序 19 第4章 Android UI基础 58 第5章 UI基础控件 79 第6章 UI高级控件 105 ...

    android network_provider

    这是在Eclipse环境下开发的android应用程序,主要是实现了在室内定位,获取所在地的经纬度信息

    《Android开发案例驱动教程》

    第9章 Activity和Intent 219 第10章 Android数据存储 248 第11章 Content Provider 302 第12章 多媒体开发 341 第13章 Service 385 第14章 Broadcast Receiver和Notification 422 第15章 云端应用 449 第16章 Google...

    Android Content Provider用法样例.rar

    Android Content Provider用法样例,解析如何使用“内容提供商”Content Provider共享不同应用的数据,本Android例子将使用Content Provider实现了获取联系人信息,里面的注释非常丰富,是学习android的好资料。

    Android高薪之路:Android程序员面试宝典 李宁

    《Android高薪之路:Android程序员面试宝典》目录: 第1章 Android入门 1 1 关于Android的非技术问题 1 1 1 为什么看好 Android 1 1 2 以前是否从事过Android的工作 做过哪些工作 1 1 3 你做的最复杂的界面是什么 1 ...

    android provider

    android provider

    Android应用开发详解

    第9章 Android中的数据存取 Android中的数据存取,讲述了Android的四种数据存取方法:Preference、File、SQLite和Network 第10章 Content Provider Content Provider,讲述了Android不同应用程序之间相互共享数据...

    《Android开发权威指南》 PDF (安卓sdk 2.3)

    第二部分 基础篇,包括第3章~第16章,第3章 Android程序设计基础、第4章 用户界面开发基础、第5章 控件(Widget)详解、第6章 菜单、第7章 信息提醒(对话框、Toast与Notification)、第8章 数据存储、第9章 Android...

Global site tag (gtag.js) - Google Analytics