一、相关ContentProvider概念解析:
1、ContentProvider简介
在Android官方指出的Android的数据存储方式总共有五种,分别是:Shared Preferences、网络存储、文件存储、外储存储、SQLite。但是我们知道一般这些存储都只是在单独的一个应用程序之中达到一个数据的共享,有时候我们需要操作其他应用程序的一些数据,例如我们需要操作系统里的媒体库、通讯录等,这时我们就可能通过ContentProvider来满足我们的需求了。
2、为什么要选择ContentProvider?
ContentProvider向我们提供了我们在应用程序之前共享数据的一种机制,而我们知道每一个应用程序都是运行在不同的应用程序的,数据和文件在不同应用程序之间达到数据的共享不是没有可能,而是显得比较复杂,而正好Android中的ContentProvider则达到了这一需求,比如有时候我们需要操作手机里的联系人,手机里的多媒体等一些信息,我们都可以用到这个ContentProvider来达到我们所需。
1)、ContentProvider为存储和获取数据提供了统一的接口。ContentProvide对数据进行封装,不用关心数据存储的细节。使用表的形式来组织数据。
2)、使用ContentProvider可以在不同的应用程序之间共享数据。
3)、Android为常见的一些数据提供了默认的ContentProvider(包括音频、视频、图片和通讯录等)。
总的来说使用ContentProvider对外共享数据的好处是统一了数据的访问方式。
3、Uri介绍
为系统的每一个资源给其一个名字,比方说通话记录。
1)、每一个ContentProvider都拥有一个公共的URI,这个URI用于表示这个ContentProvider所提供的数据。
2)、Android所提供的ContentProvider都存放在android.provider包中。 将其分为A,B,C,D 4个部分:
A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;"content://"
B:URI 的标识,用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的类名。这个标识在 元素的 authorities属性中说明:一般是定义该ContentProvider的包.类的名称
C:路径(path),通俗的讲就是你要操作的数据库中表的名字,或者你也可以自己定义,记得在使用的时候保持一致就可以了;"content://com.bing.provider.myprovider/tablename"
D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部; "content://com.bing.provider.myprovider/tablename/#" #表示数据id。
PS:
路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
1、要操作person表中id为10的记录,可以构建这样的路径:/person/10
2、要操作person表中id为10的记录的name字段, person/10/name
3、要操作person表中的所有记录,可以构建这样的路径:/person
4、要操作xxx表中的记录,可以构建这样的路径:/xxx
5、当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:
要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name
6、如果要把一个字符串转换成Uri,可以使用Uri类中的parse()方法,如下:Uri uri = Uri.parse("content://com.bing.provider.personprovider/person")
4、UriMatcher类使用介绍
因为Uri代表了要操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher和ContentUris 。掌握它们的使用,会便于我们的开发工作。
5。 ContentProvider:为存储和获取数据提供统一的接口。可以在不同的应用程序之间共享数据。Android已经为常见的一些数据提供了默认的ContentProvider
1、ContentProvider使用表的形式来组织数据
无论数据的来源是什么,ContentProvider都会认为是一种表,然后把数据组织成表格
2、ContentProvider提供的方法
query:查询
insert:插入
update:更新
delete:删除
getType:得到数据类型
onCreate:创建数据时调用的回调函数
3、每个ContentProvider都有一个公共的URI,这个URI用于表示这个ContentProvider所提供的数据。Android所提供的ContentProvider都存放在android.provider包当中
6、ContentProvider的内部原理
自定义一个ContentProvider,来实现内部原理
步骤:
1、定义一个CONTENT_URI常量(里面的字符串必须是唯一)
Public static final Uri CONTENT_URI = Uri.parse("content://com.WangWeiDa.MyContentprovider");
如果有子表,URI为:
Public static final Uri CONTENT_URI = Uri.parse("content://com.WangWeiDa.MyContentProvider/users");
2、定义一个类,继承ContentProvider
Public class MyContentProvider extends ContentProvider
3、实现ContentProvider的所有方法(query、insert、update、delete、getType、onCreate)
这里上传自己写的contentProvider类
数据源Bean
package com.leige.stu.domain;
public class Student {
private int id;
private String name;
private String sex;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(int id, String name, String sex, int age) {
super();
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", sex=" + sex
+ ", age=" + age + "]";
}
public Student() {
super();
}
}
ContentProvider类,详细解释都在类的注解中
欢迎大家纠错
package com.leige.stu.mycontentprovider;
import com.leige.stu.mysqllite.StudentSqlHelper;
import com.leige.stu.mysqllite.Studentdao;
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;
public class MyProvider extends ContentProvider {
private StudentSqlHelper helper;
private static final UriMatcher uriMatcher;
//定义authority
private static final String authority="com.leige.stu.mycontentprovider.MyProvider";
//定义匹配操作码
private static final int STUDENT_INSERT_CODE = 0;
private static final int STUDENT_UPDATE_CODE = 1;
private static final int STUDENT_FINDBYID_CODE = 2;
private static final int STUDENT_DELETE_CODE = 3;
private static final int STUDENT_FINDALL_CODE = 4;
static{
//实例化UriMatcher
uriMatcher=new UriMatcher(UriMatcher.NO_MATCH);
//匹配路径content://com.leige.stu.mycontentprovider.MyProvider/student/insert
uriMatcher.addURI(authority, "student/insert", STUDENT_INSERT_CODE);
//匹配路径content://com.leige.stu.mycontentprovider.MyProvider/student/delete
uriMatcher.addURI(authority, "student/delete", STUDENT_DELETE_CODE);
//匹配路径content://com.leige.stu.mycontentprovider.MyProvider/student/update
uriMatcher.addURI(authority, "student/update", STUDENT_UPDATE_CODE);
//匹配路径content://com.leige.stu.mycontentprovider.MyProvider/student/findById/#
uriMatcher.addURI(authority, "student/findById/#", STUDENT_FINDBYID_CODE);
//匹配路径content://com.leige.stu.mycontentprovider.MyProvider/student/findAll
uriMatcher.addURI(authority, "student/findAll", STUDENT_FINDALL_CODE);
}
@Override
public boolean onCreate() {
// TODO Auto-generated method stub
//创建数据库
helper=new StudentSqlHelper(getContext(), "stu.db",null , 1);
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO Auto-generated method stub
//得到数据库
SQLiteDatabase db=helper.getReadableDatabase();
switch (uriMatcher.match(uri)) {
case STUDENT_FINDALL_CODE:
{
if(db.isOpen()){
//查询得到游标对象,返回,查询所有
Cursor cursor=db.query( "student", projection, selection,
selectionArgs, null, null,sortOrder);
return cursor;
}
}
break;
case STUDENT_FINDBYID_CODE:
{
if(db.isOpen()){//查询单个,
int id=(int) ContentUris.parseId(uri);
Cursor cursor=db.query("student",projection ,"_id=",
new String[]{1+""}, null, null, sortOrder);
return cursor;
}
}
break;
default:
break;
}
//返回游标,不能关闭db,切记
//db.close();
return null;
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
switch (uriMatcher.match(uri)) {
case STUDENT_FINDALL_CODE:
return "vnd.android.cursor.dir/student";
case STUDENT_FINDBYID_CODE:
return "vnd.android.cursor.item/student";
default:
break;
}
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
SQLiteDatabase db=helper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case STUDENT_INSERT_CODE:
{
if(db.isOpen()){
long id=db.insert("student",null, values);
db.close();
return ContentUris.withAppendedId(uri, id);
}
}
break;
default:
break;
}
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
SQLiteDatabase db=helper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case STUDENT_DELETE_CODE:
{
if(db.isOpen()){
int count=db.delete("student", selection, selectionArgs);
db.close();
return count;
}
}
break;
default:
break;
}
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
SQLiteDatabase db=helper.getWritableDatabase();
switch (uriMatcher.match(uri)) {
case STUDENT_UPDATE_CODE:
{
if(db.isOpen()){
int count=db.update("student", values, selection, selectionArgs);
db.close();
return count;
}
}
break;
default:
break;
}
return 0;
}
}
contentProvider类写完后,需要发布到机器上,提供统一的uri接口可以被外部程序所访问,另外contentProvider是android的四大组件之一,所以需要在androidMainfest.xml文件中注册
例如
<provider android:name=".mycontentprovider.MyProvider"
android:authorities="com.leige.stu.mycontentprovider.MyProvider"
android:readPermission="myprovider.read"
android:writePermission="myprovider.write"
>
<!--
自定义权限需要声明,才会被系统所认可,所以需要定义permission节点,声明自定义权限
android:readPermission="myprovider.read"
android:writePermission="myprovider.write" -->
</provider>
这里定义了对contentprovider的读写权限设置,如果在其他程序中访问contentprovider,需要申请权限
测试类代码
package comleige.testcontentprovider.test;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.test.AndroidTestCase;
import android.util.Log;
public class MyTest extends AndroidTestCase {
public void test(){
//得到内容提供者的访问对象
ContentResolver resolver = getContext().getContentResolver();
//设定uri
Uri uri=Uri.parse("content://com.leige.stu.mycontentprovider.MyProvider/student/insert");
ContentValues values=new ContentValues();
values.put("name", "磊哥2");
values.put("sex", "男");
values.put("age", 18);
resolver.insert(uri, values);
}
/* public void testFindById(){
ContentResolver resolver=getContext().getContentResolver();
Uri uri=Uri.parse
("content://com.leige.stu.mycontentprovider.MyProvider/student/findById/#");
uri=ContentUris.withAppendedId(uri,1);
Cursor cursor=resolver.query(uri,
new String[]{"_id","name","sex","age"}, null, null, null);
if(cursor!=null){
cursor.moveToFirst();
int id=cursor.getInt(0);
String name=cursor.getString(1);
String sex=cursor.getString(2);
int age=cursor.getInt(3);
Student s=new Student(id,name,sex,age);
System.out.println(s);
Log.i("err", s.toString());
Log.d("err", "leige");
}
}*/
}