传送门 ☞ Android兵器谱 ☞ 转载请注明 ☞ http://blog.csdn.net/leverage_1229

一、共享数据

ContentProvider在Android中的作用是对外共享数据,也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider对你应用中的数据进行添删改查。关于数据共享,我们学知道通过指定文件的操作模式为Context.MODE_WORLD_READABLE或Context.MODE_WORLD_WRITEABLE同样也可以对外共享数据。那么,为何还要使用ContentProvider对外共享数据呢?如果采用文件操作模式对外共享数据,数据的访问方式会因数据存储的方式而不同,导致数据的访问方式无法统一。如果采用xml文件对外共享数据,需要进行xml解析才能读取数据;如果采用sharedpreferences共享数据,需要使用sharedpreferences API读取数据。使用ContentProvider对外共享数据的好处是统一了数据的访问方式。

通过ContentProvider对外共享数据,技术要点如下:

1.继承ContentProvider并重写下列方法

public class UserContentProvider extends ContentProvider{public boolean onCreate()public Uri insert(Uri uri, ContentValues values)public int delete(Uri uri, String selection, String[] selectionArgs)public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)public String getType(Uri uri)
}

2.在AndroidManifest.xml使用<provider>标签对该ContentProvider进行注册。为了让其他应用能够找到该ContentProvider,ContentProvider采用了authorities(主机名/域名)对它进行唯一标识,如果把ContentProvider看作是一个站点,那么authorities就是它的域名。

<manifest><application android:icon="@drawable/icon" android:label="@string/app_name"><provider android:name=".UserContentProvider" android:authorities="cn.lynn.providers.userprovider"/></application>
</manifest>

二、Uri类

Uri代表了待操作的数据,主要包含了两部分信息:需要操作的ContentProvider和对ContentProvider中的数据进行操作,一个Uri由以下几部分组成:

ContentProvider的scheme由Android所指定,scheme:content://
主机名(或叫Authority)唯一标识该ContentProvider,外部调用者根据这个标识来找到它。
路径(path)标识要操作的数据,路径的构建应根据业务而定,如下:
操作user表中id为10的记录:/user/10
操作user表中id为10的记录的name字段:user/10/name
操作user表中的所有记录:/user
操作xxx表中的记录:/xxx
当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,操作xml文件中user节点下的name节点:/user/name
如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,Uri uri = Uri.parse("content://cn.lynn.providers.userprovider/user")

三、UriMatcher类的使用

因为Uri代表了待操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher和ContentUris 。掌握它们的使用,会便于我们的开发工作。
        UriMatcher类用于匹配Uri,用法如下:

// 常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
UriMatcher  sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// 如果match()方法匹配content://cn.lynn.providers.userprovider/user路径,返回匹配码为1
sMatcher.addURI("cn.lynn.providers.userprovider", "user", 1); // 添加需要匹配uri,如果匹配就会返回匹配码
// 如果match()方法匹配content://cn.lynn.providers.userprovider/user/16路径,返回匹配码为2
sMatcher.addURI("cn.lynn.providers.userprovider", "user/#", 2);// #号为通配符
switch (sMatcher.match(Uri.parse("content://cn.lynn.providers.userprovider/user/10"))) { case 1:break;case 2:break;default:break;
}

注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假设匹配content://cn.lynn.providers.userprovider/user路径,返回的匹配码为1。

四、ContentUris类的使用

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

1.withAppendedId(uri, id):为路径加上ID部分

Uri uri = Uri.parse("content://cn.lynn.providers.userprovider/user")
Uri resultUri = ContentUris.withAppendedId(uri, 11);
//生成后的Uri为:content://cn.lynn.providers.userprovider/user/11

2.parseId(uri):从路径中获取ID部分

Uri uri = Uri.parse("content://cn.lynn.providers.userprovider/user/11")
long userId = ContentUris.parseId(uri);//获取的结果为:11

