简介
我们知道数据在Android系统是进程私有的,当我们需要跨越进程间传递数据时,ContentProvider就发挥了它的作用了。
ContentProvider是android系统中对外共享数据的,一个进程可以通过实现它的抽象接口就可以向其他应用进程共享其数据。
源码
//这是一个抽象类,通过实现它的接口来负责跨进程数据传递!
public abstract class ContentProvider implements ComponentCallbacks {
private Context mContext = null;
private int mMyUid;
private String mReadPermission; //读取权限
private String mWritePermission; //写入权限
private PathPermission[] mPathPermissions; //路径权限
private Transport mTransport = new Transport(); //传输端口
public ContentProvider() {
}
//构造
public ContentProvider(
Context context,
String readPermission,
String writePermission,
PathPermission[] pathPermissions) {
mContext = context;
mReadPermission = readPermission;
mWritePermission = writePermission;
mPathPermissions = pathPermissions;
}
// 返回一个实例
public static ContentProvider coerceToLocalContentProvider(
IContentProvider abstractInterface) {
if (abstractInterface instanceof Transport) {
return ((Transport)abstractInterface).getContentProvider();
}
return null;
}
//Binder对象远程处理
class Transport extends ContentProviderNative {
ContentProvider getContentProvider() {
return ContentProvider.this;
}
// 查询
public IBulkCursor bulkQuery(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
IContentObserver observer, CursorWindow window) {
enforceReadPermission(uri); //检查权限
Cursor cursor = ContentProvider.this.query(uri, projection,
selection, selectionArgs, sortOrder);
if (cursor == null) {
return null;
}
return new CursorToBulkCursorAdaptor(cursor, observer,
ContentProvider.this.getClass().getName(),
hasWritePermission(uri), window);
}
//查询
public Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder) {
enforceReadPermission(uri);
return ContentProvider.this.query(uri, projection, selection,
selectionArgs, sortOrder);
}
//获得类型
public String getType(Uri uri) {
return ContentProvider.this.getType(uri);
}
//插入
public Uri insert(Uri uri, ContentValues initialValues) {
enforceWritePermission(uri);
return ContentProvider.this.insert(uri, initialValues);
}
//插入
public int bulkInsert(Uri uri, ContentValues[] initialValues) {
enforceWritePermission(uri);
return ContentProvider.this.bulkInsert(uri, initialValues);
}
//匹配
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
for (ContentProviderOperation operation : operations) {
if (operation.isReadOperation()) {
enforceReadPermission(operation.getUri());
}
if (operation.isWriteOperation()) {
enforceWritePermission(operation.getUri());
}
}
return ContentProvider.this.applyBatch(operations);
}
//删除
public int delete(Uri uri, String selection, String[] selectionArgs) {
enforceWritePermission(uri);
return ContentProvider.this.delete(uri, selection, selectionArgs);
}
//更新
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
enforceWritePermission(uri);
return ContentProvider.this.update(uri, values, selection, selectionArgs);
}
//打开文件 获得文件描述符
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
else enforceReadPermission(uri);
return ContentProvider.this.openFile(uri, mode);
}
//打开文件 获得文件描述符
public AssetFileDescriptor openAssetFile(Uri uri, String mode)
throws FileNotFoundException {
if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
else enforceReadPermission(uri);
return ContentProvider.this.openAssetFile(uri, mode);
}
//调用方法
public Bundle call(String method, String request, Bundle args) {
return ContentProvider.this.call(method, request, args);
}
//是否具有读取权限
private void enforceReadPermission(Uri uri) {
final int uid = Binder.getCallingUid();
if (uid == mMyUid) {
return;
}
final Context context = getContext();
final String rperm = getReadPermission();
final int pid = Binder.getCallingPid();
if (rperm == null
|| context.checkPermission(rperm, pid, uid)
== PackageManager.PERMISSION_GRANTED) {
return;
}
PathPermission[] pps = getPathPermissions();
if (pps != null) {
final String path = uri.getPath();
int i = pps.length;
while (i > 0) {
i--;
final PathPermission pp = pps[i];
final String pprperm = pp.getReadPermission();
if (pprperm != null && pp.match(path)) {
if (context.checkPermission(pprperm, pid, uid)
== PackageManager.PERMISSION_GRANTED) {
return;
}
}
}
}
if (context.checkUriPermission(uri, pid, uid,
Intent.FLAG_GRANT_READ_URI_PERMISSION)
== PackageManager.PERMISSION_GRANTED) {
return;
}
String msg = "Permission Denial: reading "
+ ContentProvider.this.getClass().getName()
+ " uri " + uri + " from pid=" + Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
+ " requires " + rperm;
throw new SecurityException(msg);
}
//是否具有写入权限
private boolean hasWritePermission(Uri uri) {
final int uid = Binder.getCallingUid();
if (uid == mMyUid) {
return true;
}
final Context context = getContext();
final String wperm = getWritePermission();
final int pid = Binder.getCallingPid();
if (wperm == null
|| context.checkPermission(wperm, pid, uid)
== PackageManager.PERMISSION_GRANTED) {
return true;
}
PathPermission[] pps = getPathPermissions();
if (pps != null) {
final String path = uri.getPath();
int i = pps.length;
while (i > 0) {
i--;
final PathPermission pp = pps[i];
final String ppwperm = pp.getWritePermission();
if (ppwperm != null && pp.match(path)) {
if (context.checkPermission(ppwperm, pid, uid)
== PackageManager.PERMISSION_GRANTED) {
return true;
}
}
}
}
if (context.checkUriPermission(uri, pid, uid,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
== PackageManager.PERMISSION_GRANTED) {
return true;
}
return false;
}
//是否具有执行写入权限
private void enforceWritePermission(Uri uri) {
if (hasWritePermission(uri)) {
return;
}
String msg = "Permission Denial: writing "
+ ContentProvider.this.getClass().getName()
+ " uri " + uri + " from pid=" + Binder.getCallingPid()
+ ", uid=" + Binder.getCallingUid()
+ " requires " + getWritePermission();
throw new SecurityException(msg);
}
}
// 获得上下文
public final Context getContext() {
return mContext;
}
//设置读取权限
protected final void setReadPermission(String permission) {
mReadPermission = permission;
}
// 返回读取权限
public final String getReadPermission() {
return mReadPermission;
}
//设置写入权限
protected final void setWritePermission(String permission) {
mWritePermission = permission;
}
//返回写入权限
public final String getWritePermission() {
return mWritePermission;
}
//更改路径的权限
protected final void setPathPermissions(PathPermission[] permissions) {
mPathPermissions = permissions;
}
//基于路径的权限(读取和写入)
public final PathPermission[] getPathPermissions() {
return mPathPermissions;
}
//创建 抽象方法 有实体类实现
public abstract boolean onCreate();
//配置发生改变
public void onConfigurationChanged(Configuration newConfig) {
}
//内存过低
public void onLowMemory() {
}
//查询 抽象
public abstract Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder);
//MIME类型的数据
public abstract String getType(Uri uri);
//插入数据
public abstract Uri insert(Uri uri, ContentValues values);
//插入数据
public int bulkInsert(Uri uri, ContentValues[] values) {
int numValues = values.length;
for (int i = 0; i < numValues; i++) {
insert(uri, values[i]);
}
return numValues;
}
//删除
public abstract int delete(Uri uri, String selection, String[] selectionArgs);
//更新
public abstract int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs);
//打开文件
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
throw new FileNotFoundException("No files supported by provider at "
+ uri);
}
//打开文件
public AssetFileDescriptor openAssetFile(Uri uri, String mode)
throws FileNotFoundException {
ParcelFileDescriptor fd = openFile(uri, mode);
return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null;
}
//打开文件
protected final ParcelFileDescriptor openFileHelper(Uri uri,
String mode) throws FileNotFoundException {
Cursor c = query(uri, new String[]{"_data"}, null, null, null);
int count = (c != null) ? c.getCount() : 0;
if (count != 1) {
//没有 则抛出异常
if (c != null) {
c.close();
}
if (count == 0) {
throw new FileNotFoundException("No entry for " + uri);
}
throw new FileNotFoundException("Multiple items at " + uri);
}
c.moveToFirst();
int i = c.getColumnIndex("_data");
String path = (i >= 0 ? c.getString(i) : null);
c.close();
if (path == null) {
throw new FileNotFoundException("Column _data not found.");
}
int modeBits = ContentResolver.modeToMode(uri, mode);
return ParcelFileDescriptor.open(new File(path), modeBits);
}
//是否临时数据
protected boolean isTemporary() {
return false;
}
//返回通讯对象
public IContentProvider getIContentProvider() {
return mTransport;
}
//匹配信息
public void attachInfo(Context context, ProviderInfo info) {
// 执行一次
if (mContext == null) {
mContext = context;
mMyUid = Process.myUid();
if (info != null) {
setReadPermission(info.readPermission);
setWritePermission(info.writePermission);
setPathPermissions(info.pathPermissions);
}
ContentProvider.this.onCreate();
}
}
// 匹配
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
final int numOperations = operations.size();
final ContentProviderResult[] results = new ContentProviderResult[numOperations];
for (int i = 0; i < numOperations; i++) {
results[i] = operations.get(i).apply(this, results, i);
}
return results;
}
//构造成Bundle数据
public Bundle call(String method, String request, Bundle args) {
return null;
}
}
App设计
一个Android应用程序设计的一般方法,如下图所示:
在这个架构中, 数据层采用数据库、文件或者网络来保存数据,数据访问层使用Content Provider来实现,而业务层就通过一些APP来实现。
总结
1、进程间是不能直接读写数据文件的,如果它们想共享数据的话,可以通过ContentProvider组件来实现。
2、ContentProvider组件主要通过Binder进程间通信机制和匿名共享内存机制来实现的。
3、ContentProvider组件中的数据更新通知机制和Android系统中的广播(Broadcast)通知机制相似,都是一种消息发布和订阅的事件驱动模型。