1 背景
在 Android 官方指出的 Android的数据存储方式总共5种,分别为:
- Shard Prederences;网络存储;文件存储;外储存储;SQLite
一般这些存储只是在单独的一个应用程序之中达到一个数据的共享,有时需要操作其他应用程序的一些数据。例如,我们需要操作系统里的媒体库、通讯录等,这是就可以通过 ContentProvider 来满足我们的需求。
当采用文件方式对外共享数据,需要进行文件操作读写数据;当采用 sharepreferences共享数据,需要其相应的 api读写数据。而采用 ContentProvider 共享数据,是统一了数据访问方式。
2 App间的数据获取
ContentProvider:组织应用的数据;向其他应用提供数据
ContentResolver:获取ContentProvider提供的数据;添加/删除/查询/修改数据等
- Android 是如何实现应用程序之间数据共享的?
一个应用程序可以将自己的数据完全暴露,但外界看不到也不用看到。只需要有一套标准及统一的结构,来获取该应用里的数据和资源,例如:添加(insert)、删除(delete)、查询(query)、修改(update),当然要获得相应的权限。- 如何将应用的数据暴露出去?
Android 提供了 ContentProvider,一个程序可以通过实现一个 Content Provider 的抽象接口将自己的数据完全暴露出来,以类似数据库中表的方式。ContentProvider 存储和检索数据,通过它可以让所有的应用程序访问到,这也是应用程序之间唯一共享数据的方式。方式:创建一个属于自己的 Content provider、或者将自己的数据添加到一个已经存在的 Content provider中(前提是在具有相同的数据类型,并且有写入Content provider 的权限)- 如何通过一套标准及统一接口获取到应用暴露的数据?
Android 提供了 ContentResolver,外界的应用可以通过 ContentResolver接口访问 ContentProvider提供的数据。
ContentResolver 通过 Uri来查询 ContentProvider 中提供的数据。 Uri在 这里 有做介绍。我们需要知道获取的数据段的名称、以及此数据段的数据类型。
3 在Manifecst中注册ContentResolver
使用ContentProvider来共享数据时,必须在AndroidManifest.xml文件中进行注册,类似于这样
<provider android:authorities="list" android:enabled=["true" | "false"] android:exported=["true" | "false"] android:grantUriPermissions=["true" | "false"] android:icon="drawable resource" android:initOrder="integer" android:label="string resource" android:multiprocess=["true" | "false"] android:name="string" android:permission="string" android:process="string" android:readPermission="string" android:syncable=["true" | "false"] android:writePermission="string"> . . . </provider>
Android系统通过 content:URI 的授权部分来识别内容提示器。
例如,假设下列的 Uri 要传递给 ContentResolve.query() 方法:
content://com.example.project.healthcareprovider/nurses/rn
- content:表示数据是属于内容提供器
授权(com.example.project.healthcareprovider):标识这一个具体的提供器。因此授权必须是唯一的。通常授权是一个完整的 ContentProvider 子类的名称。Uri 的路径部分被内容提供器用来标识集体的数据子集,但那些路径没有声明在清单文件中。
脚本详细内容这里不做介绍
4 ContentResolver 的接口
与数据库的操作基本一样
- 【添加】
返回值:final Uri
函数声明:insert(Uri url, ContentValues values)- 【删除】
返回值:final int
函数声明:insert(Uri url, ContentValues values)- 【查询】
Query the given URI, returning a Cursor over the result set
返回值:final Cursor
函数声明:query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)- 【修改】
返回值:final int
函数声明:update(Uri uri, ContentValues values, String where, String[] selectionArgs)
4 Cursor
ContentResolver 的查询操作,返回的为 Cursor。
Cursor 默认是行的集合。查询出来的cursor的初始位置是指向第一条记录的前一个位置的
- cursor.moveToFirst() 指向查询结果的第一个位置。
一般通过判断cursor.moveToFirst()的值为true或false来确定查询结果是否为空。- cursor.moveToNext() 用来做循环的,一般这样来用:while(cursor.moveToNext()){ }
- cursor.moveToPrevious() 指向当前记录的上一个记录,是和moveToNext相对应的;
- cursor.moveToLast() 指向查询结果的最后一条记录
下面代表的是一个cursor对象。
当我们是用 query 方法查询到的指向的是 cursor对象第一行的前一行,在该图中就是空行。然后使用 cursor.move.ToNext() 方法,指向了 cursor的第一行数据。每行中存在很多列数据,且数据类型不一定相同。
- getColumnIndex(String columnName) 获取该列数据的index(索引)。返回值为int。
- cursor.getxxx(int columnIdx) 获取 cursor 某一行 columnIdx列的数据内容,类型为xxx。比如cursor.getString() 获取该行数据中类型为string的数据。
例:
// get photo from Uri public static String get_path_from_URI(Context context) { String result; Cursor cursor = context.getContentResolver().query(uri, null, null, null, null); if (cursor != null) { cursor.moveToFirst(); int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); result = cursor.getString(idx); cursor.close(); } else { result = null; } return result; }
使用cursor可以很方便的处理查询结果以便得到想要的数据。