本文详细介绍了Android开发的ContentProvider的使用说明。需要朋友推荐
前言
内容提供商为存储数据和获取数据提供了统一的接口,可以在不同的应用程序中共享数据。但是上一篇文章提到的关于如何使用Android开发的SQLite,只能在同一个应用中共享数据。此外,android为一些常见数据提供内容提供商,如音频、视频、图片、地址簿等。以便我们可以方便地操作这些类型的数据。使用ContentProvider的好处是开发人员不需要考虑数据是如何在内部存储的。例如,如果我们想要使用ContentProvider来存储数据,我们只需要告诉insert函数ContentProvider的uri和我们想要存储的数据(包括列名和值)。查询时也是如此。我们只需要输入Uri和被查询的表、列名和查询条件。至于这些操作是如何在Content Provider中执行的,我们就不需要知道了。
实验基础
要理解这个实验的内容,需要使用以下与ContentProvider相关的类。
UriMatcher:
要理解UriMatcher,首先需要了解android中的Uri表示方法。众所周知,Uri是一个统一的资源标识符,它表示要操作的数据。Android中的每一个资源(如文字、图片、视频等。)可以用Uri来表示。Android中的Uri由以下三部分组成:“content://”(authory)、数据的路径、资源标识id(可选),其中如果有ID,则表示特定的资源,如果没有ID,则表示路径下的整体。因此,addUri()函数的三个参数也对应着上述三个参数。
UriMatcher的匹配过程分为三步:初始化uri matcherUri注册时需要;与注册的URIs匹配。
ContentResolver:
当使用ContentProvider在不同的应用程序中共享数据时,其数据以类似于数据库中的表的方式公开。ContentResolver只是使用类似数据库的方法从ContentProvider访问数据。它通过Uri查询ContentProvider中提供的数据。查询时,您还需要知道目标数据库的名称、数据段的数据类型或资源的ID。
SQLiteQueryBuilder:
SQLiteQueryBuilder是一个用来产生SQL查询语句的辅助类,可以方便地访问SQLiteDatabase。在构造SQL查询语句时,还需要指定表名、列名、where条件等。
实验过程
本文通过一个例子来实现ContentProvider。其实一般情况下,我们不需要自己实现,而是使用andorid内置的ContentProvider。不过自己实现了一个之后,可以对它的原理有更深入的了解,以后用内置的就得心应手了。这是马尔斯先生说的。我还不够成熟,还没有深刻的体会。Mars将实施ContentProvider的步骤总结如下:
程序中需要四个java文件,因此在实现这些类时需要注意以下几点:
FirstProviderMetaData类:
因为在通过继承FirstContentProvider类获得的子类中使用了许多常量,所以我们在这里创建了一个专门存储这些常量的新类。这个类命名为FirstProviderMetaData,它包含作者名、数据库名、数据库版本号、表名、字符表名、子表Uri、子表ContentProvider数据类型等。单词list继承自BaseColumns类,该类已经有两个列_ID和_COUNT。
DatabaseHelper类:
类似于android中SQLite的使用,也需要一个继承SQLiteOpenHelper的子类。这个子类被命名为DatabaseHelper,我们在子类的回调函数onCreate()中构建了一个表。表中的表名和列名引用FirstProviderMetaData类中定义的常数。
FirstContentProvider类:
创建一个名为FirstContentProvider的新类,继承类ContentProvider,必须重写父类的以下五个方法,否则会报错。这五个方法是oncreate()、gettype()、insert()、update()和delete()。
onCreate()为回调函数,是指当内容提供者创建的时候调用,本程序在该函数中使用数据库助手新建了一个SQLite数据库。
在getType()方法完成的功能是根据传入的Uri,返回该上呼吸道感染所表示的数据类型。函数内部是使用的尿酸匹配器来匹配该函数所传进来的参数,来得到其数据类型。
插入()函数给指定的数据库表中插入一个指定的值,插入完成后必然会生成一个新的记录,然后利用该记录和表的上呼吸道感染重新生成一个新的Uri,这个上呼吸道感染就代表了插入成功的那条记录的Uri,该函数返回的也是这个尤里。
MainActivity类:
在主要活动中,主要是有2个按钮,分为为它们绑定了监听器,来完成插入和查询操作。
当单击插入按钮时,在监听器函数中会首先得到一个内容解析器,然后当在执行内容解析器的插入方法时会自动调用内容提供者的插入方法,因为内容解析器的插入方法中的第一个参数就为某个内容提供者的尤里。
AndroidManifest.xml:
内容提供者的使用需要在AndroidManifest.xml中进行注册,在活动标签外加入如下声明即可:
提供商Android:name=' com。举例。CP测试。第一内容提供商' Android:authorities=' com。举例。CP测试。第一个内容提供商'/
实验主要部分代码及注释:
MainActivity.java:
复制代码代码如下:包com。举例。CP测试;
//导入com。举例。CP测试。firstprovidermetadata导入com。举例。CP测试。firstprovidermetadata。usertablemetadata
导入安卓。app。活动;导入安卓。内容。内容值;导入安卓。数据库。光标;导入安卓。网。uri导入安卓。OS。捆绑;导入安卓。查看。菜单;导入安卓。查看。查看;导入安卓。查看。查看。onclick侦听器;导入安卓。小部件。按钮;
公共类主要活动扩展活动{
私有按钮插入=空私有按钮查询=null @ Override public void onCreate(Bundle savedInstanceState){ super。onCreate(savedInstanceState);setContentView(r . layout。活动_主);insert=(Button)findViewById(r . id。插入);insert.setOnClickListener(新的InsertOnClickListener());query=(Button)findViewById(r . id。查询);查询。setonclicklistener(new QueryOnClickListener());系统。出去。println(getContentResolver().getType(FirstProviderMetaData .UserTableMetaData。内容_ URI));}
//往子表中插入一条记录公共类InsertOnClickListener实现OnClickListener{
public void onClick(View arg 0){//TODO自动生成的方法存根内容值values=新内容值();价值观。put(FirstProviderMetaData .UserTableMetaData。用户名,'龙卷风相遇');//实际上使用的是内容解析器的插入方法//该插入中有2个参数,第一个为代表了内容提供者的Uri,第二个参数为要插入的值。此处的插入函数//一执行,则自动调用内容提供者的插入方法Uri uri=getContentResolver().insert(FirstProviderMetaData .UserTableMetaData。内容_URI值);系统。出去。println(' uri-' uri。tostring());} }
//查询也是采用的内容解析器中的询问方法公共类QueryOnClickListener实现onClick侦听器{ public void onClick(View v){//TODO自动生成的方法存根游标c=getContentResolver().查询(FirstProviderMetaData .UserTableMetaData。CONTENT_URI,null,null,null,null);while(c .移到下一个())系统。出去。println(c . getstring(c . getcolumnindex(UserTableMetaData .USER _ NAME)));} }
@ Override public boolean oncreateoptions Menu(Menu Menu){ getMenuInflater().inflate(R.menu.activity_main,menu);返回true} }数据库助手:复制代码代码如下:包com。举例。CP测试;
导入安卓。内容。语境;导入安卓。数据库。SQLite。SQLite数据库;导入安卓。数据库。SQLite。sqliteopenhelper导入安卓。数据库。SQLite。SQLite数据库。光标工厂;
公共类数据库助手扩展SQLiteOpenHelper {
private static final int VERSON=1;//默认的数据库版本
//继承SQLiteOpenHelper类的类必须有自己的构造函数//该构造函数四个参数,直接调用父类的构造函数。其中第一个参数为该类本身;第二个参数为数据库的名字;//第3个参数是用来设置游标对象的,这里一般设置为空参数四是数据库的版本号public database helper(Context Context,String name,cursor Factory factory,int verson){ super(context,name,Factory,verson);}
//该构造函数有3个参数,因为它把上面函数的第3个参数固定为空了public database helper(Context Context,String name,int verson){ this(context,name,null,verson);}
//该构造函数只有2个参数,在上面函数的基础山将版本号固定了public database helper(Context Context,String name){ this(context,name,VERSON);}
//该函数在数据库第一次被建立时调用@ Override public void onCreate(SQLite database arg 0){//TODO自动生成的方法存根系统。出去。println('创建数据库');//execSQL()为执行参数里面的结构化查询语言语句,因此参数中的语句需要符合结构化查询语言语法,这里是创建一个表//arg 0。exec SQL(' create table user 1(id int,name varchar(20))');下面的语句格式是与该句类似//arg 0。exec SQL(' create table ' FirstProviderMetaData .USERS _ TABLE _ NAME//'(' firstprovidermetadata。usertablemetadata。_ ID//'整数主键自动增量,//ID类型为自增长的整型//FirstProviderMetaData .用户表元数据。USER _ NAME ' varchar(20));'//);//arg 0。exec SQL(' create table user 1(id int,name varchar(20))');参数0。exec SQL(' create table ' FirstProviderMetaData .user _ TABLE _ NAME '(' FirstProviderMetaData。usertablemetadata。_ ID '整数主键自动增量,' FirstProviderMetaData .用户表元数据。USER _ NAME ' varchar(20))');System.out.println('创建数据库ok’);}
@ Override public void on upgrade(SQLite database arg 0,int arg1,int arg2) { //TODO自动生成的方法存根系统。出去。println('更新数据库');}
}FirstProviderMetaData.java:复制代码代码如下:包com。举例。CP测试;
导入安卓。网。uri导入安卓。提供商。基础列;
公共类第一提供者元数据{
//这里的作者为包的全名内容提供者子类的全名公共静态最终字符串作者ty=' com。举例。CP测试。“第一内容提供商”;//数据库的名称公共静态最终字符串DATABASE _ NAME=' fisrtprovider。db ';//数据库的版本号public static final int DATABASE _ VERSION=1;//数据库中的表名公共静态最终字符串USERS _ TABLE _ NAME=' users//表中的字表公共静态最终类用户表元数据实现BaseColumns{ //子表名公共静态最终字符串TABLE _ NAME=' users//内容_URI为常量上呼吸道感染从语法上分析是将文本转换成上呼吸道感染公共静态最终内容URI=Uri。parse(' CONTENT://' author ty '/users ');//返回内容提供者中表的数据类型公共静态最终字符串CONTENT _ TYPE=' vnd。安卓。光标。dir/vnd第一提供商。用户';//返回内容提供者表中项目的数据类型公共静态最终字符串CONTENT _ TYPE _ ITEM=' vnd。安卓。光标。项目/越南盾。第一提供商。用户';//子表列名公共静态最终字符串USER _ NAME=' name//表中记录的默认排序算法,这里是降序排列公共静态最终字符串DEFAULT _ SORT _ ORDER=' _ id desc ';
}
}FirstContentProvider.java:复制代码代码如下:包com。举例。CP测试;
导入Java。util。hashmap
导入安卓。内容。内容提供商;导入安卓。内容。内容URIs;导入安卓。内容。内容值;导入安卓。内容。uri匹配器;导入安卓。数据库。光标;导入安卓。数据库。sqlexception导入安卓。数据库。SQLite。SQLite数据库;导入安卓。数据库。SQLite。sqlitequerybuilder导入安卓。网。uri导入安卓。文字。文本实用程序;
导入com。举例。CP测试。firstprovidermetadata。usertablemetadata
公共类FirstContentProvider扩展了ContentProvider {
//定义一个尿酸匹配器类对象,用来匹配上呼吸道感染的公共静态最终uri匹配器uri匹配器;//组时的ID public static final int INCOMING _ USER _ COLLECTION=1;//单个时的ID public static final int INCOMING _ USER _ SIGNAL=2;私有DatabaseHelper dh//定义一个数据库助手对象static { uri matcher=新的uri匹配器(uri匹配器.NO _ MATCH);//UriMatcher .不匹配表示不匹配任何路径的返回码uri匹配器。adduri(FirstProviderMetaData .AUTHORTY,' users ',INCOMING _ USER _ COLLECTION);uri匹配器。adduri(FirstProviderMetaData .AUTHORTY,' users/# ',INCOMING _ USER _ SIGNAL);//后面加了#表示为单个}
公共静态HashMapString,字符串userProjectionMap//新建一个散列表,后面执行插入操作时有用static { userProjectionMap=new HashMapString,String();//这里可以直接调用另外一个类的公众的变量,这里放里面的2个参数一样, //是因为这里是给数据库表中的列取别名,因此取的是一样的名字userprojectionmap。put(UserTableMetaData ._ID,UserTableMetaData ._ ID);userprojectionmap。put(UserTableMetaData .用户名,用户表元数据。用户名);}
//得到内容提供者的数据类型,返回的参数上呼吸道感染所代表的数据类型@ Override公共字符串getType(Uri arg 0){//TODO自动生成方法存根系统。出去。println(' getType ');开关(uri匹配器。match(arg 0)){//匹配器满足上呼吸道感染的前2项(即协议路径)为第一种情况时,开关语句的值为上呼吸道感染的第3项,此处为INCOMING _ USER _ COLLECTION案例INCOMING _ USER _ COLLECTION:返回用户表元数据.内容类型;案例输入_用户_信号://同上返回用户表元数据.内容类型项目;默认:抛出新的IllegalArgumentException('未知的URI ' arg 0);//抛出是处理异常的,java中的语法} }
@ Override public int delete(Uri Uri,String selection,String[] selectionArgs) { //TODO自动生成方法存根系统。出去。println(“delete”);返回0;}
@ Override public int update(Uri Uri,ContentValues values,String selection,String[] selectionArgs) { //TODO自动生成方法存根系统。出去。println('更新');返回0;}
@ Override public Uri insert(Uri Uri,ContentValues values) { //TODO自动生成的方法存根系统。出去。println(“insert”);//DH=新建数据库助手(get context(),FirstProviderMetaData .DATABASE _ NAME);SQLite数据库db=DH。getwritabledatabase();long rowId=db。insert(UserTableMetaData .TABLE_NAME,null,values);//System.out.println('插入OK’);//系统。出去。println(' rowId ');if(rowId 0){ //发出通知给监听器,说明数据已经改变//ContentUris为工具类uri insertedUserUri=内容URIs。withappendedid(UserTableMetaData .CONTENT_URI,rowId);getContext()。getContentResolver().notifyChange(insertedUserUri,null);
返回insertedUserUri}抛出新的SQLException('未能将行插入uri’);}
//回调函数,在内容提供者创建的时候调用@ Override public boolean onCreate(){//TODO自动生成方法存根系统。出去。println(' onCreate ');DH=新数据库助手(get context(),FirstProviderMetaData).DATABASE _ NAME);//创建一个数据库助手对象返回真实}
@ Override public Cursor query(Uri Uri,String[] projection,String selection,String[] selectionArgs,String sortOrder) { //TODO自动生成方法存根系统。出去。println(' query ');SQLiteQueryBuilder QB=new SQLiteQueryBuilder();开关(uri匹配器。匹配(uri)){ case INCOMING _ USER _ COLLECTION:QB。settables(UserTableMetaData .TABLE _ NAME);//设置表的名称QB。setprojectionmap(userProjectionMap);//其中用户项目映射为上面建立好了的hashmap break case INCOMING _ USER _ SIGNAL:QB。settables(UserTableMetaData .TABLE _ NAME);//设置表的名称QB。setprojectionmap(userProjectionMap);//其中用户项目映射为上面建立好了的hashmap //uri.getPathSegments()得到小路部分,即把上呼吸道感染的协议作者部分去掉,把剩下的部分分段获取,这里取第//一部分QB。appendwhere(UserTableMetaData ._ID '=' uri.getPathSegments().get(1));//设置在哪里条件打破;} //排序字符串orderByif(textutils。isempty(排序顺序)){ order by=UserTableMetaData .默认_排序_顺序;//传入的排序参数为空的时候采用默认的排序} else { orderBy=sortOrder//不为空时用指定的排序方法进行排序} SQLiteDatabase db=DH。getwritabledatabase();//采用传入的参数进行查询Cursor c=qb.query(db,projection,selection,selectionArgs,null,null,排序顺序);//发出通知setnotificationuri(获取上下文().getContentResolver(),uri);返回c;}
}
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。