五、使用ContentProvider共享数据
1.ContentProvider类主要方法:
public boolean onCreate():该方法在ContentProvider创建后就会被调用,Android开机后,ContentProvider在其它应用第一次访问它时才会被创建。
public Uri insert(Uri uri, ContentValues values):该方法用于供外部应用往ContentProvider添加数据。
public int delete(Uri uri, String selection, String[] selectionArgs):该方法用于供外部应用从ContentProvider删除数据。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):该方法用于供外部应用更新ContentProvider中的数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):该方法用于供外部应用从ContentProvider中获取数据。
public String getType(Uri uri):该方法用于返回当前Url所代表数据的MIME类型。
2.如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头:
要得到所有user记录的Uri为content://cn.lynn.providers.userprovider/user,那么返回的MIME类型字符串应该为:"vnd.android.cursor.dir/user"。
3.如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头:
要得到id为11的user记录,Uri为content://cn.lynn.providers.userprovider/user/11,那么返回的MIME类型字符串为:"vnd.android.cursor.item/user"。
六、使用ContentResolver操作ContentProvider中数据

当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。 ContentResolver 类提供了与ContentProvider类相同签名的四个方法:

public Uri insert(Uri uri, ContentValues values):该方法用于往ContentProvider添加数据。
public int delete(Uri uri, String selection, String[] selectionArgs):该方法用于从ContentProvider删除数据。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):该方法用于更新ContentProvider中的数据。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):该方法用于从ContentProvider中获取数据。
        这些方法的第一个参数为Uri,代表要操作的ContentProvider和对其中的什么数据进行操作,
如果待操作的数据为:Uri.parse("content://cn.lynn.providers.userprovider/user/11"),那么将会对主机名为cn.lynn.providers.userprovider的ContentProvider进行操作,操作的数据为user表中id为11的记录。

ContentResolver resolver =  getContentResolver();
Uri uri = Uri.parse("content://cn.lynn.providers.userprovider/user");
//添加一条记录
ContentValues values = new ContentValues();
values.put("name", "lynn");
values.put("age", 25);
resolver.insert(uri, values);
//获取user表中所有记录
Cursor cursor = resolver.query(uri, null, null, null, "userid desc");
while(cursor.moveToNext()){Log.i("Test", "userid = " + cursor.getInt(0)+ ", name = " + cursor.getString(1));
}
//把id为1的记录的name字段值更改新为zhangsan
ContentValues updateValues = new ContentValues();
updateValues.put("name", "zhangsan");
Uri updateIdUri = ContentUris.withAppendedId(uri, 2);
resolver.update(updateIdUri, updateValues, null, null);
//删除id为2的记录
Uri deleteIdUri = ContentUris.withAppendedId(uri, 2);
resolver.delete(deleteIdUri, null, null);

七、监听ContentProvider中数据的变化

如果ContentProvider的访问者需要知道ContentProvider中的数据发生变化,可以在ContentProvider发生数据变化时调用getContentResolver().notifyChange(uri, null)来通知注册在此URI上的访问者。

public class UserContentProvider extends ContentProvider {public Uri insert(Uri uri, ContentValues values) {db.insert("user", "userid", values);getContext().getContentResolver().notifyChange(uri, null);}
}

如果ContentProvider的访问者需要得到数据变化通知,必须使用ContentObserver对数据(数据采用uri描述)进行监听,当监听到数据变化通知时,系统就会调用ContentObserver的onChange()方法。

