ContentProvider 源码分析---之一

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;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值