android contentprovider简单讲解
来源:互联网 发布:mac物理地址 编辑:程序博客网 时间:2024/05/01 23:27
文章的开头奉送上代码方便大家对照学习。
1 ContentProvider简介
ContentProvider是android4大组件之一,它的出现是为了在二个应用之间共享数据。
在Android中,对数据的保护是很严密的,除了放在SD卡中的数据,一个应用所持有的数据库、文件、等等内容,都是不允许其他直接访问的。但有时候沟通是必要的,不仅对第三方很重要,对应用自己也很重要。比如,一个联系人管理的应用。如果不允许第三方的应用对其联系人数据库进行增删该查,整个应用就失去了可扩展力,必将被其他应用抛弃,然后另立门户,自个玩自个的去了。Andorid当然不会真的把每个应用都做成一座孤岛,它为所有应用都准备了一扇窗,这就是Content Provider。
Content Provider屏蔽了内部数据的存储细节,向外提供了上述统一的接口模型。这样大大简化了我们代码的书写。
在使用ContentProvider时我们需要用到以下工具,这里先做简单介绍,下面会仔细讲解:
2 ContentProvider相关类的介绍
这些类大家看不懂也不要紧,大体看一下心里有个印象就行。我们在contentProvider实例讲解用到的时候直接到这里面查阅就行。
2.1 Uri介绍
外部应用通过uri来唯一标识一个ContentProvider。
举个例子:
由图中可以看出uri分3部分:
1.scheme:content://
固定写法,表示这个uri指定一个contentprovider(即我们要访问的是一个contentprovider)。
2.主机名(或叫Authority)用于唯一标识一个contentyprovider。注意这个主机名必须和menifest中contentProvider的authorities属性一样,不然找不到我们需要的contentyprovider。在本例子中主机名是:com.ljq.provider.personprovider
3.路径用来表示我们要操作的数据,路径的构建应根据业务而定。例如:
/person/10:要操作person表中id为10的记录person/10/name:要操作person表中id为10的记录的name字段, /person:要操作person表中的所有记录/xxx:要操作xxx表中的记录
如果你想创建自己的contentprovider,最好把自定义的URI设置为常量,这样简化别人的调用,并且以后如果更新URI也很容易。android定义了CONTENT_URI常量用于URI,比如:
public static final Uri CONTENT_URI =
Uri.parse(“content://contacts/people”);
可能大家看到这里还是不知道uri怎么用,我学习的时候也有这个疑问,不要着急,uri要结合UriMatcher和ContentUris一块使用的,下面会讲到。
2.2 ContentResolver
在外部应用的activity中通过getContentResolver()方法来获取对象,然后进行增删改查操作,步骤如下:
1.获取ContentResolver。
getContentResolver()
2.利用ContentResolver增删改查:
增:getContentResolver().insert(Uri url, ContentValues values);删:getContentResolver().delete(Uri url, String where, String[] selectionArgs)改:getContentResolver().update(Uri uri, ContentValues values, String where, String[] selectionArgs)查:getContentResolver().query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);
在这4个方法中,每一个方法都需要一个uri,因为这个uri唯一标识一个contentyprovider(内部是怎么实现的我们下面会讲到,这里不做介绍)。其他的参数就和sqlite操作的参数大同小异,这里不做介绍。
2.3 UriMatcher
UriMatcher用来匹配uri的作用。UriMatcher中只有3个方法(包括构造方法):
1.UriMatcher(int code)方法
构造方法,固定写法:new UriMatcher(UriMatcher.NO_MATCH)
2.addURI(String authority, String path, int code)方法
添加匹配规则
这里对path讲一下,因为它比较灵活,”*”表于匹配所有的字符串,”#” 表示匹配所有数字,如:
uri的路径是: “/people” sURIMatcher.addURI("contacts", "people", PEOPLE); uri的路径是: “/people/10” sURIMatcher.addURI("contacts", "people/#", PEOPLE_ID); uri的路径是: “/people/10/phones” sURIMatcher.addURI("contacts", "people/#/phones", PEOPLE_PHONES); uri的路径是: “/people/10/phones/3” sURIMatcher.addURI("contacts", "people/#/phones/#", PEOPLE_PHONES_ID);
3.match(Uri uri)方法
根据addURI()方法添加的匹配规则来匹配,如果匹配到了就会返回响应的匹配码。如:
int matchId= sURIMatcher.match(uri); switch(matchId){ case 1://表示访问的student表 break; case 2://表示访问的是teacher表 break;}
2.4 ContentProvider
终于讲到我们的重点了,使用步骤如下:
1.继承ContentProvider重写它的方法:
onCreate()query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)getType(Uri uri)insert(Uri uri, ContentValues values)delete(Uri uri, String selection, String[] selectionArgs) update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
在ContentProvider中,我们要给UriMatcher添加匹配规则,做匹配操作。
2.在menifenst中注册:
<providerandroid:name=".contentprovider.MyContentProvider"android:authorities="com.czh.mycontentprovider.study" />
注意android:authorities是主机名,唯一标识这个ContentProvider,外部应用也是通过这个来查找。
2.5 补充ContentUris
ContentUris是一个辅助工具类,里面全是静态方法,我们看一下:
3 ContentProvider实例
呼!终于讲到实例了。接下来我们自定义ContentProvider来访问数据库。
第一步重写contentProvider:
public class MyContentProvider extends ContentProvider { private final static int MyStudyTableFlag = 1;//查询表的标记,建议大家都弄成常量 private final static int MyStudyTableNumFlag = 2;//查询表的标记,建议大家都弄成常量 private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); static{//静态语句块,当第一次加载的时候调用 //匹配查询表 sURIMatcher.addURI(Constant.Authorities, Constant.TableName, MyStudyTableFlag); //匹配查询表中的特定记录 sURIMatcher.addURI(Constant.Authorities, Constant.TableName+"/#", MyStudyTableNumFlag); } @Override public boolean onCreate() { Log.d(Constant.TAG,"--MyContentProvider--onCreate--"); return false; } @Nullable @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Log.d(Constant.TAG,"--MyContentProvider--query--"); int matchId= sURIMatcher.match(uri); switch(matchId) { case MyStudyTableFlag://如果查询的是表 SQLiteDatabase db1 = SqlManager.getInstance(getContext()).getWritableDatabase();// String selectSql1 = "select * from " + Constant.TableName; Cursor cursor1 = db1.query(true, Constant.TableName, projection, selection, selectionArgs, null, null, null, null); return cursor1; case MyStudyTableNumFlag://如果查询的是表中的确定id的记录 long id = ContentUris.parseId(uri);//ContentUris的使用。 Log.d(Constant.TAG, "ContentUris:" + id); SQLiteDatabase db2 = SqlManager.getInstance(getContext()).getWritableDatabase(); //查找id相匹配的数据。 String selectSql2 = "select * from " + Constant.TableName + " where _id = ?"; String[] args = {"" + id}; Cursor cursor2 = db2.rawQuery(selectSql2, args); return cursor2; } return null; } @Nullable @Override public String getType(Uri uri) { Log.d(Constant.TAG,"--MyContentProvider--getType--"); return null; } @Nullable @Override public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase db = SqlManager.getInstance(getContext()).getWritableDatabase(); db.insert(Constant.TableName,null,values); Log.d(Constant.TAG,"--MyContentProvider--insert--"); return uri; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { Log.d(Constant.TAG,"--MyContentProvider--delete--"); int matchId= sURIMatcher.match(uri); switch(matchId) { case MyStudyTableFlag:// SQLiteDatabase db1 = SqlManager.getInstance(getContext()).getWritableDatabase();// String selectSql1 = "select * from " + Constant.TableName; db1.delete(Constant.TableName, selection, selectionArgs); break; case MyStudyTableNumFlag: long id = ContentUris.parseId(uri);//ContentUris的使用。 Log.d(Constant.TAG, "ContentUris:" + id); SQLiteDatabase db2 = SqlManager.getInstance(getContext()).getWritableDatabase(); String[] args = {"" + id}; db2.delete(Constant.TableName, "_id = ?", args); break; } return 0; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { Log.d(Constant.TAG,"--MyContentProvider--update--"); int matchId= sURIMatcher.match(uri); switch(matchId) { case MyStudyTableFlag: SQLiteDatabase db1 = SqlManager.getInstance(getContext()).getWritableDatabase(); db1.update(Constant.TableName, values, selection, selectionArgs); break; case MyStudyTableNumFlag: long id = ContentUris.parseId(uri);//ContentUris的使用。 Log.d(Constant.TAG, "ContentUris:" + id); SQLiteDatabase db2 = SqlManager.getInstance(getContext()).getWritableDatabase(); String[] args = {"" + id}; db2.update(Constant.TableName, values,"_id = ?", args); break; } return 0; }}
第二步注册contentProvider:
<provider android:name=".contentprovider.MyContentProvider" android:authorities="com.czh.mycontentprovider.study" />
第三步外部应用增删改查
查找数据的代码:
String uriStr = "content://com.czh.mycontentprovider.study/"+Constant.TableName+"/4";String[] projection = {Constant._ID,Constant.NAME,Constant.AGE};String selection = "_id = ?";String[] selectionArgs = {"2"};Cursor cursor = getContentResolver().query(Uri.parse(uriStr),projection,selection,selectionArgs,null,null);CursorAdapter ca = new SqlAdapter(MainActivity.this, cursor);listView.setAdapter(ca);
插入数据的代码:
String uriStr = "content://com.czh.mycontentprovider.study"; ContentValues cv = new ContentValues(); cv.put("name","yyd插入测试"); cv.put("age",100); getContentResolver().insert(Uri.parse(uriStr), cv);
删除数据的代码:
String uriStr = "content://com.czh.mycontentprovider.study/"+Constant.TableName+"/10"; // Uri url, String where, String[] selectionArgs getContentResolver().delete(Uri.parse(uriStr),null,null);
更新数据的代码:
String uriStr = "content://com.czh.mycontentprovider.study/"+Constant.TableName+"/10";getContentResolver().delete(Uri.parse(uriStr),null,null);
4 contentprovider使用小结
外部应用操作步骤:
第一步获取ContentResolver
ContentResolver cr = getContentResolver();
第二步:
利用ContentResolver,结合uri进行增删改查。
主应用使用步骤:
第一步:继承contentprovider,重写它的方法
第二步:在注册contentprovider。
监听ContentProvider中数据的变化
步骤:
1.在ContentProvider类的insert\update\delete方法添加改变通知:
this.getContext().getContentResolver().notifyChange(URI,null);
2.在外部应用设置监听:
getContentResolver().registerContentObserver(Uri.parse("content://com.czh.mycontentprovider.study"),true,new PersonObserver(new Handler())); private class PersonObserver extends ContentObserver{//监听 public PersonObserver(Handler handler) { super(handler); } //当ContentProvier数据发生改变,则触发该函数 @Override public void onChange(boolean selfChange) { super.onChange(selfChange); Log.i("myapp", "数据改变"); } }
挺简单的,这里不过多讨论。
5 ContentProvider深入理解
讲到最后了,我们来讨论几个问题:
1. 在应用程序A里面怎么跨进程拿到ContentProvider的对象呢?2. ContentProvider实例对象是保存在哪里呢?3. ContentProvider的方法实现要注意线程安全吗?
这块还没研究透彻,后面补充。
6 参考文档
【1】Android开发手册
【2】内容提供程序
【3】ContentProvider浅析—写点你平时没注意到的
7 结尾
文章的结尾奉送上代码方便大家对照学习。
好了就讲到这里吧。希望对大家有所帮助!如果觉的我写的不错,就点个赞吧!
- android contentprovider简单讲解
- Android ContentProvider讲解
- android ContentProvider讲解
- Android ContentProvider简单实现
- Android ContentProvider简单使用
- Android ContentProvider 的简单使用
- Android Handler简单讲解
- android Sqlite简单讲解
- android service简单讲解
- Android四大组件之一ContentProvider 的详细讲解及使用
- Android自学笔记-12-ContentProvider简单例子
- Android开发笔记---contentProvider的简单了解
- android ContentProvider简单介绍及使用
- Android ContentProvider 完全解析及简单DEMO
- Android中ContentProvider的简单使用
- ContentProvider简单使用 -- Android学习之路
- Android ContentProvider 完全解析及简单DEMO
- Android ContentProvider 完全解析及简单DEMO
- 解决svn上传是可以过滤掉class文件
- HTML5 canvas元素初识
- 报错java.sql.SQLException: Subquery returns more than 1 row
- OC笔记(3)
- GCD入门(三): Dispatch Sources
- android contentprovider简单讲解
- 十分钟搞定pandas
- QFile
- SQLServer 修改表字段的长度
- Python爬虫入门学习--(向网页提交数据)
- 解读Flink中轻量级的异步快照机制--Flink 1.2 源码
- 从jvm的角度来看java的多线程
- oj1070
- Android ubuntu录制手机 GIF 视频