Android四大组之ContentProvider
应用场景:
在Android官方指出的Android的数据存储方式总共有五种,分别是:Shared Preferences、网络存储、文件存储、外储存储、SQLite。但是我们知道一般这些存储都只是在单独的一个应用程序之中达到一个数据的共享,而且这些知识在前面我都有介绍,有时候我们需要操作其他应用程序的一些数据,例如我们需要操作系统里的媒体库、通讯录等,这时我们就可能通过ContentProvider来满足我们的需求了
ContentProvider概述:
ContentProvider向我们提供了我们在应用程序之前共享数据的一种机制,而我们知道每一个应用程序都是运行在不同的应用程序的,数据和文件在不同应用程序之间达到数据的共享不是没有可能,而是显得比较复杂,而正好Android中的ContentProvider则达到了这一需求,比如有时候我们需要操作手机里的联系人,手机里的多媒体等一些信息,我们都可以用到这个ContentProvider来达到我们所需。
如何理解ContentProvider
上面说了一大堆ContentProvider的概述,可能大家还是不太特别理解ContentProvider到底是干什么的,那么我们以一个网站来形象的描述这个ContentProvider吧,可以这么理解为ContentProvider就是一个网站,它向我们去访问网站这里的数据达到了一种可能,它就是一个向外提供数据的接口。那么既然它是向外提供数据,我们有时候也需要去修改数据,这时我们就可以用到另外一个类来实现这个对数据的修改ContentResolver类,这个类就可以通过URI来操作数据。至于这些类的作用及描述在下面就会一一的介绍到。
如何实现ContentProvider
理解了ContentProvider类,那么我们怎么去实现ContentProvider呢?怎么样让外部程序去访问或者修改我们的数据呢?这样的一个操作其实是非常简单的,我们只需要下面的两步就可以实现ContentProvider
1、 编写一个实现ContentProvider的在,这个子类必须要实现一些必须实现的方法,在ContentProvider类里面,有一系列针对于数据的增、删、改、查等方法
2、 ContentProvider也是Android中的四大组件,因此也必须在AndroidMainfest.xml中完成对ContentProvider的注册。注册方式为:
与ContentProvider相关操作的类介绍
从Uri谈起
什么是Uri?
Uri是指通用资源标志符
A:前缀表明数据受控于一个内容提供者。它从不修改,也就是schema
B:是指在AndroidMainfest.xml中我们注册的provider中的android:authorities属性所对应的
C:具体操作于哪个条目
D:具体指定到哪个条目下的哪条记录
再看它的类结构和常用方法:
Uri
在这个里它是没有构造方法的,它通常通过下面的这个方法来返回一个Uri对象
方法名称 | 描述 |
public static Uri parse (String uriString) | 通过一个传入的字符串来构造一个Uri对象 |
熟悉完Uri类再看与之相关的另外两个类
UriMatcher类:
因为Uri代表了要操作的数据,所以我们经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris 。掌握它们的使用,会便于我们的开发工作。
先看下它比较常用的几个方法:
方法名称 | 描述 |
public void addURI (String authority, String path, int code) | 往UriMatcher类里添加一个拼凑的Uri,在此我们可以理解为UriMatcher为一个Uri的容器,为个容器里面包含着我们即将可能要操作的Uri,它用于我们业务逻辑的处理,特别是第三个参数code,如果通过下面的match()方法匹配成功就返回这个code值 |
public int match (Uri uri) | 与传入的Uri匹配,它会首先与找我们之前通过addURI方法添加进来的Uri匹配,如果匹配成功就返回之前我们设置的code值,否则返回一个UriMatcher.NO_MATCH常量值为-1 |
熟悉完上面的方法,那么我们再来看它如何使用:
UriMatcher类用于匹配Uri,它的用法如下:
UriMatcher类的用法
首先第一步把你需要匹配Uri路径全部给注册上,如下:
//常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//如果match()方法匹配content:// com.jiahui.provider.myprovider/person路径,返回匹配码为1
sMatcher.addURI(“com.jiahui.provider.myprovider”, “person”, 1);//添加需要匹配uri,如果匹配就会返回匹配码
//如果match()方法匹配content:// com.jiahui.provider.myprovider /person/230路径,返回匹配码为2
sMatcher.addURI(“com.jiahui.provider.myprovider”, “person/#”, 2);//#号为通配符
switch (sMatcher.match(Uri.parse("content:// com.jiahui.provider.myprovider /person/10"))) {
case 1
break;
case 2
break;
default://不匹配
break;
}
注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假设匹配content://cn.itcast.provider.personprovider/person路径,返回的匹配码为1
再看另外一个工具类
ContentUris:
它用于在Uri后面追加一个ID或者解析出传入的Uri所带上的ID值,常用的两个方法如下:
方法名称 | 描述 |
public static Uri withAppendedId (Uri contentUri, long id) | 用于为路径加上ID部分 |
public static long parseId (Uri contentUri) | 从路径中获取ID部分 |
熟悉完上面所提及的相关的类,接下来我们再看这个ContentProvider核心类
ContentProvider
常用方法
方法名称 | 描述 |
public abstract boolean onCreate () | 在ContentProvider创建后被调用。 |
public abstract Uri insert (Uri uri, ContentValues values) | 根据Uri插入values对就的数据 |
public abstract int delete (Uri uri, String selection, String[] selectionArgs) | 根据Uri删除selection指定的条件所匹配的全部记录 |
public abstract int update (Uri uri, ContentValues values, String selection, String[] selectionArgs) | 根据Uri修改selection指定的条件所匹配的全部记录 |
public abstract Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) | 根据Uri查询出selection指定的条件所匹配的全部记录,并且可以指定查询哪些列(projection),以什么方式(sortOrder)排序 |
public abstract String getType (Uri uri) | 返回当前Uri所数据的MIME类型,如果该Uri对应的数据可能包括多条记录,那么MIME类型字符串就是以vnd.android.cursor.dir/开头,如果Uri对应的数据只包含一条记录,那么MIME类型字符串就是以vnd.android.cursor.item/开头 |
既然我们知道了ContentProvider类是向外提供数据的一种机制,那么在之前我们也说过要想来操作这个对外提供的数据,我们就用到了另外一个类:
ContentResolver
在这个类里面也定义了一系列的增、删、改、查方法,与其ContentProvider定义的方法基本上相同,在此不再复核。读者可以自己查阅相关文档。
可能大家在这里还是有点理不清这些类的一些关系,特别是ContentResolver与ContentProvider与Uri类的关系,那么我上张图吧,或许对大家有所帮助:
好了熟悉完上面所述的这么多类那么我们就在实践中见证真理吧:
实例:
实现效果:
代码实现:
先开发我们自己的ContentProvider:
[java] view plain copy print ? <EMBED id=ZeroClipboardMovie_1 name=ZeroClipboardMovie_1 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer height=16 width=32 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=1&width=32&height=16" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">- packagecom.jiahui.provider;
- importcom.jiahui.db.DBHelper;
- importandroid.content.ContentProvider;
- importandroid.content.ContentUris;
- importandroid.content.ContentValues;
- importandroid.content.UriMatcher;
- importandroid.database.Cursor;
- importandroid.database.sqlite.SQLiteDatabase;
- importandroid.net.Uri;
- publicclassMyProviderextendsContentProvider{
- privateDBHelperdbHelper;
- //定义一个UriMatcher类
- privatestaticfinalUriMatcherMATCHER=newUriMatcher(
- UriMatcher.NO_MATCH);
- privatestaticfinalintPERSONS=1;
- privatestaticfinalintPERSON=2;
- static{
- MATCHER.addURI("com.jiahui.provider.myprovider","person",PERSONS);
- MATCHER.addURI("com.jiahui.provider.myprovider","person/#",PERSON);
- }
- @Override
- publicbooleanonCreate(){
- System.out.println("---oncreate----");
- dbHelper=newDBHelper(this.getContext());
- returnfalse;
- }
- //查询数据
- @Override
- publicCursorquery(Uriuri,String[]projection,Stringselection,
- String[]selectionArgs,StringsortOrder){
- SQLiteDatabasedb=dbHelper.getWritableDatabase();
- switch(MATCHER.match(uri)){
- casePERSONS:
- //查询所有的数据
- returndb.query("person",projection,selection,selectionArgs,
- null,null,sortOrder);
- casePERSON:
- //查询某个ID的数据
- //通过ContentUris这个工具类解释出ID
- longid=ContentUris.parseId(uri);
- Stringwhere="_id="+id;
- if(!"".equals(selection)&&selection!=null){
- where=selection+"and"+where;
- }
- returndb.query("person",projection,where,selectionArgs,null,
- null,sortOrder);
- default:
- thrownewIllegalArgumentException("unknowuri"+uri.toString());
- }
- }
- //返回当前操作的数据的mimeType
- @Override
- publicStringgetType(Uriuri){
- switch(MATCHER.match(uri)){
- casePERSONS:
- return"vnd.android.cursor.dir/person";
- casePERSON:
- return"vnd.android.cursor.item/person";
- default:
- thrownewIllegalArgumentException("UnkwonUri:"+uri.toString());
- }
- }
- //插入数据
- @Override
- publicUriinsert(Uriuri,ContentValuesvalues){
- SQLiteDatabasedb=dbHelper.getWritableDatabase();
- UriinsertUri=null;
- switch(MATCHER.match(uri)){
- casePERSONS:
- longrowid=db.insert("person","name",values);
- insertUri=ContentUris.withAppendedId(uri,rowid);
- break;
- default:
- thrownewIllegalArgumentException("UnkwonUri:"+uri.toString());
- }
- returninsertUri;
- }
- //删除数据
- @Override
- publicintdelete(Uriuri,Stringselection,String[]selectionArgs){
- SQLiteDatabasedb=dbHelper.getWritableDatabase();
- intcount=0;
- switch(MATCHER.match(uri)){
- casePERSONS:
- count=db.delete("person",selection,selectionArgs);
- returncount;
- casePERSON:
- longid=ContentUris.parseId(uri);
- Stringwhere="_id="+id;
- if(selection!=null&&!"".equals(selection)){
- where=selection+"and"+where;
- }
- count=db.delete("person",where,selectionArgs);
- returncount;
- default:
- thrownewIllegalArgumentException("UnkwonUri:"+uri.toString());
- }
- }
- //更新数据
- @Override
- publicintupdate(Uriuri,ContentValuesvalues,Stringselection,
- String[]selectionArgs){
- SQLiteDatabasedb=dbHelper.getWritableDatabase();
- intcount=0;
- switch(MATCHER.match(uri)){
- casePERSONS:
- count=db.update("person",values,selection,selectionArgs);
- break;
- casePERSON:
- //通过ContentUri工具类得到ID
- longid=ContentUris.parseId(uri);
- Stringwhere="_id="+id;
- if(selection!=null&&!"".equals(selection)){
- where=selection+"and"+where;
- }
- count=db.update("person",values,where,selectionArgs);
- break;
- default:
- thrownewIllegalArgumentException("UnkwonUri:"+uri.toString());
- }
- returncount;
- }
- }
千万别忘记了要在AndroidMainfest.xml文件中注册这个组件哦:
[html] view plain copy print ? <EMBED id=ZeroClipboardMovie_2 name=ZeroClipboardMovie_2 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer height=16 width=32 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=2&width=32&height=16" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">- <provider
- android:authorities="com.jiahui.provider.myprovider"
- android:name=".MyProvider">
- </provider>
然后在一个主Activity编写一些实现代码:
[java] view plain copy print ? <EMBED id=ZeroClipboardMovie_3 name=ZeroClipboardMovie_3 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer height=16 width=32 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=3&width=32&height=16" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">- packagecom.jiahui.provider;
- importjava.util.ArrayList;
- importjava.util.HashMap;
- importjava.util.List;
- importjava.util.Map;
- importandroid.app.Activity;
- importandroid.content.ContentResolver;
- importandroid.content.ContentUris;
- importandroid.content.ContentValues;
- importandroid.content.Context;
- importandroid.content.Intent;
- importandroid.database.Cursor;
- importandroid.net.Uri;
- importandroid.os.Bundle;
- importandroid.os.Handler;
- importandroid.os.Message;
- importandroid.view.View;
- importandroid.widget.AdapterView;
- importandroid.widget.AdapterView.OnItemClickListener;
- importandroid.widget.Button;
- importandroid.widget.EditText;
- importandroid.widget.ListView;
- importandroid.widget.SimpleAdapter;
- importandroid.widget.Toast;
- importcom.jiahui.model.Person;
- publicclassContentProviderDemoActivityextendsActivity{
- privateButtonbtnadd,btnqueryall;
- privateEditTextedtname,edtage;
- privateListViewlvall;
- privateList<Person>persons;
- privateSimpleAdaptersimpleAdapter;
- privateHandlerhandler=newHandler(){
- @Override
- publicvoidhandleMessage(Messagemsg){
- List<Map<String,Object>>data=(List<Map<String,Object>>)msg.obj;
- System.out.println(data.size());
- simpleAdapter=newSimpleAdapter(
- ContentProviderDemoActivity.this,data,R.layout.list_item,
- newString[]{"id","name","age"},newint[]{
- R.id.tvId,R.id.tvname,R.id.tvage});
- lvall.setAdapter(simpleAdapter);
- }
- };
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- persons=newArrayList<Person>();
- btnqueryall=(Button)this.findViewById(R.id.btnqueryall);
- btnadd=(Button)this.findViewById(R.id.btnadd);
- edtname=(EditText)this.findViewById(R.id.edtname);
- edtage=(EditText)this.findViewById(R.id.edtage);
- lvall=(ListView)this.findViewById(R.id.lvall);
- btnadd.setOnClickListener(newView.OnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- ContentResolvercontentResolver=ContentProviderDemoActivity.this
- .getContentResolver();
- Uriurl=Uri
- .parse("content://com.jiahui.provider.myprovider/person");
- ContentValuesvalues=newContentValues();
- values.put("name",edtname.getText().toString());
- values.put("age",edtage.getText().toString());
- Uriresult=contentResolver.insert(url,values);
- System.out.println(result.toString());
- if(ContentUris.parseId(result)>0){
- Toast.makeText(ContentProviderDemoActivity.this,"添加成功",Toast.LENGTH_LONG).show();
- //添加成功后再启动线程查询
- MyThreadthread=newMyThread(ContentProviderDemoActivity.this);
- thread.start();
- }
- }
- });
- //查询所有
- btnqueryall.setOnClickListener(newView.OnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- MyThreadthread=newMyThread(ContentProviderDemoActivity.this);
- thread.start();
- }
- });
- lvall.setOnItemClickListener(newOnItemClickListener(){
- @Override
- publicvoidonItemClick(AdapterView<?>parent,Viewview,
- intposition,longid){
- //Toast.makeText(ContentProviderDemoActivity.this,position,
- //Toast.LENGTH_LONG).show();
- System.out.println("position:"+position);
- Personperson=persons.get(position);
- Bundlebundle=newBundle();
- bundle.putInt("id",person.getId());
- bundle.putString("name",person.getName());
- bundle.putInt("age",person.getAge());
- Intentintent=newIntent(ContentProviderDemoActivity.this,
- ItemActivity.class);
- intent.putExtra("item",bundle);
- startActivityForResult(intent,1);
- }
- });
- }
- @Override
- protectedvoidonActivityResult(intrequestCode,intresultCode,Intentdata){
- if(resultCode==2){
- MyThreadthread=newMyThread(ContentProviderDemoActivity.this);
- thread.start();
- }
- }
- classMyThreadextendsThread{
- Contextcontext;
- publicMyThread(Contextcontext){
- //一定要清空。否则会有问题,每执行一次都会把之前的全部的item加进去
- persons.clear();
- lvall.setAdapter(null);
- this.context=context;
- }
- @Override
- publicvoidrun(){
- Uriurl=Uri
- .parse("content://com.jiahui.provider.myprovider/person");
- Cursorcursor=context.getContentResolver().query(url,
- newString[]{"_id","name","age"},null,null,"_id");
- while(cursor.moveToNext()){
- //System.out.println("_id:"
- //+cursor.getInt(cursor.getColumnIndex("_id")));
- //System.out.println("name:"
- //+cursor.getString(cursor.getColumnIndex("name")));
- //System.out.println("age:"
- //+cursor.getInt(cursor.getColumnIndex("age")));
- Personperson=newPerson();
- person.setId(cursor.getInt(cursor.getColumnIndex("_id")));
- person.setName(cursor.getString(cursor.getColumnIndex("name")));
- person.setAge(cursor.getInt(cursor.getColumnIndex("age")));
- persons.add(person);
- }
- cursor.close();
- List<Map<String,Object>>data=newArrayList<Map<String,Object>>();
- Map<String,Object>map=null;
- for(inti=0;i<persons.size();i++){
- map=newHashMap<String,Object>();
- map.put("id",persons.get(i).getId());
- map.put("name",persons.get(i).getName());
- map.put("age",persons.get(i).getAge());
- data.add(map);
- }
- if(data.size()>=persons.size()){
- }
- Messagemsg=handler.obtainMessage();
- msg.obj=data;
- handler.sendMessage(msg);
- }
- }
- }
ItemActivity代码:
[java] view plain copy print ? <EMBED id=ZeroClipboardMovie_4 name=ZeroClipboardMovie_4 type=application/x-shockwave-flash align=middle pluginspage=http://www.macromedia.com/go/getflashplayer height=16 width=32 src=http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf wmode="transparent" flashvars="id=4&width=32&height=16" allowfullscreen="false" allowscriptaccess="always" bgcolor="#ffffff" quality="best" menu="false" loop="false">- packagecom.jiahui.provider;
- importandroid.app.Activity;
- importandroid.content.ContentResolver;
- importandroid.content.ContentValues;
- importandroid.content.Intent;
- importandroid.net.Uri;
- importandroid.os.Bundle;
- importandroid.view.View;
- importandroid.widget.Button;
- importandroid.widget.EditText;
- importandroid.widget.TextView;
- importandroid.widget.Toast;
- publicclassItemActivityextendsActivity{
- privateEditTextedt_item_name;
- privateEditTextedt_item_age;
- privateEditTextedt_item_id;
- privateButtonbtndel,btnupdate;
- privateIntentintent;
- @Override
- protectedvoidonCreate(BundlesavedInstanceState){
- //TODOAuto-generatedmethodstub
- super.onCreate(savedInstanceState);
- setContentView(R.layout.item);
- edt_item_id=(EditText)this.findViewById(R.id.edt_item_id);
- edt_item_id.setEnabled(false);//控制不可用
- edt_item_name=(EditText)this.findViewById(R.id.edt_item_name);
- edt_item_age=(EditText)this.findViewById(R.id.edt_item_age);
- //得到传过来的数据
- btndel=(Button)this.findViewById(R.id.btndel);
- btnupdate=(Button)this.findViewById(R.id.btnupdate);
- intent=getIntent();
- Bundlebundle=intent.getBundleExtra("item");
- intid=bundle.getInt("id");
- System.out.println("id----"+id);
- Stringname=bundle.getString("name");
- intage=bundle.getInt("age");
- edt_item_id.setText(String.valueOf(id));
- edt_item_name.setText(name);
- edt_item_age.setText(String.valueOf(age));
- btndel.setOnClickListener(newView.OnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- ContentResolvercontentResolver=ItemActivity.this
- .getContentResolver();
- //构建Uri
- Stringurl="content://com.jiahui.provider.myprovider/person/"
- +edt_item_id.getText();
- Uriuri=Uri.parse(url);
- intresult=contentResolver.delete(uri,null,null);
- System.out.println("deleteresult:"+result);
- if(result>=1){
- Toast.makeText(ItemActivity.this,"删除成功",Toast.LENGTH_LONG)
- .show();
- ItemActivity.this.setResult(2);
- ItemActivity.this.finish();
- }
- }
- });
- btnupdate.setOnClickListener(newView.OnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- ContentResolvercontentResolver=ItemActivity.this
- .getContentResolver();
- //构建Uri
- Stringurl="content://com.jiahui.provider.myprovider/person/"
- +edt_item_id.getText();
- Uriuri=Uri.parse(url);
- ContentValuesvalues=newContentValues();
- values.put("name",edt_item_name.getText().toString());
- values.put("age",
- Integer.parseInt(edt_item_age.getText().toString()));
- intresult=contentResolver.update(uri,values,null,null);
- System.out.println("updateresult:"+result);
- if(result>=1){
- Toast.makeText(ItemActivity.this,"更新成功",Toast.LENGTH_LONG)
- .show();
- ItemActivity.this.setResult(2);
- ItemActivity.this.finish();
- }
- }
- });
- }
- }
特别说明:这个例子也是与之前讲过的一讲与SQLite知识相关的代码中一个类,读者需要用到之前的DBHelper类,请自行拷贝。
更多相关文章
- Android--GreenDao
- android 识别U盘以及读写文件的方法
- Android仿小米商城底部导航栏(基于BottomNavigationBar)
- 更快实现Android多级树形选择列表
- Android(安卓)Dependencies小差号引起的问题
- [转]Android读写XML(中)——SAX
- Android上传图片的方式
- Android(安卓)Studio下三种包名的修改方法
- Android(安卓)模板方法模式