题记:这篇是对content provider的一个全局的认识篇,包括一些基本概念和用法,故而借用下大酒神的大菊观附体~
主要包括以下几个方面:
- provider执行原理以及相关的概念;
- 通过provider来存储数据;
- provider的三大类型,以及不同的试用情况;
- provider的工具类(contect class和mime类型)。
content provider主要是用来支持跨应用访问数据,如果只是本身应用程序使用数据,那么直接使用SQLiteDataBase就可以了。按我的理解是,content provider封装了一些和android底层数据的操作,向外提供了统一的接口。contentResolver又是什么呢?按我的理解是,建立在很多具体的content provider基础之上的一个工具类,同时封装实现了content provider的那些数据访问接口,统一了再上一层也就是客户端的调用。这样客户端只需要一种调用方式,而不需要管调用的是哪个应用的数据,这些跨进程的访问细节都被contentResolver给屏蔽掉了。那么这时候客户端调用数据需要有一个统一的调用方式,就是通过content URI来实现访问。content URI规定了访问数据的一个标准。同时,若要访问非数据库一类的资源,也可以通过MIME类型的表示来访问,只不过表现形式不一样而已。
一、provider执行原理已经相关概念
实际上,访问数据都是先通过contentResolver的相应方法,如查询时,contentResolver.query()方法,实际上,其内部调用的相关content provider的query()方法。一切需要通过content provider的操作,都可以通过contentResolver的相应操作来实现。
相关概念:
- content URI:资源标识符,用来访问指定content Provider的指定资源。形式如下
content://schema/resource
其中:content://为固定头部,shema为具体的content provider标识,resource为具体content provider提供的资源标识,如表名words;
- projection:查询时需要显示的列集合,为一字符串数组;
- selection:查询条件表达式字符串
- selectionArgs:用来匹配查询条件表达式中的?标识符,使得查询更加严谨,主要是为了防止SQL注入等恶意输入的情况;
- sortOrder:排序条件,和sql查询一样的排序
最终,其组合而成的还是一个SQL查询语句,查询到指定资源并返回。
二、provider存储数据
- 读取数据。
从content provider读取数据,首先需要相关被请求的content provider的读取权限,并且相关权限需要在AndroidManifest.xml中的user-permission节点中声明。
组织查询条件,定义好需要查询的列集合,查询条件等。query方法返回的是cursor对象,也称游标。若cursor为null或者query方法直接抛出异常,则表示query方法执行时异常;正常cursor不为空,其cursor.getCount()方法返回值大于等于0的。cursor对象可以自由的访问其包含的行和列对象,同时返回的数据类型不超过其支持的那几种:int ,long,float,double,blob。cursor能够根据查询目标更新而自动更新。
展示Cursor中的查询结果包括两种方式:
一是直接将Cursor对象当作参数传递到SimpleCursorAdapter对象中,展示在listView中。这时需要有_id一列。
二是直接读取Cursor对象中的值:
if (mCursor != null) { (mCursor.moveToNext()) { // Gets the value from the column. newWord = mCursor.getString(index); } } else { // Insert code here to report an error if the cursor is null or the provider threw an exception. }
- 写入数据。
写入包括以下三种类型的操作:
a).insert。
通过ContentValues对象的put方法,将相应字段的对应值放入该对象中。若要放入空值,使用putNull。
Uri mNewUri; ... // Defines an object to contain the new values to insert ContentValues mNewValues = new ContentValues(); /* * Sets the values of each column and inserts the word. The arguments to the "put" * method are "column name" and "value" */ mNewValues.put(UserDictionary.Words.APP_ID, "example.user"); mNewValues.put(UserDictionary.Words.LOCALE, "en_US"); mNewValues.put(UserDictionary.Words.WORD, "insert"); mNewValues.put(UserDictionary.Words.FREQUENCY, "100"); mNewUri = getContentResolver().insert( UserDictionary.Word.CONTENT_URI, // the user dictionary content URI mNewValues // the values to insert );
同时insert方法返回uri,指向新增加的一行,可以通过ContentUris.parseId(),获取该URI中表示的ID。
b).update。
通过ContentValues对象把要更新的字段写入其中,contentResolver.update()方法返回的是已更新的行数。
c).delete。
contentResolver.delete()方法返回的是已删除的行数。
三、访问Provider的三大方式
- 批量访问(batch access):通过ContentProviderOperation类型来创建批量操作,并且通过contentResolver.applyBatch()方法来实现;
- 通过intent来访问,适用于没有设定权限而又想访问其他应用的数据时。直接通过intent来访问,然后根据返回的uri再来获取对应的值;
- 异步加载数据,常用的有CursorLoader。
四、工具类
- 工具类实际是用来标识content provider所要控制的数据一个结构描述,如某张表下有哪些列,基本content uri字符串是什么等一些能够描述content provider里面的数据的。
- content provider URI返回值也可以包括两种MIME类型:标准的MIME和自定义的MIME。
标准的MIME如:text/html,前面的是类型,后面的是子类型。
自定义的MIME类型:
vnd.android.cursor.dir
vnd.android.cursor.item
还是蛮有意思的,和正常的content uri对比,详见SDK文档。
另外,本文中引用的代码片段来自SDK官方学习文档,转载请说明出处~~