概述
ContentProvider(内容提供者)是Android中的四大组件之一。主要用于程序间数据的共享(IPC的一种).
它提供了一套完整的机制,允许一个程序访问另一个应用程序,并且保证数据的安全性.
我们知道在Android中常见的数据存储方式有sharedpreferences,文件和数据库等,但是数据的访问方式会因为存储方式的不同而不同.
而且这些数据只能在应用内使用,而ContentProvider允许在程序间实现数据的共享,并且提供好了统一了数据的访问方式.
ContentResolver
访问内容提供器中共享的数据,需要借助通过ContentResolver,其中context.getContentResolver()方法可以获取到ContentResolver实例,
ContentResolver提供了一系列方法来对数据进行CRUD操作.
URI
统一资源标识符,结构和HTTP形式的URL是一样的.
代表了要操作的数据,每一个ContentProvider都拥有一个公共的URI,不能重复
<prefix>://<authority>/<data_type>/<id>
其中,<prefix>
的值永远为content
,不可更改
<authority>
唯一标识符,用来定位ContentProvider
,一般为自定义Provider的全路径名,保证唯一
<data_type>/<id>
代表资源路径,如/person/2
代表person表中id为2的数据
MIME
用于指定某个扩展名的文件用一种应用程序来打开,如application/pdf,text/css等,Android中的MIME类型有两种
* 多条记录
vnd.android.cursor.dir/vnd.xxx
* 单条记录
vnd.android.cursor.item/vnd.xxx
其中包含类型和子类型,/前面的类型是Android定义好的,不可更改,子类型中vnd.后面的可以随意指定.在使用Intent时,会用到MIME这玩意,根据Mimetype打开符合条件的活动。
自定义Contentprovider
- 继承ContentProvider,并重写其中的一些方法,
其中OnCreate()方法在Provider初始化的时候执行
getType(URI uri)用于返回某一URI对应的MIME类型,运行在Binder线程池中
还有其他一些操作CRUD操作,运行在Binder线程池中
- UriMatcher
用于冠关联Provider中的自定义URI和URI_CODE,通过addURI()将相应的Path和Code联系起来,通过match(uri)得到相应的CODE.
//为外部程序准备好一个所有地址匹配集合
static{
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(PROVIDER_NAME, "students", STUDENTS);
uriMatcher.addURI(PROVIDER_NAME, "students/#", STUDENT_ID);
}
// 取得数据的类型,此方法会在系统进行URI的MIME过滤时被调用。
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)){
/**
* Get all student records
*/
case STUDENTS:
return "vnd.android.cursor.dir/vnd.example.students";
/**
* Get a particular student
*/
case STUDENT_ID:
return "vnd.android.cursor.item/vnd.example.students";
default:
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
}
- ContentUris
用于操作Uri路径后面的ID部分
其中withAppendedId(uri, id)用于为路径加上ID部分:
Uri uri = Uri.parse("content://com.example.provider.College/students")
Uri resultUri = ContentUris.withAppendedId(uri, 10);
//生成后的Uri为:content://com.example.provider.College/students/10
parseId(uri)方法用于从路径中获取ID部分:
Uri uri = Uri.parse("content://com.example.provider.College/students/10 ")
long personid = ContentUris.parseId(uri);//获取的结果为:10
- 配置清单文件
<provider
android:authorities="com.bobomee.android.contentproviderdemo"
android:name=".BookContentProvider"/>
监听ContentProvider变化
如果ContentProvider的访问者需要知道ContentProvider中的数据发生变化,可以在ContentProvider发生数据变化时调用getContentResolver().notifyChange(uri, null)来通知注册在此URI上的访问者,
Uri insertUri = Uri.withAppendedPath(uri, "/" + rowId);
Log.i(TAG, "insertUri:"+insertUri.toString());
//发出数据变化通知(book表的数据发生变化)
getContext().getContentResolver().notifyChange(uri, null);
return insertUri;
Loader
Loader是3.0引入的API,可以优雅的实现异步,常用于Activity和Fragment中异步加载数据.防止引起内存泄漏,不仅如此,Loader还实时监听数据源,在配置发生改变后不会重新查询等.
Loader是一个抽象类,实际使用时,我们使用的是AsyncTaskLoader与CursorLoader,使用Loader,需要了解LoaderManager及LoaderCallbacks的API.关于Loader的详细介绍Android之Loader介绍
其中CursorLoader和Contentprovider一起使用再合适不过了
最后使用Contentprovider的小Demo:ProviderDemo
参考文章:
ContentProvider和Uri详解
Android - Content Providers
我是这样理解Android开发中的contentprovider的
Android开发教程:Android数据储存之ContentProvider
android ContentProvider使用详解
Android之Loader介绍
Android中Loader及LoaderManager的使用(附源码下载)