一、Content Provider数据共享
第一步,
ContentProvider 在android中的作用是对外共享数据, 也就是说你可以通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider对你应用中的数据 进行添删改查。关于数据共享,以前我们学习过文件操作模式,知道通过指定文件的操作模式为Context.MODE_WORLD_READABLE或 Context.MODE_WORLD_WRITEABLE同样也可以对外共享数据。那么,这里为何要使用ContentProvider对外共享数据 呢?是这样的,如果采用文件操作模式对外共享数据,数据的访问方式会因数据存储的方式而不同,导致数据的访问方式无法统一,如:采用xml文件对外共享数 据,需要进行xml解析才能读取数据;采用sharedpreferences共享数据,需要使用sharedpreferences API读取数据。
使用ContentProvider对外共享数据的好处是统一了数据的访问方式。
使用Content Provider的第一步,需要继承Content Provider,并重写其中的方法。
第二步,
需要在AndroidMainfest中进行配置,为了让其他应用程序找到Content Provider。我们需要给Content Provider配置一个唯一的标识,即authorities属性,它好比是一个网站,authorities就是它的域名。
android:authorities="com.ljq.providers.personprovider"/>
二、URI解释
其中,scheme已经被Android所规定,只能为content://。主机名(authority):是我们将要使用或者的Content Provider,外部应用如果要使用它,则它是唯一的标识。路径(Path):是我们将要操作的数据。比如:
操作person表中id为10的数据:person/10操作person表中id为10的name字段:person/10/name操作person表中所有的数据:person
我们也可以操作不为数据库的数据,例如,想要操作xml里面person节点下的name节点:person/name
注意:要将字符串转化为uri类型,需要使用到URI.parse()方法,即
Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person")
三、UriMatcher 类使用介绍
前面我们已经介绍到,Uri是我们要操作的数据。所以,我们要解析Uri数据。因此,android为我们提供了2类解析Uri的类。UriMatcher 和 ContentUris
UriMather用于匹配Uri,具体使用如下:第一步,将要需要使用的Uri路径全部匹配上去,
//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码UriMathcer mather = new UrlMathcer(UriMathcer.NO_MATCH);
//如果match()方法匹配content://com.ljq.provider.personprovider/person路径,返回匹配码为1matcher.addURI("com.ljq.provider.personprovider", "person", 1);//添加需要匹配的uri,如果匹配则返回匹配码
// 如果match()方法匹配content://com.ljq.provider.personprovider/person/201路径,返回匹配码为2
matcher.addURI("com.ljq.provider.personprovider", "person/#", 2);//因为#是通配符,所以,不管是ID为几,它都表示为匹配
使用方法:
switch(matcher.match(uri)){ case 1:{ break; } case 2:{ break; } }
注册完成后,就可以使用mather.match(uri)方法对输入的Uri数据进行匹配,如果匹配,则返回匹配码。匹配码是调用match.addUri()方法进行传入的第3个参数。
四、ContentUris使用
ContentUris用于操作Uri后面的ID部分,它有2个比较使用的方法:
withAppendedId(uri,id):给uri地址上面加上IDUri uri = Uri.parse("content://com.wangpei.provider.personprovider/person"); Uri resultUri = ContentUris.withAppendedId(uri,10);
生成的uri为:content://com.wangpei.provider.personprovider/person/10
parseId(uri):用于从uri中获取Id部分Uri uri = Uri.parse("content://com.wangpei.provider.personprovider/person/10"); long id = ContentUris.parseId(uri);//结果为10
id的值为10
五、使用Content Provider共享数据
Content Provier主要的方法有:
该方法是在Content Provider创建后就会被调用。android开机后,只有应用程序访问Content Provider里面的数据时,才会被创建。public boolean onCreate()
该方法是供外部程序往Content Provider里面插入新的数据。public Uri insert(Uri uri, ContentValues values)
该方法是供外部程序在Content Provider里面删除符合条件的数据。public int delete(Uri uri, String selection, String[] selectionArgs)
该方法是供外部程序更新Content Provide里面的符合条件的数据。public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
该方法是供外部程序获得Content Provider里面符合条件的数据。public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
该方法用于返回当前Uri所代表的数据的MIME类型,有以下2中情况:public String getType(Uri uri)
1.如果操作的数据类型属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头,例如:要得到数据为person的所有记录Uri:content://com.wangpei.provider.persionprovider/person,那么返回的MIME类型字符串为:“vnd.android.cursor.dir/person”
2.如果操作的书库类型属于非集合类型,那么MIME类型字符串应该以vnd.android.cursor.item/开头,例如:要得到的数据为person中id为10的记录Uri:content://com.wangpei.provider.personprovider/person/10,把么返回的MIME类型字符串为:“vnd.android.cursor.item/person”
六、使用ContentResolver操作Content Provider里面的数据
当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver类来完成,获取ContentResolver对象,可以使用Activity提供的getContentResolver()方法。
ContentResolver类提供了和ContentProvider类相同的四个方法:
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
public Uri insert(Uri uri,ContentValues values);
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs);
public int delete(Uri uri, String selection, String[] selectionArgs)
这些方法的第一个参数为uri,它表示对什么数据进行操作。下面我们会举一些例子:
ContentResolver resolver = getContentResolver(); Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person"); //添加一条记录 ContentValues values = new ContentValues(); values.put("name", "linjiqin"); values.put("age", 25); resolver.insert(uri, values); //获取person表中所有记录 Cursor cursor = resolver.query(uri, null, null, null, "personid desc"); while(cursor.moveToNext()){ Log.i("ContentTest", "personid="+ 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);
七、监听Content Provider中数据的变化
如果Content Provider的访问者需要知道Content Provider中数据发生变化,可以在ContentProvider发生数据变化时调用:getContentResolver。notifyChange(uri,null);//通知注册在此Uri上的访问者
例子:
public class PersonContentProvider extends ContentProvider { public Uri insert(Uri uri, ContentValues values) { db.insert("person", "personid", values); getContext().getContentResolver().notifyChange(uri, null);//数据发生变化,进行通知 } }
如果Content Provider的访问者需要得到数据变化的通知,必须使用ContentObserver进行监听,当监听到数据发生变化时,则系统会调用ContentObserver的onChange()方法:
getContentResolver().registerContentObserver(Uri.parse("content://com.ljq.providers.personprovider/person"), true, new PersonObserver(new Handler())); public class PersonObserver extends ContentObserver{ public PersonObserver(Handler handler) { super(handler); } public void onChange(boolean selfChange) { //此处可以进行相应的业务处理 } }