getContentResolver().registerContentObserver(Uri.parse("content://cn.lynn.providers.userprovider/user"),true, new UserObserver(new Handler()));
public class UserObserver extends ContentObserver{public PersonObserver(Handler handler) {super(handler);}public void onChange(boolean selfChange) {// 可在此处进行相应的业务处理}
}

八、示例

1.AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="cn.lynn.contentprovider" android:versionCode="1"android:versionName="1.0"><application android:icon="@drawable/icon"android:label="@string/app_name"><uses-library android:name="android.test.runner" /><activity android:name=".ContentProviderMainActivity"android:label="@string/app_name"><intent-filter><action android:name="android.intent.action.MAIN" /><categoryandroid:name="android.intent.category.LAUNCHER" /></intent-filter></activity><provider android:name="cn.lynn.providers.UersonContentProvider" android:authorities="cn.lynn.providers.userprovider" /></application><uses-sdk android:minSdkVersion="8" /><instrumentationandroid:name="android.test.InstrumentationTestRunner"android:targetPackage="cn.lynn.contentprovider" android:label="Tests for My App" />
</manifest>

2.UserContentProvider.java

package com.lynn.contentprovider;import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.text.TextUtils;/*** 内容提供者:统一数据访问方式,方便外部调用* @author lynnli1229*/
public class UserContentProvider extends ContentProvider {// 数据集的MIME类型字符串则应该以vnd.android.cursor.dir/开头public static final String USERS_TYPE = "vnd.android.cursor.dir/user";// 单一数据的MIME类型字符串应该以vnd.android.cursor.item/开头public static final String USERS_ITEM_TYPE = "vnd.android.cursor.item/user";public static final String AUTHORITY = "cn.lynn.providers.userprovider";// 主机名/* 自定义匹配码 */public static final int USERS = 1;/* 自定义匹配码 */public static final int USER = 2;public static final Uri USERS_URI = Uri.parse("content://" + AUTHORITY + "/user");private DBOpenHelper dbOpenHelper;// UriMatcher类用来匹配Uri,使用match()方法匹配路径时返回匹配码private static final UriMatcher uriMatcher;static {// 常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);// 如果match()方法匹配content://cn.lynn.providers.userprovider/user路径,返回匹配码为USERSuriMatcher.addURI(AUTHORITY, "user", USERS);// 如果match()方法匹配content://cn.lynn.providers.userprovider/user/16路径,返回匹配码为USERuriMatcher.addURI(AUTHORITY, "user/#", USER);}@Overridepublic boolean onCreate() {dbOpenHelper = new DBOpenHelper(this.getContext());return true;}@Overridepublic Uri insert(Uri uri, ContentValues values){SQLiteDatabase db = dbOpenHelper.getWritableDatabase();long id = 0;switch (uriMatcher.match(uri)) {case PERSONS:id = db.insert("user", "name", values);// 返回的是记录的行号,主键为int,实际上就是主键值return ContentUris.withAppendedId(uri, id);case PERSON:id = db.insert("user", "name", values);String path = uri.toString();return Uri.parse(path.substring(0, path.lastIndexOf("/"))+id); // 替换掉iddefault:throw new IllegalArgumentException("Unknown URI " + uri);}}@Overridepublic int delete(Uri uri, String selection, String[] selectionArgs) {SQLiteDatabase db = dbOpenHelper.getWritableDatabase();int count = 0;switch (uriMatcher.match(uri)) {case USERS:count = db.delete("user", selection, selectionArgs);break;case USER:// 下面的方法用于从URI中解析出id,对路径content://cn.lynn.providers.userprovider/user/11进行解析,返回值为11long userId = ContentUris.parseId(uri);String where = "id=" + userId; // 删除指定id的记录where += !TextUtils.isEmpty(selection) ? " and (" + selection + ")" : ""; // 附加其它条件count = db.delete("user", where, selectionArgs);break;default:throw new IllegalArgumentException("Unknown URI " + uri);}db.close();return count;}@Overridepublic int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) {SQLiteDatabase db = dbOpenHelper.getWritableDatabase();int count = 0;switch (uriMatcher.match(uri)) {case USERS:count = db.update("user", values, selection, selectionArgs);break;case USER:long userId = ContentUris.parseId(uri);String where = "id=" + userId; // 获取指定id的记录where += !TextUtils.isEmpty(selection) ? " and (" + selection + ")" : "";count = db.update("user", values, where, selectionArgs);break;default:throw new IllegalArgumentException("Unknown URI " + uri);}db.close();return count;}@Overridepublic String getType(Uri uri) {switch (uriMatcher.match(uri)) {case USERS:return USERS_TYPE;case USER:return USERS_ITEM_TYPE;default:throw new IllegalArgumentException("Unknown URI " + uri);}}@Overridepublic Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {SQLiteDatabase db = dbOpenHelper.getReadableDatabase();switch (uriMatcher.match(uri)) {case USERS:return db.query("person", projection, selection, selectionArgs, null, null, sortOrder);case USER:long userId = ContentUris.parseId(uri);String where = "id=" + userId;// 获取指定id的记录where += !TextUtils.isEmpty(selection) ? " and (" + selection + ")" : "";return db.query("user", projection, where, selectionArgs, null, null, sortOrder);default:throw new IllegalArgumentException("Unknown URI " + uri);}}}

3.UserContentProviderTest.java

package cn.lynn.contentprovider;import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.test.AndroidTestCase;
import android.util.Log;/*** 测试类:外部访问内容提供者* @author lynnli1229*/
public class PersonContentProviderTest extends AndroidTestCase{private static final String TAG = "UserContentProviderTest";public void testSave() throws Throwable{ContentResolver contentResolver = this.getContext().getContentResolver();Uri insertUri = Uri.parse("content://cn.lynn.providers.userprovider/user");ContentValues values = new ContentValues();values.put("name", "lynn");values.put("phone", "18700888777");Uri uri = contentResolver.insert(insertUri, values);Log.i(TAG, uri.toString());}public void testUpdate() throws Throwable{ContentResolver contentResolver = this.getContext().getContentResolver();Uri updateUri = Uri.parse("content://cn.lynn.providers.userprovider/user/1");ContentValues values = new ContentValues();values.put("name", "zhangsan");contentResolver.update(updateUri, values, null, null);}public void testFind() throws Throwable{ContentResolver contentResolver = this.getContext().getContentResolver();Uri uri = Uri.parse("content://cn.lynn.providers.userprovider/user");Cursor cursor = contentResolver.query(uri, null, null, null, "id asc");while(cursor.moveToNext()){int userId = cursor.getInt(cursor.getColumnIndex("id"));String name = cursor.getString(cursor.getColumnIndex("name"));String phone = cursor.getString(cursor.getColumnIndex("phone"));Log.i(TAG, "userId = " + userId + ", name = " + name + ", phone = " + phone);}cursor.close();}public void testDelete() throws Throwable{ContentResolver contentResolver = this.getContext().getContentResolver();Uri uri = Uri.parse("content://cn.lynn.providers.userprovider/user/1");contentResolver.delete(uri, null, null);}
}

Android青翼蝠王之ContentProvider相关推荐

