1, 相关类图
主要文件路径: packages/providers/ContactsProvider
frameworks/base
ContentProvider是四大组件之一,是android中专门用于不同应用进程间进行数据共享的方式。由此, ContentProvider必然涉及
到发起进程,AMS(AMS服务所在进程),目标进程(也就是真正实现增删改查的ContentProvider所在的进程)三个进程之间的通信。
目标ContentProvider至少有5个方法,其中onceate运行于主线程中,其他四个增删改查方法都由外界回调并且运行在Binder线程池中。
Android系统中那么多的数据库,那么根据什么来区分呢?或者说发起进程如何找到对应的数据库呢?以下都以联系人数据库来进行说明。
<provider android:name="ContactsProvider2"
android:authorities="contacts;com.android.contacts"
android:label="@string/provider_label"
android:multiprocess="false" // 是否可以在其他进程中创建
android:exported="true"
android:grantUriPermissions="true"
android:readPermission="android.permission.READ_CONTACTS" // 读权限
android:writePermission="android.permission.WRITE_CONTACTS">// 写权限
其中android:authorities 是ContentProvider的唯一标识,就像每个人的身份证一样,通过authorities就可以找到对应的数据库,在本例中,
如果发起端进行中的URI中包含contacts或者com.android.contacts 就可以找到ContactsProvider2数据库了。
ContentResolver相关类图如下,
ContentProvider相关类图
SQLiteDatabase相关类图
一般调用数据库的查询方法如下,
ContentResolver resolver = getContentResolver();
Cursor phoneCursor = resolver.query(Phone.CONTENT_URI,•••
首先获取的是ContentResolver对象, getContentResolver调用流程图如下,
在客户端,在增删改查之前,首先都会调用getContentResolver方法,
public ContentResolver getContentResolver() {
return mContentResolver;
}
在ContextImpl的构造函数中,
mContentResolver = new ApplicationContentResolver(this, mainThread, user);
可以看到, mContentResolver是一个ApplicationContentResolver对象, 是ContextImpl的一个内部类,并且继承自ContentResolver。
这些流程都运行于发起端进程。ApplicationContentResolver定义如下,
private static final class ApplicationContentResolver extends ContentResolver {
调用getContentResolver方法获取的并不是ContentProvider对象,而是ContentResolver对象, ContentResolver就像中间代理,
app直接和ContentResolver交互,然后ContentResolver和ContentProvider交互。
2,获取ContentProvider
在ContentProvider的四个主要方法,增删改查,
public final Uri insert(Uri url, ContentValues values){}
public final int delete(Uri url, String where, String[] selectionArgs){}
public final int update(Uri uri, ContentValues values, String where, String[] selectionArgs) {}
public final Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {}
在ContentResolver的这四个方法中首先都会调用acquireProvider方法获取IcontentProvider对象。
在insert/delete/update三个方法调用acquireProvider方法如下,
IContentProvider provider = acquireProvider(uri);
在query方法调用acquireProvider方法如下,
stableProvider = acquireProvider(uri);
传入的唯一参数是Uri对象。
实际上,调用acquireProvider方法才是获取目标ContentProvider的ContentProvider对象。
ContentResolver的acquireProvider方法调用流程图如下,
ContentResolver的acquireProvider方法如下,
public final IContentProvider acquireProvider(Uri uri) {
if (!SCHEME_CONTENT.equals(uri.getScheme())) {//类型检查
return null;
}
final String auth = uri.getAuthority();//获取auth
if (auth != null) {
return acquireProvider(mContext, auth);
}
return null;
}
ContentResolver的这个acquireProvider方法为抽象方法,具体的在子类ApplicationContentResolver中实现,
ContextImpl的内部类ApplicationContentResolver的acquireProvider方法如下,
protected IContentProvider acquireProvider(Context context, String auth) {
return mMainThread.acquireProvider(context, ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), true);
}
mMainThread对象是指客户端也就是app的ActivityThread对象,
ActivityThread的acquireProvider方法逻辑如下,
1,目标ContentProvider的ContentProvider对象已启动,直接从mProviderMap变量中获取并返回,
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
return provider;
}
2,如果未启动,跨进程获取IactivityManager的内部类ContentProviderHolder对象,
IActivityManager.ContentProviderHolder holder = null;
try {
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
}
ActivityManagerNative的getDefault方法会获取AMS在客户端的代理对象,因此最后会调用AMS的getContentProvider方法。
3,然后利用ContentProviderHolder对象调用installProvider方法获取IcontentProvider对象,
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;