欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android学习笔记之ContentProvider和Uri详解

程序员文章站 2024-03-02 15:55:46
本文介绍了自定义content provider的相关内容,完全解析内容提供者的用法。content provider,内容提供者,相信大家对这个组件的名字都不陌生,可能是...

本文介绍了自定义content provider的相关内容,完全解析内容提供者的用法。content provider,内容提供者,相信大家对这个组件的名字都不陌生,可能是自己平时做的都是一些简单的app,所以对于content provider的使用并不是很多,也不是特别熟悉。但是这里还是对content provider作个简单的总结,不是很深入,但是希望能给包括我在内的初学者一点帮助,看完这篇能对这个组件有个总体上的了解。

一、使用contentprovider(内容提供者)共享数据

contentprovider在android中的作用是对外共享数据,也就是说你可以通过contentprovider把应用中的数据共享给其他应用访问,其他应用可以通过contentprovider对你应用中的数据进行添删改查。关于数据共享,以前我们学习过文件操作模式,知道通过指定文件的操作模式为context.mode_world_readable或context.mode_world_writeable同样也可以对外共享数据。那么,这里为何要使用contentprovider对外共享数据呢?是这样的,如果采用文件操作模式对外共享数据,数据的访问方式会因数据存储的方式而不同,导致数据的访问方式无法统一,如:采用xml文件对外共享数据,需要进行xml解析才能读取数据;采用sharedpreferences共享数据,需要使用sharedpreferences api读取数据。使用contentprovider对外共享数据的好处是统一了数据的访问方式。当应用需要通过contentprovider对外共享数据时,第一步需要继承contentprovider并重写下面方法:   

public class personcontentprovider 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) 
} 

    第二步需要在androidmanifest.xml使用<provider>对该contentprovider进行配置,为了能让其他应用找到该contentprovider ,contentprovider采用了authorities(主机名/域名)对它进行唯一标识,你可以把contentprovider看作是一个网站(想想,网站也是提供数据者),authorities 就是他的域名:
 

  <manifest.... > 
 <application android:icon="@drawable/icon" android:label="@string/app_name"> 
   <provider android:name=".personcontentprovider"  
   android:authorities="com.ljq.providers.personprovider"/> 
 </application> 
</manifest> 

二、uri介绍
uri代表了要操作的数据,uri主要包含了两部分信息:1》需要操作的contentprovider ,2》对contentprovider中的什么数据进行操作,一个uri由以下几部分组成:

Android学习笔记之ContentProvider和Uri详解

contentprovider(内容提供者)的scheme已经由android所规定, scheme为:content://

主机名(或叫authority)用于唯一标识这个contentprovider,外部调用者可以根据这个标识来找到它。

路径(path)可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:

要操作person表中id为10的记录,可以构建这样的路径:/person/10

要操作person表中id为10的记录的name字段, person/10/name

要操作person表中的所有记录,可以构建这样的路径:/person

要操作xxx表中的记录,可以构建这样的路径:/xxx

当然要操作的数据不一定来自数据库,也可以是文件、xml或网络等其他存储方式,如下:

要操作xml文件中person节点下的name节点,可以构建这样的路径:/person/name

如果要把一个字符串转换成uri,可以使用uri类中的parse()方法,如下:

uri uri = uri.parse("content://com.ljq.provider.personprovider/person") 

三、urimatcher类使用介绍

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

首先第一步把你需要匹配uri路径全部给注册上,如下:

//常量urimatcher.no_match表示不匹配任何路径的返回码 
urimatcher smatcher = new urimatcher(urimatcher.no_match); 
//如果match()方法匹配content://com.ljq.provider.personprovider/person路径,返回匹配码为1 
smatcher.adduri("com.ljq.provider.personprovider", "person", 1);//添加需要匹配uri,如果匹配就会返回匹配码 
//如果match()方法匹配content://com.ljq.provider.personprovider/person/230路径,返回匹配码为2 
smatcher.adduri("com.ljq.provider.personprovider", "person/#", 2);//#号为通配符 
switch (smatcher.match(uri.parse("content://com.ljq.provider.personprovider/person/10"))) { 
  case 1 
   break; 
  case 2 
   break; 
  default://不匹配 
   break; 
} 

注册完需要匹配的uri后,就可以使用smatcher.match(uri)方法对输入的uri进行匹配,如果匹配就返回匹配码,匹配码是调用adduri()方法传入的第三个参数,假设匹配content://com.ljq.provider.personprovider/person路径,返回的匹配码为1

四、contenturis类使用介绍

contenturis类用于操作uri路径后面的id部分,它有两个比较实用的方法:

withappendedid(uri, id)用于为路径加上id部分:

uri uri = uri.parse("content://com.ljq.provider.personprovider/person") 
uri resulturi = contenturis.withappendedid(uri, 10);  
//生成后的uri为:content://com.ljq.provider.personprovider/person/10 

parseid(uri)方法用于从路径中获取id部分:

uri uri = uri.parse("content://com.ljq.provider.personprovider/person/10") 
long personid = contenturis.parseid(uri);//获取的结果为:10 

五、使用contentprovider共享数据

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类型。如果操作的数据属于集合类型,那么mime类型字符串应该以vnd.android.cursor.dir/开头,

 例如:要得到所有person记录的uri为content://com.ljq.provider.personprovider/person,那么返回的mime类型字符串应该为:"vnd.android.cursor.dir/person"。

如果要操作的数据属于非集合类型数据,那么mime类型字符串应该以vnd.android.cursor.item/开头,

例如:得到id为10的person记录,uri为content://com.ljq.provider.personprovider/person/10,那么返回的mime类型字符串为:"vnd.android.cursor.item/person"。

六、使用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://com.ljq.providers.personprovider/person/10"),那么将会对主机名为com.ljq.providers.personprovider的contentprovider进行操作,操作的数据为person表中id为10的记录。
使用contentresolver对contentprovider中的数据进行添加、删除、修改和查询操作:

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); 

七、监听contentprovider中数据的变化

如果contentprovider的访问者需要知道contentprovider中的数据发生变化,可以在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); 
} 
} 

 如果contentprovider的访问者需要得到数据变化通知,必须使用contentobserver对数据(数据采用uri描述)进行监听,当监听到数据变化通知时,系统就会调用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) { 
   //此处可以进行相应的业务处理 
  } 
} 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。