Android组件 ContentProvider
1.什么是ContentProvider
ContentProvider,即内容提供者,是Android四大组件之一。底层采用Android中的binder机制,以uri的形式在进程间进行搬运,传递数据&实现进程间通信。
2.URI
定义:Uniform Resource Identifier ,统一资源标识符
格式:
主题名 | 标识符 | 资源路径 | |
---|---|---|---|
URI= | content:// | com.example.test/ | User/1 |
URI前缀,表示ContentProvider使用的协议由Android规定 | ContentProvider的唯一标识符,一般为完整的类名(包.类名) | 可以动态访问的资源路径,上述为数据库中User表里id为1的数据。 |
3.ContentProvider类
3.1 在AndroidManifest.xml注册
<provider
android:authorities="com.example.test/User/1" // 指定URI
android:name=".test" //指定类名
android:exported="true"></provider>
属性exported指定是否对外暴露数据,只有为true时,其他应用才可以访问该应用的数据;
3.2 方法
public boolean onCreate()
该方法在ContentProvider创建后或其他应用程序第一次访问ContentProvide时,被系统创建出来,并立即回调该onCreate方法
public Uri insert(Uri uri, ContentValues values)
根据URI,外部进程向ContentProvider传入values对应数据
public int delete(Uri uri, String selection, String[] selectionArgs)
根据URI,外部进程删除ContentProvider中selection条件匹配的数据
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
根据URI,外部进程更新ContentProvider中selection条件匹配的数据
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
根据URI,外部进程获取ContentProvider中selection条件匹配的数据
query()方法参数 | 对应sql部分 | 描述 |
---|---|---|
Uri uri | from table_name | 指定应用程序和表名 |
String[] projection | select column1 | 指定查询的表名 |
String selection | where column=value | 指定where的约束条件 |
String[] selectionArgs | - | 为where中的占位符提供具体的值 |
String sortOrder | order by column1 | 指定查询结果的排序方式 |
以上四种方法由外部进程调用,并运行在ContentProvider进程的Binder线程池中(不是主线程)若ContentProvider使用多个SQLite存储数据或使用内存存储数据,需要线程同步
public String getType(Uri uri)
返回当前 Url 所代表数据的MIME类型
3.3 MIME类型
定义:MIME:全称Multipurpose Internet Mail Extensions,多功能Internet邮件扩充
格式:type/subtype
MIME的结构为类型+子类型,两个字符串中间用’/’分隔而成,不允许空格存在。
类型 | 描述 |
---|---|
text | 普通文件 |
image | 图片文件,不包括视频,但包括动态图片(GIF) |
audio | 音频文件 |
video | 视频文件 |
applicable | 应用程序文件 |
4.ContentResolver类
4.1 ContentResolver作用
ContentProvider类并不会直接与外部进程交互,而是通过ContentResolver 类,ContentResolver用于统一管理不同 ContentProvider间的操作。
4.2 获取ContentResolver
使用ContentResolver前,需要先获取ContentResolver
通过调用Content的 getContentResolver() 方法获取 ContentResolver对象实例,获取对象后根据Uri对数据进行CRUD操作。
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://com.example.databasetest.provider/book");
Cursor cursor = resolver.query(uri, null, null, null, null);
4.3 方法
ContentResolver 类提供了与ContentProvider类相同名字的4个方法:
public Uri insert(Uri uri, ContentValues values)
根据URI,外部进程向ContentProvider传入values对应数据
public int delete(Uri uri, String selection, String[] selectionArgs)
根据URI,外部进程删除ContentProvider中selection条件匹配的数据
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
根据URI,外部进程更新ContentProvider中selection条件匹配的数据
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
根据URI,外部进程获取ContentProvider中selection条件匹配的数据
5.辅助ContentProvide的工具类
5.1 ContentUris类
5.1.1 withAppendedId
作用:向URI追加一个id
Uri uri = Uri.parse("content://com.example.test/User")
Uri resultUri = ContentUris.withAppendedId(uri, 3);
最终生成后的Uri为:content://com.example.test/User/3
5.1.2 parseId
作用:从URL中获取ID
Uri uri = Uri.parse("content://com.example.test/User/3")
long personid = ContentUris.parseId(uri);
获取的结果为:3
5.2 UriMatcher类
该类主要是对传入的 Uri 进行匹配,向UriMatcher注册Uri,参数code 是该Uri对应的标识码,根据标识码匹配数据库。
5.2.1 初始化UriMatcher对象
UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
// 初始化不匹配任何东西
5.2.2 在ContentProvider 中注册URI(addURI())
int URI_CODE_a = 1;
int URI_CODE_b = 2;
matcher.addURI("com.example.test", "user1", URI_CODE_a);
matcher.addURI("com.example.test", "user2", URI_CODE_b);
5.2.3 根据URI 匹配 URI_CODE,从而匹配ContentProvider中相应的资源(match())
@Override
public String getType(Uri uri) {
Uri uri = Uri.parse(" content://com.example.test/User1");
switch(matcher.match(uri)){
case URI_CODE_a:
return tableNameUser1;
case URI_CODE_b:
return tableNameUser2;
}
}
5.3 ContentObserver类
ContentObserver:内容观察者,目的是观察(捕捉)特定Uri引起的数据库的变化,继而做一些相应的处理。当ContentObserver所观察的Uri发生变化时,便会触发它。
观察特定URI的步骤如下:
(1)创建特定的ContentObserver子类,必须重载父类构造方法,必须重载onChange()方法去处理回调后的功能实现
(2) 利用context.getContentResolover()获得ContentResolove对象,接着调用 registerContentObserver()方法去注册内容观察者
getContentResolver().registerContentObserver(uri);
(3) 由于ContentObserver的生命周期不同步于Activity和Service等,因此不需要时,需要手动的调用 unregisterContentObserver()去取消注册。
getContentResolver().unregisterContentObserver(uri);