ContentProvider 使用示例(转载)
ContentProvider 使用示例(转载)
当数据需要在应用程序间共享时,我们就可以利用ContentProvider为数据定义一个URI。之后其他应用程序对数据进行查询或者修改时,只需要从当前上下文对象获得一个ContentResolver(内容解析器)传入相应的URI就可以了。本节中将以前面创建的code.db数据库为例,向读者介绍如何定义一个ContentProvider,以及如何在其他程序中使用ContentResolver访问URI所指定的数据。
9.3.1 定义ContentProvider(1)
要为当前应用程序的私有数据定义URI,就需要专门定义一个继承自ContentProvider的类,然后根据不同的操作调用的方法去实现这些方法的功能。下面我们用SQLite2这个例子,来为它的数据库code.db定义一个URI。
首先,在SQLite2的包中创建一个新类ContryCode.java,来装入所有与数据库操作有关的静态字段,以便于打包成JAR文件供其他应用程序调用。
- package com.studio.android.chp9.ex3;
- import com.sun.jndi.toolkit.url.Uri;
- publicclass CountryCode {
- publicstaticfinal String DB_NAME = "code.db";
- publicstaticfinal String TB_NAME = "countrycode";
- publicstaticfinalint VERSION = 1;
- publicstaticfinal String ID = "_id";
- publicstaticfinal String COUNTRY = "country";
- publicstaticfinal String CODE = "code";
- publicstaticfinal String AUTHORITY = "com.studio.andriod.provider.countrycode";
- publicstaticfinalint ITEM = 1;
- publicstaticfinalint ITEM_ID = 2;
- publicstaticfinal String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.studio.android.countrycode";
- publicstaticfinal String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.studio.android.countrycode";
- publicstaticfinal Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/item");
- }
package com.studio.android.chp9.ex3; import com.sun.jndi.toolkit.url.Uri; public class CountryCode {
public static final String DB_NAME = "code.db";
public static final String TB_NAME = "countrycode";
public static final int VERSION = 1;
public static final String ID = "_id";
public static final String COUNTRY = "country";
public static final String CODE = "code";
public static final String AUTHORITY = "com.studio.andriod.provider.countrycode";
public static final int ITEM = 1;
public static final int ITEM_ID = 2;
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.studio.android.countrycode";
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.studio.android.countrycode";
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/item"); }
其中DB_NAME、TB_NAME和VERSION分别定义了数据库和表的名称以及数据库的版本号。
ID、COUNTRY和CODE分别定义的是表中的各个列的列名。
AUTHORITY定义了标识ContentProvider的字符串
ITEM和ITEM_ID分别用于UriMatcher(资源标识符匹配器)中对路径item和item/id的匹配号码。
CONTENT_TYPE和CONTENT_ITEM_TYPE定义了数据的MIME类型。
需要注意的是,单一数据的MIME类型字符串应该以vnd.android.cursor.item/开头,数据集的MIME类型字符串则应该以vnd.android.cursor.dir/开头。CONTENT_URI定义的是查询当前表数据的content://样式URI。
接下来,同样是在SQLite2的包中创建一个继承自ContentProvider的类MyProvider.java,来实现对数据操作的各个方法。这里将用到MyHelper来辅助获得SQLiteDatabase对象,虽然也可以直接使用Context.OpenOrCreate()方法获得,但不及使用数据库打开辅助类方便。
- import android.content.ContentProvider;
- import android.content.UriMatcher;
- publicclass MyProvider extends ContentProvider {
- MyHelper dbHelper;
- privatestaticfinal UriMatcher sMatcher;
- static {
- sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
- sMatcher.addURI(CountryCode.AUTHORITY, "item", CountryCode.ITEM);
- sMatcher.addURI(CountryCode.AUTHORITY, "item/#", CountryCode.ITEM_ID);
- }
- }
import android.content.ContentProvider;
import android.content.UriMatcher; public class MyProvider extends ContentProvider {
MyHelper dbHelper;
private static final UriMatcher sMatcher;
static {
sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sMatcher.addURI(CountryCode.AUTHORITY, "item", CountryCode.ITEM);
sMatcher.addURI(CountryCode.AUTHORITY, "item/#", CountryCode.ITEM_ID);
}
}
这里UriMatcher类型的静态字段是用来匹配传入到ContentProvider中的Uri的类。其构造方法传入的匹配码是使用match()方法匹配根路径时返回的值,这个匹配码可以为一个大于零的数表示匹配根路径或传入-1,即常量UriMatcher.NO_MATCH表示不匹配根路径。addURI()方法是用来增加其他URI匹配路径的,第一个参数传入标识ContentProvider的AUTHORITY字符串。第二个参数传入需要匹配的路径,这里的#代表匹配任意数字,另外还可以用*来匹配任意文本。第三个参数必须传入一个大于零的匹配码,用于match()方法对相匹配的URI返回相对应的匹配码。
ContentProvider里针对数据的各种操作定义了6个抽象方法,下面是对各个方法的实现和讲解。
- @Override
- publicboolean onCreate() {
- dbHelper = new MyHelper(getContext(), CountryCode.DB_NAME, null,
- CountryCode.VERSION);
- returntrue;
- }
@Override
public boolean onCreate() {
dbHelper = new MyHelper(getContext(), CountryCode.DB_NAME, null,
CountryCode.VERSION);
return true;
}
每当ContentProvider启动时都会回调onCreate()方法。此方法主要进行一些ContentProvider初始化的工作,返回true表示初始化成功,返回false则初始化失败。在这个ContentProvider中,主要是构造了需要操作数据库的辅助类对象。
- @Override
- public String getType(Uri uri) {
- switch (sMatcher.match(uri)) {
- case CountryCode.ITEM:
- return CountryCode.CONTENT_TYPE;
- case CountryCode.ITEM_ID:
- return CountryCode.CONTENT_ITEM_TYPE;
- default:
- thrownew IllegalArgumentException("Unknown URI " + uri);
- }
- }
@Override
public String getType(Uri uri) {
switch (sMatcher.match(uri)) {
case CountryCode.ITEM:
return CountryCode.CONTENT_TYPE;
case CountryCode.ITEM_ID:
return CountryCode.CONTENT_ITEM_TYPE;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
}
getTyper()是用来返回数据的MIME类型的方法。使用sMatcher对URI进行匹配,并返回相应的MIME类型字符串,若无法匹配传入的URI,抛出IllegalArgumentException异常。
- @Override
- publicint delete(Uri uri, String where, String[] args) {
- SQLiteDatabase db = dbHelper.getWritableDatabase();
- int count;
- switch (sMatcher.match(uri)) {
- case CountryCode.ITEM:
- count = db.delete(CountryCode.TB_NAME, where, args);
- break;
- case CountryCode.ITEM_ID:
- String id = uri.getPathSegments().get(1);
- count = db.delete(CountryCode.TB_NAME,
- CountryCode.ID
- + "="
- + id
- + (!TextUtils.isEmpty(where) ? " AND (" + where
- + ')' : ""), args);
- break;
- default:
- thrownew IllegalArgumentException("Unknown URI " + uri);
- }
- getContext().getContentResolver().notifyChange(uri, null);
- return count;
- }
@Override
public int delete(Uri uri, String where, String[] args) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
int count;
switch (sMatcher.match(uri)) {
case CountryCode.ITEM:
count = db.delete(CountryCode.TB_NAME, where, args);
break;
case CountryCode.ITEM_ID:
String id = uri.getPathSegments().get(1);
count = db.delete(CountryCode.TB_NAME,
CountryCode.ID
+ "="
+ id
+ (!TextUtils.isEmpty(where) ? " AND (" + where
+ ')' : ""), args);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
- @Override
- publicint update(Uri uri, ContentValues values, String where, String[] args) {
- SQLiteDatabase db = dbHelper.getWritableDatabase();
- int count;
- switch (sMatcher.match(uri)) {
- case CountryCode.ITEM:
- count = db.update(CountryCode.TB_NAME, values, where, args);
- break;
- case CountryCode.ITEM_ID:
- String id = uri.getPathSegments().get(1);
- count = db.update(CountryCode.TB_NAME, values,
- CountryCode.ID
- + "="
- + id
- + (!TextUtils.isEmpty(where) ? " AND (" + where
- + ')' : ""), args);
- break;
- default:
- thrownew IllegalArgumentException("Unknown URI " + uri);
- }
- getContext().getContentResolver().notifyChange(uri, null);
- return count;
- }
@Override
public int update(Uri uri, ContentValues values, String where, String[] args) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
int count;
switch (sMatcher.match(uri)) {
case CountryCode.ITEM:
count = db.update(CountryCode.TB_NAME, values, where, args);
break;
case CountryCode.ITEM_ID:
String id = uri.getPathSegments().get(1);
count = db.update(CountryCode.TB_NAME, values,
CountryCode.ID
+ "="
+ id
+ (!TextUtils.isEmpty(where) ? " AND (" + where
+ ')' : ""), args);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
delete()和update()方法分别用于数据的删除和修改操作,返回的是所影响数据的数目。我们这里两种方法的实现比较相似。首先利用数据库辅助对象获取一个SQLiteDatabase对象。然后根据传入的Uri用sMatcher进行匹配,对单个数据或数据集进行删除或修改,以便于在调用SQLiteDatabase对象的删除或修改方法时where语句中使用不同的表达式。这里通过调用getContext()方法获得调用update()方法的Context对象,再利用这个Context对象来获取一个ContentResolver的对象。notifyChange()方法则用来通知注册在此URI上的观察者(observer)数据发生了改变。最后返回删除或修改数据的行数。
- @Override
- public Uri insert(Uri uri, ContentValues initialValues) {
- SQLiteDatabase db = dbHelper.getWritableDatabase();
- long rowId;
- if (sMatcher.match(uri) != CountryCode.ITEM) {
- thrownew IllegalArgumentException("Unknown URI " + uri);
- }
- rowId = db.insert(CountryCode.TB_NAME, CountryCode.ID, initialValues);
- if (rowId > 0) {
- Uri noteUri = ContentUris.withAppendedId(CountryCode.CONTENT_URI,
- rowId);
- getContext().getContentResolver().notifyChange(noteUri, null);
- return noteUri;
- }
- thrownew SQLException("Failed to insert row into " + uri);
- }
@Override
public Uri insert(Uri uri, ContentValues initialValues) {
SQLiteDatabase db = dbHelper.getWritableDatabase();
long rowId;
if (sMatcher.match(uri) != CountryCode.ITEM) {
throw new IllegalArgumentException("Unknown URI " + uri);
}
rowId = db.insert(CountryCode.TB_NAME, CountryCode.ID, initialValues);
if (rowId > 0) {
Uri noteUri = ContentUris.withAppendedId(CountryCode.CONTENT_URI,
rowId);
getContext().getContentResolver().notifyChange(noteUri, null);
return noteUri;
}
throw new SQLException("Failed to insert row into " + uri);
}
insert()方法用来插入数据,最后返回新插入数据的URI。在此方法的实现中,只接受数据集的URI,即指向表的URI。然后利用数据库辅助对象获得的SQLiteDatabase对象,调用insert()方法向指定表中插入数据。最后通知观察者数据发生变化,返回插入数据的URI。
- @Override
- public Cursor query(Uri uri, String[] projection, String selection,
- String[] args, String order) {
- SQLiteDatabase db = dbHelper.getReadableDatabase();
- Cursor c;
- switch (sMatcher.match(uri)) {
- case CountryCode.ITEM:
- c = db.query(CountryCode.TB_NAME, projection, selection, args,
- null, null, order);
- break;
- case CountryCode.ITEM_ID:
- String id = uri.getPathSegments().get(1);
- c = db.query(CountryCode.TB_NAME, projection, CountryCode.ID
- + "="
- + id
- + (!TextUtils.isEmpty(selection) ? " AND (" + selection
- + ')' : ""), args, null, null, order);
- break;
- default:
- thrownew IllegalArgumentException("Unknown URI " + uri);
- }
- c.setNotificationUri(getContext().getContentResolver(), uri);
- return c;
- }
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] args, String order) {
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor c;
switch (sMatcher.match(uri)) {
case CountryCode.ITEM:
c = db.query(CountryCode.TB_NAME, projection, selection, args,
null, null, order);
break;
case CountryCode.ITEM_ID:
String id = uri.getPathSegments().get(1);
c = db.query(CountryCode.TB_NAME, projection, CountryCode.ID
+ "="
+ id
+ (!TextUtils.isEmpty(selection) ? " AND (" + selection
+ ')' : ""), args, null, null, order);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
query()是对数据进行查询的方法,最终将查询的结果包装入一个Cursor对象并返回。其实现首先还是通过数据库辅助对象获取一个SQLiteDatabase对象,然后使用sMatcher对传入URI进行匹配,并分别对单数据和多数据的URI构造不同的where语句表达式并查询。setNotificationUri()方法是用来为Cursor对象注册一个观察数据变化的URI。
实现完这几个抽象方法后,一个完整的ContentProvider就被定义好了,剩下的就是在Android-Manifest.xml中对这个ContentProvider的声明了。在AndroidManifest.xml中添加如下声明代码。
<provider android:name="MyProvider"
android:authorities="com.studio.andriod.provider.countrycode"/>
其中android:name需要设置成刚才定义ContentProvider类的类名,android:authorities则指定了在content://样式的URI中标识这个ContentProvider的字符串。另外,可以设置android:readPermission和android:writePermission这两个属性, 来分别指定对这个ContentProvider中数据读和写操作的权限。也可以在onCreate()方法的实现中调用setRead-Permission()和setWritePermission()方法来动态指定权限。
为了让其他程序更加方便地使用我们自己定义的ContentProvider,一般会将要用到的静态数据导出成JAR归档文件。如本程序中将所有要用到的静态字段都放在了类CountryCode中。下面是将其打包成JAR文件的步骤。
(1) 在项目文件夹上或CountryCode.java文件上右键,选择Export..
(2) 在弹出的选择导出类型的对话框中,点击选择JAR file,然后点Next
(3) 在选择要导出的文件框中,只选择CountryCode.java。找到Browse...按钮指定导出路径(默认为workspace),点选Finish 完成导出CountryCode.jar
导出了JAR文件后,若需要在其他应用程序中使用,只需要为该项目添加外部的归档文件即可。在该项目文件夹上右键找到Build path→Add External Archive,然后选择要添加的JAR文件就可以在程序中使用import语句导入归档文件中的内容了。
ContentProvider是什么时候创建的,是谁创建的
访问某个应用程序共享的数据,是否需要启动这个应用程序?这个问题在 Android SDK中没有明确说明,但是从数据共享的角度出发,ContentProvider应该是Android在系统启动时就创建了,否则就谈不上数据共享了。 这就要求在AndroidManifest.XML中使用元素明确定义。
可能会有多个程序同时通过ContentResolver访问一个ContentProvider,会不会导致像数据库那样的“脏数据”?这个问题一方面需要数据库访问的同步,尤其是数据写入的同步,在AndroidManifest.XML中定义ContentProvider的时 候,需要考虑是元素multiprocess属性的值;另外一方面Android在ContentResolver中提供了notifyChange() 接口,在数据改变时会通知其他ContentObserver,这个地方应该使用了观察者模式,在ContentResolver中应该有一些类似 register,unregister的接口。
至此,已经对ContentProvider提供了比较全面的分析,至于如何创建ContentProvider,可创建一个属于你自己的 ContentProvider或者将你的数据添加到一个已经存在的ContentProvider中,当然前提是有相同数据类型并且有写入 Content provider的权限
ContentProvider 使用示例(转载)的更多相关文章
- Nginx 简单的负载均衡配置示例(转载)
原文地址:Nginx 简单的负载均衡配置示例(转载) 作者:水中游于 www.s135.com 和 blog.s135.com 域名均指向 Nginx 所在的服务器IP. 用户访问http://www ...
- HBase Java简单示例--转载
Hbase采用Java实现,原生客户端也是Java实现,其他语言需要通过thritf接口服务间接访问Hbase的数据. Hbase作为大数据存储数据库,其写能力非常强,加上Hbase本身就脱胎于Had ...
- Redis 缓存 + Spring 的集成示例(转载)
1. 依赖包安装 pom.xml 加入: <dependency> <groupId>org.springframework.data</groupId> < ...
- VC++使用服务做守护进程的示例(转载)
转载:http://blog.csdn.net/zdy0_2004/article/details/40461571 #define _WIN32_WINNT 0x502 #define _CRT_S ...
- C# 中[DllImport("user32.dll")]和extern用法和示例----转载
原文:https://blog.csdn.net/michellehsiao/article/details/7629746 extern 修饰符用于声明在外部实现的方法.extern ...
- [moka同学笔记]YII2中发送邮件示例(转载)
原文:http://yiilib.com/topic/675/Yii2%E4%B8%AD%E5%8F%91%E9%80%81%E9%82%AE%E4%BB%B6%E7%A4%BA%E4%BE%8B { ...
- 关于UIButton嵌入到UIView点击无反应问题的解决方法和delegate的简单用法示例(转载)
做项目封装UIView的时候碰到的问题,没想到有个哥们儿还写成博客,特此收藏! 问题是这样的,几个界面用到同一个自定义返回按钮,于是就想着把这个按钮单独封装起来,添加一个UIView类,在里面自定义U ...
- C++调Python示例(转载)
C++调Python,代码粘贴如下: #include <iostream> #include <Python.h> using namespace std; void Hel ...
- MVC5 + EF6 简单示例(转载)
原文地址:http://www.cnblogs.com/panchunting/p/creating-an-entity-framework-data-model-for-an-asp-net-mvc ...
随机推荐
- js取配置文件内容
使用 jQuery.i18n.properties 实现 Web 前端的国际化 http://www.ibm.com/developerworks/cn/web/1305_hezj_jqueryi18 ...
- (基础篇)PHP字符串函数
1查找字符位置函数: strpos($str,search,[int]):查找search在$str中的第一次位置从int开始: stripos($str,search,[int]):函数返回字符 ...
- 十五个最常用Linux命令行 - imsoft.cnblogs
众多Linux管理员在使用Linux的时候会经常使用到很多Linux命令行,其中有绝大部分不是经常使用到的.在本文中主要为大家总结了经常使用的十五个最常用Linux命令行,希望对刚刚接触Linux命令 ...
- 2015GitWebRTC编译实录8
2015.07.20 common_video 编译通过,其对libyuv有引用[1309/1600 ] CXX obj /webrtc/common_video/libyuv/common_vide ...
- hdu 1548 (dijkstra解法)(一次AC就是爽)
恭喜福州大学杨楠获得[BestCoder Round #4]冠军(iPad Mini一部) <BestCoder用户手册>下载 A strange lift Time Limit: 200 ...
- Android拍照保存图片内存大小
图片拍摄的大小会随着硬件而变化,比如,像素高的相机拍出来的图片要比像素低的图片内存要大. 如此一来,针对机型可能调用camera app保存照片的时候,图片大小会不一样. 为了缩小图片大小,我们需要把 ...
- Bootstrap部分---环境安装及一个可视化的布局;
一:环境安装*****顺序不可变***** <head> 如果需要可以设定,移动设备优先 <meta name="viewport" content=" ...
- leetcode 105 Construct Binary Tree from Preorder and Inorder Traversal ----- java
Given preorder and inorder traversal of a tree, construct the binary tree. Note:You may assume that ...
- Python实现ORM
ORM即把数据库中的一个数据表给映射到代码里的一个类上,表的字段对应着类的属性.将增删改查等基本操作封装为类对应的方法,从而写出更干净和更富有层次性的代码. 以查询数据为例,原始的写法要Python代 ...
- Open vSwitch
https://github.com/openvswitch/ovs/blob/master/INSTALL.RHEL.md