  1. 有一个数列:白眉鹰王、金毛狮王、紫衫龙王、青翼蝠王 猜数游戏:从键盘中任意输入一个名称,判断数列中是否包含此名称【顺序查找】 要求: 如果找到了,就提示找到,并给出下标值

    有一个数列:白眉鹰王.金毛狮王.紫衫龙王.青翼蝠王 猜数游戏:从键盘中任意输入一个名称,判断数列中是否包含此名称[顺序查找] 要求: 如果找到了,就提示找到,并给出下标值 如果有多个查找结果,都找出来 ...

  2. flickr app android,Flickr latest Android app(Version: 2.1.5) ContentProvider security issue

    8种机械键盘轴体对比 本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选? 摘要:Flickr latest Android app(Version: 2.1.5) ContentProvider ...

  3. 高速数据采集专家--青翼8通道125MSPS 16位AD采集FMC子卡

    青翼自研FMC129是一款8通道125MHz采样率16位AD采集FMC子卡,符合VITA57.1规范,可以作为一个理想的IO模块耦合至FPGA前端,8通道AD通过高带宽的FMC连接器(HPC)连接至F ...

  4. 类查找android中跨项目的数据库操作ContentProvider的使用

    上班之余抽点时间出来写写博文,希望对新接触的朋友有帮助.今天在这里和大家一起学习一下类查找 RuiXin.java类 package com.gtl.data.two;import android.n ...

