【转】Pro Android学习笔记(七):了解Content Provider(下上)
我们通过一个Content Provider小例子进行详细说明。数据源是一个SQLite数据库,名字为books.db,该数据库只含有一个表格,名字为books。表格中含有name,isbn,author,created_date和modified_date几列。我们通过一个名为BookProvider的内容提供者将数据源运行封装,并对外提供增删改查的接口。
首先:定义Content Provider的结构
创建一个Provider,我们首先需要定义好这个provider的结构。通过constant的定义,阐明接口的含义。本例在BookProviderMetaData类中定义,包括数据库,URI,列名等等,具体如下:
/* 定义一个类专门给出provider结构,以常量方式给出,根据具体的数据源结构,数据库对应一个authority,而不同的表格为不同的page segment,本例只有一个表格。本例为二层结构。Content://authority/table_name/book_item */ public class BookProviderMetaData { /* 步骤1:定义content://authority以及对应数据源(db)的相关属性 */ /* 步骤1.1 定义provider的内容:以constant的方式定义authority*/ public static final String AUTHORITY = "cn.flowingflying.provider.BookProvider"; /* 步骤1.2 定义数据源的相关信息,本例对相关的SQLite数据库进行定义 */ public static final String DATABASE_NAME = "books.db"; public static final int DATABASE_VERSION = 1; public static final String BOOKS_TABLE_NAME = "books"; /* 步骤1.3 定义私有的构造函数,目的是本类只进行结构描述,只用于定义引用,不能对本类创建对象 */ private BookProviderMetaData(){}; /* 步骤2:采用内部类定义content://authority/page_segment、具体的item和对应数据源(table),本例只有一个表格,其uri的引用方式为BookProviderMetaData.BookTableMetaData.CONTENT_URI。SQLite的表格实现BaseColumns接口,其中_id是该接口自带的,常量为_ID,每行由系统自动生成唯一的_id */ public static final class BookTableMetaData implements BaseColumns{ /* 步骤2.3 定义私有构造类,表明本类制作定义引用,不生成对象 */ private BookTableMetaData(){}; //不应该进行该对象的创建。只用于描述 /* 步骤2.1 定义provider的结构,本层结构已经映射到具体的item,定义相关的uri和MIME*/ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/books"); public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.cn.flowingflying.book"; public static final String CONTENT_ITEM_TYPE="vnd.android.cursor.item/vnd.cn.flowingflying.book"; /* 步骤2.2 定义数据源的相关的结构,即表格的相关信息*/ public static final String TABLE_NAME = "books"; public static final String BOOK_NAME = "name"; public static final String BOOK_ISDN = "isbn"; public static final String BOOK_AUTHOR = "author"; public static final String CREATED_DATE = "created"; public static final String MODIFIED_DATE = "modified"; public static final String DEFAULE_SORT_ORDER = "modified DESC"; } } |
其次:继承ContentProvider抽象类,实现我们自己的Provider
BookProvider是android.content.ContentProvider的extend,需要对创建onCreate()、获取类型getType(),以及数据的增删改查 query(),add(),delete(),update进行重写。
/* 创建我们的BookProvider,先对数据源进行处理,为下一步对provider提供的增删改查等接口进行准备,即先处理数据源,然后对数据源的I/O接口(provider)进行处理。 */ /* 步骤1.3:@Override onUpgrade,当发现数据库的版本低于当前版本时,对数据库进行升级,本例将删除原来的 全部数据,重新建立新的表格*/ private DatabaseBookHelper mDataSource = null; //步骤2:设置并获取数据源对象 @Override @Override /* 步骤2:关联数据源,本例创建数据库的对象 */ @Override @Override |
第三:实现BookProvider的询问MIME,以及数据的增删改查
(1)获取数据类型,重写getType()
/* 通过getType(),Provider对外提供uri获取的数据类型(MIME Type),分为collection和item两种情况。*/ public String getType(Uri uri) { switch(sUriMatch.match(uri)){ case BOOK_COLLECTION_URI_INDICATOR: return BookTableMetaData.CONTENT_TYPE; case BOOK_ITEM_URI_INDICATION: return BookTableMetaData.CONTENT_ITEM_TYPE; default: //无效uri throw new IllegalArgumentException("Unknown Uri " + uri); } } |
(2)数据查询,重写query(),返回游标
public Cursor query(Uri uri, String[] protection, String selection, String[] selectionArgs, String order) { //1、通过SQLiteQueryBuilder,设置数据库查询的信息。Uri有两种情况,一种是collect,一种已经指定某个item, 两者需要区别对待,item将获取_ID,并在where中增加一个匹配条件。 SQLiteQueryBuilder dbQuery = new SQLiteQueryBuilder(); switch(sUriMatch.match(uri)){ case BOOK_COLLECTION_URI_INDICATOR: dbQuery.setTables(BookTableMetaData.TABLE_NAME); dbQuery.setProjectionMap(sBooksProjectionMap); //设定与project的映射关系 break; case BOOK_ITEM_URI_INDICATION: dbQuery.setTables(BookTableMetaData.TABLE_NAME); dbQuery.setProjectionMap(sBooksProjectionMap); //设定与project的映射关系 // 通过getPathSegments( )获取具体的ID,path segment从0还是计算,本例中0为books,1为# dbQuery.appendWhere(BookTableMetaData._ID + "=" + uri.getPathSegments().get(1)); break; default: throw new IllegalArgumentException("Unknown Uri " + uri); } //2、对缺省进行设置,如排序 String orderBy; if(TextUtils.isEmpty(order)){ orderBy = BookTableMetaData.DEFAULE_SORT_ORDER; }else{ orderBy = order; } //3、查询数据库 SQLiteDatabase db = mDataSource.getReadableDatabase(); Cursor c = dbQuery.query(db, protection, selection, selectionArgs, null, null, orderBy); //4、向系统注册通知:观察所要查询的数据,即Uri对应的数据,是否发生变化。开发者通过provider接口获取数据, 可通过通知获知数据已经发生变更。 c.setNotificationUri(getContext().getContentResolver(), uri); return c; } |
(3)数据增加,重写insert(),返回新增数据的uri
public Uri insert(Uri uri, ContentValues initalValue) { //1、检查uri是否合法,由于新增item,故uri只能是collection方式 if(sUriMatch.match(uri) != BOOK_COLLECTION_URI_INDICATOR){ throw new IllegalArgumentException("Unknown Uri " + uri); } //2、从ContentValues中获取数据,检查数据是否有效和完备 //3、在数据库表格中增加row |
(4)数据删除,重写delete(),返回成功删除的item数目
public int delete(Uri uri, String where, String[] whereArgs) { int count = 0; //记录删除item数目 SQLiteDatabase db = mDataSource.getWritableDatabase(); //删除:根据uri分为collection和item两种情况 switch(sUriMatch.match(uri)){ case BOOK_COLLECTION_URI_INDICATOR: count = db.delete(BookTableMetaData.TABLE_NAME, where, whereArgs); break; case BOOK_ITEM_URI_INDICATION: String id = uri.getPathSegments().get(1); //从0开始计算,本例中0为content://xxxx/books/2中的books count = db.delete(BookTableMetaData.TABLE_NAME, BookTableMetaData._ID + "=" + id +(TextUtils.isEmpty(where) ? "" : " AND (" + where + ")"), whereArgs); break; default: throw new IllegalArgumentException("Unknown Uri " + uri); } getContext().getContentResolver().notifyChange(uri, null); //通知该uri的数据发生变化 return count; } |
(5)数据更改,重写update(),返回成功修改的item数目
public int update(Uri uri, ContentValues values, String whereClause, String[] whereArgs) { int count = 0; //记录更新item数目 SQLiteDatabase db = mDataSource.getWritableDatabase(); //更新:根据uri分为collection和item两种情况 switch(sUriMatch.match(uri)){ case BOOK_COLLECTION_URI_INDICATOR: count = db.update(BookTableMetaData.TABLE_NAME, values, whereClause, whereArgs); break; case BOOK_ITEM_URI_INDICATION: count = db.update(BookTableMetaData.TABLE_NAME, values, BookTableMetaData._ID + "=" + uri.getPathSegments().get(1) + (!TextUtils.isEmpty(whereClause)? " AND (" + whereClause + ")" : ""), whereArgs); break; default: throw new IllegalArgumentException("Unknown Uri " + uri); } getContext().getContentResolver().notifyChange(uri,null); //通知该uri的数据发生变化 return count; } |
最后:在Manifest上注册BookProvider
<provider android:name=".BookProvider" android:authorities="cn.flowingflying.provider.BookProvider" /> |
相关链接: 我的Android开发相关文章
转自http://blog.csdn.net/flowingflying/article/details/9242995
【转】Pro Android学习笔记(七):了解Content Provider(下上)的更多相关文章
- 【转】 Pro Android学习笔记(六七):HTTP服务(1):HTTP GET
目录(?)[-] HTTP GET小例子 简单小例子 出现异常NetworkOnMainThreadException 通过StrictMode进行处理 URL带键值对 Andriod应用可利用ser ...
- 【转】 Pro Android学习笔记(五五):调试和分析(3):adb命令、模拟器控制台和StrictMode
目录(?)[-] adb命令 模拟器Console StrictMode adb命令 我们在学习SQLite的使用,介绍过部分adb命令的使用,见Pro Android学习笔记(五):了解Conten ...
- 【转】 Pro Android学习笔记(五六):配置变化
目录(?)[-] Activity的destorycreate过程 Fragment的destorycreate过程 onSaveInstanceState saveFragmentInstanceS ...
- 【转】 Pro Android学习笔记(四十):Fragment(5):适应不同屏幕或排版
目录(?)[-] 设置横排和竖排的不同排版风格 改写代码 对于fragment,经常涉及不同屏幕尺寸和不同的排版风格.我们在基础小例子上做一下改动,在横排的时候,仍是现实左右两个fragment,在竖 ...
- 【转】 Pro Android学习笔记(二二):用户界面和控制(10):自定义Adapter
目录(?)[-] 设计Adapter的布局 代码部分 Activity的代码 MyAdapter的代码数据源和构造函数 MyAdapter的代码实现自定义的adapter MyAdapter的代码继续 ...
- 【转】 Pro Android学习笔记(十九):用户界面和控制(7):ListView
目录(?)[-] 点击List的item触发 添加其他控件以及获取item数据 ListView控件以垂直布局方式显示子view.系统的android.app.ListActivity已经实现了一个只 ...
- Pro Android学习笔记 ActionBar(1):Home图标区
Pro Android学习笔记(四八):ActionBar(1):Home图标区 2013年03月10日 ⁄ 综合 ⁄ 共 3256字 ⁄ 字号 小 中 大 ⁄ 评论关闭 ActionBar在A ...
- 【转】 Pro Android学习笔记(八二):了解Package(1):包和进程
文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowingflying/ 在之前,我们已经学习了如何签发apk,见P ...
- 【转】 Pro Android学习笔记(五二):ActionBar(5):list模式
可以在action bar中加入spinner的下来菜单,有关spinner,可以参考Pro Android学习笔记(二十):用户界面和控制(8):GridView和Spinner. list的样式和 ...
- 【转】 Pro Android学习笔记(四二):Fragment(7):切换效果
目录(?)[-] 利用setTransition 利用setCustomAnimations 通过ObjectAnimator自定义动态效果 程序代码的编写 利用fragment transactio ...
随机推荐
- Gitlab来做代码review
Gitlab来做代码review 代码review是代码质量保障的手段之一,同时开发成员之间代码review也是一种技术交流的方式,虽然会占用一些时间,但对团队而言,总体是个利大于弊的事情.如何借助现 ...
- 高速修复汉澳sinox命令解释程序bash shell漏洞
bash是linux默认命令行管理程序shell.汉澳 sinox也安装有,尽管sinox并没有默认使用bash.可是用户一旦使用就会可能被通过漏洞入侵,所以必须高速修复.尽管sinox使用freeb ...
- Windows 驱动入门(二)代码结构
windows驱动程序基础.转载标明出处:http://blog.csdn.net/ikerpeng/article/details/38777641 windows驱动程序结构: 我想说的是wind ...
- python 基础 1.6 python 帮助信息及数据类型间相互转换
一. 帮助信息 # dir() 方法 查看函数的方法 # help() # type() 查看类型 name = raw_input('please input you name ...
- 【BZOJ1316】树上的询问 点分治+set
[BZOJ1316]树上的询问 Description 一棵n个点的带权有根树,有p个询问,每次询问树中是否存在一条长度为Len的路径,如果是,输出Yes否输出No. Input 第一行两个整数n, ...
- python知识点导图(搜集)
第一章 基本环境 第二章 内置类型 第三章 表达式 第四章 函数 第五章 迭代器 第六章 模块 第七章 类 第八章 异常 第九章 装饰器 第十章 描述符 第十一章 元类 第十二章 标准库 Re模块 附 ...
- Vue引入js、css文件
1.js调用方法一:这是组件内调用,非公共js 2.js调用方法二:公共jsmain.js内加入公共jsVue.prototype.timeago = timeago 3.引入公共css在main.j ...
- php函数: set_include_path
<?php $p =get_include_path(); $p.=PATH_SEPARATOR.'./bp/'; $p.=PATH_SEPARATOR.'./CLI/'; $p.=PATH_S ...
- Android之Handler使用方法总结
方法一:(java习惯,在android平台开发时这样是不行的,由于它违背了单线程模型) 刚刚開始接触android线程编程的时候,习惯好像java一样,试图用以下的代码解决这个问题 new T ...
- .net概念(转)
你主要想问.Net和Java的差异在哪里 Java是开发语言 .Net叫开发平台 但事实上你管Java叫开发平台也没错 平台就是一个供你在上面进行开发的平台 (英语叫Framework,也可以翻译成“ ...