这篇文章大体介绍一下ContentProvider提供方和使用方之间如何通过binder机制进行通信的。
下面是ContentProvider相关的类图关系:
ContentProvider接口类,继承于IInterface类。该类有两个很重要的子类:ContentProviderNative和ContentProviderProxy,分别为本地服务端和客户端的接口。
PATH:frameworks/base/core/java/android/content/ContentProviderNative.java
为Content客户端接口。Content使用方获得该接口后,就可以调用接口里的query/insert/delete/update函数进行内容的查询、插入、删除和更新。里面有个IBinder类型的变量mRemote,使用mRemote的transact方法就可以将具体的请求发给binder驱动,binder驱动会进一步将该请求转发给Content提供方。下面以ContentProviderProxy.query为例,看一下具体实现:
public Cursor query(String callingPkg, Uri url, String[] projection, String selection, String[] selectionArgs,
String sortOrder, ICancellationSignal cancellationSignal) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
// 将请求打包到Parcel中
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(callingPkg);
data.writeInt(length);
...
// 将请求包发送给binder驱动。注意这里的请求类型为:IContentProvider.QUERY_TRANSACTION
mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
// 将返回结果转化为Cursor类型
if (reply.readInt() != 0) {
BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
adaptor.initialize(d);
} else {
adaptor.close();
adaptor = null;
}
return adaptor; //返回结果
}
}
PATH:frameworks/base/core/java/android/content/ContentProviderNative.java
为Content本地服务端接口,里面有个方法为onTransact,该方法主要是处理来自Content客户端的请求,然后调用其子类Transport来具体实现query/insert/delete/update等具体的操作。下面看一下具体代码:
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
try {
switch (code) {
case QUERY_TRANSACTION:
{
... //解析请求包data
// 调用子类的query具体实现,即ContentProvider.Transport类。
Cursor cursor = query(callingPkg, url, projection, selection, selectionArgs,
sortOrder, cancellationSignal);
... //将处理结果放入返回包reply中
return true;
}
case GET_TYPE_TRANSACTION: //getType操作
{
...
}
case INSERT_TRANSACTION: //insert操作
{
...
}
case DELETE_TRANSACTION: //delete操作
{
...
}
case UPDATE_TRANSACTION: //update操作
{
...
}
...
}
}
...
}
PATH:frameworks/base/core/java/android/content/ContentProvider.java
该类是一个抽象类,所有的Provider都继承于该类。ContentProvider定义了query/insert/delete/update的接口形式,具体实现由其子类完成。
public abstract class ContentProvider implements ComponentCallbacks2 {
public abstract Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder);
public abstract Uri insert(Uri uri, ContentValues values);
public abstract int delete(Uri uri, String selection, String[] selectionArgs);
public abstract int update(Uri uri, ContentValues values, String selection, String[] selectionArgs);
...
}
ContentProvider中还有一个内部类:Transport,其继承于ContentProviderNative,该类里面实现了query/insert/delete/update方法,由ContentProviderNative.onTransact调用。但这些方法仍然不是最终的实现,还需要进一步调用具体的ContentProvider实现。
下面以Transport.query()为例,看一下具体代码:
class Transport extends ContentProviderNative {
public Cursor query(String callingPkg, Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
ICancellationSignal cancellationSignal) {
...
try {
// 由于ContentProvider是抽象类,因此进一步调用ContentProvider的子类的query方法。
return ContentProvider.this.query(
uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
} finally {
setCallingPackage(original);
}
}
...
}
这里就是系统中某一个ContentProvider的具体实现了,比如MediaProvider、SettingsProvider等。
这些类继承于ContentProvider类,因此必须要实现ContentProvider类中定义的query/insert/delete/update抽象方法。