  5. android uri转file_Android世界:ContentProvider使用

    继上文输出之后,偶逢流感,又遇节日.停电.现在继续未完成的内容. 一.Provider的使用概述 本文暂且介绍FileProvider:至于后续遇到安卓新版本适配的其他Provider,到时再进行补充 ...

  6. Android Content Provider详解-实现ContentProvider MIME 类型

    转载至:http://www.2cto.com/kf/201212/179560.html 实现ContentProvider MIME 类型   ContentProvider 有两个方法返回MIM ...

  7. android开发笔记(五)ContentProvider

    1 ContentProvider简介 1.1 为什么要有ContentProvider? 功能需求: 一个应用需要访问另一个应用的数据库表数据 实际情况: 一个应用的数据库文件是应用私有的, 其它应 ...

  8. [Android Pro] 判断Uri对应的ContentProvider所操作的数据库u存在,及DownloadManager的暂停,继续...

    reference to : http://blog.csdn.net/u012858313/article/details/38821857 项目中遇到一个问题,就是用到DownloadManage ...

  9. Android白眉鹰王之BroadcastReceiver

    传送门 ☞ Android兵器谱 ☞ 转载请注明 ☞ http://blog.csdn.net/leverage_1229 BroadcastReceiver作为Android四大组件之一,不像Act ...

  10. 青翼科技自研模块化互联产品 • 模拟采集FMC子卡【产品资料】

    FMC122是一款基于FMC标准规范,实现2路16-bit.1GSPS ADC同步采集,2路16-bit 2.5GSPS DAC同步回放功能子卡模块.该模块遵循VITA57.1标准,可直接与FPGA载 ...

最新文章

  1. 合肥师范学院计算机毕设选老师,计算机毕设被导师要求反复修改?
  2. python 安装easy_install和pip
  3. BZOJ 1920 Luogu P4217 [CTSC2010]产品销售 (模拟费用流、线段树)
  4. JAVA复习(date)
  5. Linux 字符设备驱动开发基础(五)—— ioremap() 函数解析
  6. jquery-1.10.2.min.map是什么,怎么用?
  7. MySQL笔记-删除session,删除阻塞任务
  8. java biginteger log_java – BigInteger:计算可伸缩方法中的小数位数
  9. [设计模式-行为型]状态模式(State)
  10. Mysql中Drop,Truncate,Delete的区别
  11. 按头安利 好看又实用的手绘图标素材看这里
  12. KK模组与普通丝杠模组的区别
  13. Linux ftp服务器虚拟用户的建立
  14. 师徒结对活动记录表计算机,师徒结对活动记录表一.doc
  15. Windows Mobile 开发常见问题集(转自zsu_darkwind的专栏)
  16. 信奥中的数学:集合与子集
  17. crh寄存器_寄存器-相关博客帖子 - 电子工程世界-论坛
  18. 关于UITableView的Cell复用谈谈我的一些心得滴水穿石
  19. 2017年8月23日 星期三 --出埃及记 Exodus 29:2
  20. 颜色外观模型:人眼视觉理论基础

热门文章

  1. 现代天线设计——学习笔记(一)
  2. 小程序根据国外经纬度显示地图
  3. 分布式文件系统(Distributed File System,DFS)
  4. 王者荣耀: 史上最长对局, 无法打破的神话英雄, 10小时4千人头
  5. cpu亲和力总结taskset和setcpu及其他相关
  6. java set方法无法使用_Java setBounds无法与JPanel一起使用
  7. python 学习笔记之手把手讲解如何使用原生的 urllib 发送网络请求
  8. 用C语言解一元二次方程
  9. 浙江工商大学计算机研究生院,浙江工商大学研究生院
  10. maya2018模型传递点序