Android 开发的四大组件分别是:活动(activity),用于表现功能;服务(service),后台运行服务,不提供界面呈现;广播接受者(Broadcast Receive),用于接收广播;内容提供者(Content Provider),支持多个应用中存储和读取数据,相当于数据库。
一 概述
1.1 什么是ContentProvider
ContentProvider即内容提供者,是Android四大组件之一,是一种共享型组件。
ContentProvider为不同的应用之间实现数据共享,提供统一的接口,也就是说ContentProvider可以实现进程间的数据共享,实现跨进程通信。
ContentProvider通过Uri来唯一标识ContentProvider & 其中的数据,通过ContentProvider.getType(uri)来返回MIME类型数据。通过ContentResolver的增删改查方法实现对共享数据的操作,还可以通过注册ContentObserver来监听数据是否发生了变化来对应的刷新界面。
注意:ContentProvider 的作用不是实现进程间通信,它只是为进程间通信提供了一套统一接口,真正实现进程间通信的是底层的 Binder 机制。
优点:使用 ContentProvider 允许应用透明地将数据开放给其它应用,无论底层数据采用何种实现方式(网络、内存、文件或数据库),外界对于数据的访问方式都是统一的 & 固定的。外界只关心采用 CURD 来访问 ContentProvider 的数据,至于其内部数据的实现是采用文件存储还是数据库存储,外界是不感知的。
1.2 统一资源标识符(URI)
统一资源标识符(Uniform Resource Indentifier)的作用是 唯一标识 ContentProvider 的数据。在通过 ContentResolver 解析数据时,URI 是必要的参数。
URI 遵循固定的格式,一共分为四个部分:schema://authority/path/id
元素 | 描述 |
---|---|
schema(方案) | URI的前缀,固定为 content:// |
authority(权威) | 标识 ContentProvider 的唯一字符串,对应于注册时指定的 android:authority 属性 |
path(路径) | ContentProvider中数据表的表名。标识 authority 数据的某些子集 |
id(记录 id) | 标识 path 子集中的某个记录(不指定是标识全部记录)数据表中数据的标识 |
1.3 MIME数据类型
MIME用于指定某个扩展名的文件用某种应用程序打开,如指定.html文件采用text应用程序打开,指定.pdf文件用flash应用程序打开。
一个 MIME 类型分为「主类型」+「子类型」,例如 .html 文件对应的 MIME 类型为 text/html,其中 text 为主类型,html 为子类型。
在 ContentProvider 中,通过 getType(Uri) 方法来确定 URI 对应的 MIME 类型,返回值可以返回 标准 MIME 类型或者自定义 MIME 类型,这是一个抽象方法,需要由子类实现:
public abstract String getType(Uri uri);
标准 MIME 类型
标准 MIME 类型中常见的主类型有:
声音:audio
视频:video
图像:image
文本:text
对应的 MIMIE 类型举例:
扩展名 | MIME |
---|---|
.html | text/html |
.txt | text/plain |
.png | image/png |
.jpeg | image/jpeg |
二 ContentProvider核心类
Android提供了3个用于辅助ContentProvider的工具类:ContentUris、UriMatcher和ContentObserver
2.1 ContentUris
ContentUris 是 Uri 的工具类,在 ContentUris 的文档注释中主要描述了 ContentProvider URI 所遵循的格式,此外 ContentUris 还提供了三个工具方法:
1、从 Uri 中解析主键 id
public static long parseId(Uri contentUri) {
String last = contentUri.getLastPathSegment();
return last == null ? -1 : Long.parseLong(last);
}
2、向 Uri 追加一个 id
public static Uri.Builder appendId(Uri.Builder builder, long id) {
return builder.appendEncodedPath(String.valueOf(id));
}
3、向 Uri 追加一个 id
public static Uri withAppendedId(Uri contentUri, long id) {
return appendId(contentUri.buildUpon(), id).build();
}
2.2 UriMatcher
UriMatcher类是一个工具类,帮助匹配ContentProvider中的Uri。只提供了两个方法——addURI和match方法。
private final static String AUTHORITY = "com.android.peter.provider";
private final static int STUDENT_URI_CODE = 0;
private final static UriMatcher sUriMatcher;
static {
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
//把Uri和Uri_Code相关联
sUriMatcher.addURI(AUTHORITY,"student",STUDENT_URI_CODE);
}
//通过match方法能够根据传递的uri匹配到对应的Uri_Code
int uriType = sUriMatcher.match(uri);
2.3 ContentObserver
ContentObserver内容观察者,用于观察Uri引起ContentProvider中数据变化 & 通知外界(即访问该数据访问者)。当ContentProvider中的数据发生变化时,就会触发该ContentObserver类。其具体使用如下:
// 步骤1:注册内容观察者ContentObserver
getContentResolver().registerContentObserver(uri);
// 通过ContentResolver类进行注册,并指定需要观察的URI
// 步骤2:当该URI的ContentProvider数据发生变化时,通知外界(即访问该ContentProvider数据的访问者)
public class UserContentProvider extends ContentProvider {
public Uri insert(Uri uri, ContentValues values) {
db.insert("user", "userid", values);
getContext().getContentResolver().notifyChange(uri, null);
// 通知访问者
}
}
// 步骤3:解除观察者
getContentResolver().unregisterContentObserver(uri);
// 同样需要通过ContentResolver类进行解除
2.4 ContentResolver类
用于管理不同的ContentProvider间的操作,即通过URI即可操作不同的ContentProvider中的数据,外部进程通过ContentResolver类从而与ContentProvider类进行交互。
一般来说,一款应用要使用多个ContentProvider,若需要了解每个ContentProvider的不同实现从而完成数据交互,操作成本高、难度大。因此需要在ContentProvider上多加一个ContentResolver来进行统一管理。
ContentResolver类提供了与ContentProvider类相同名 & 作用的4个方法:
// 外部进程向 ContentProvider 中添加数据
public Uri insert(Uri uri, ContentValues values)
// 外部进程删除 ContentProvider 中的数据
public int delete(Uri uri, String selection, String[] selectionArgs)
// 外部进程更新 ContentProvider 中的数据
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
// 外部应用 获取 ContentProvider 中的数据
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
三 ContentProvider的使用
3.1 主要方法
ContentProvider 使用表格的形式管理数据,对外暴露四个操作方法,分别是:添加、删除、更新、查询(insert、delete、update、query):
添加数据(Binder 线程)
public abstract Uri insert(Uri uri, ContentValues values);
删除数据(Binder 线程)
public abstract int delete(Uri uri, String selection, String[] selectionArgs);
更新数据(Binder 线程)
public abstract int update(Uri uri, ContentValues values, String selection, String[] selectionArgs);
查询数据(Binder 线程)
public abstract Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);
除了 4 个核心方法外,ContentProvider 还有其他比较重要的方法,例如:
启动回调(主线程)
public abstract boolean onCreate();
返回 Uri 对应的 MIME 类型(调用线程)
public abstract String getType(Uri uri);
需要注意:四个核心方法执行在 ContentProvider 注册进程,并在 Binder 线程池中执行,而不是主线程。考虑到存在多线程并发访问,为了保证数据安全在实现 ContentProvider 是还需要保证线程同步。
3.2 ContentProvider的使用
ContentProvider 的使用可以简单的归纳为以下几步:
1、创建自己的数据列表;
2、自定义ContentProvider实现相关的抽象方法;
3、在AndroidManifest中声明provider以及定义相关访问权限;
4 、通过ContentResolver根据URI进行增删改查。