您的位置:首页 > 移动开发 > Android开发

浅析Android四大组件之一:ContentProvider 内容提供者 源码

2017-04-01 20:13 579 查看
今天在写代码的时候,发现我们用下面的这行代码就能够调用ContentProvider下面的insert方法,

Uri uri=getContentResolver().insert(MyContentProvider.uri,contentValues);


非常不理解,于是就去看源代码,也算是大概了解了工作原理。没有追到系统层,只是在应用层,所以只是简单的介绍,想要非常详细的解析,可以建议看下这篇博客,写的非常的好下面给处传送门:

http://blog.csdn.net/u010961631/article/details/14227421

由于我现在也是刚开始接触源代码,对系统层不是很了解,而且ContentProvider涉及到系统层的非常多,所以也不打算目前做了解。只是简单的做个介绍:

这里对于ContentProvider的基本用法不做介绍,不懂得话可以看下我的另外一篇博客:

http://blog.csdn.net/simon_crystin/article/details/68517050

下面就开始我是怎么追踪源代码的:

首先我们看 这个方法:

getContentResolver().insert(MyContentProvider.uri,contentValues);


我们先看看getContentResolver()这个方法:

public ContentResolver getContentResolver() {
return mBase.getContentResolver();
}


继续往下面看 getContentResolver();

public abstract class Context
public abstract ContentResolver getContentResolver();


这里定义了一个抽象方法,是Context下面的抽象方法。

肯定有个子类重写了这个方法,我们发现:class ContextImpl extends Context,

于是我们去搜索:

@Override
public ContentResolver getContentResolver() {
return mContentResolver;
}


果然在下面找到了这个方法。接着往下面看:

private final ApplicationContentResolver mContentResolver;


这里返回的是ApplicationContentResolver 的对象。

private static final class ApplicationContentResolver extends ContentResolver


ApplicationContentResolver 继承自ContentResolver;

这就到了我们熟悉的地方了。终于是获得了ContentResolver 的对象。

我们去这下面找insert方法:

public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url,
@Nullable ContentValues values) {
Preconditions.checkNotNull(url, "url");
IContentProvider provider = acquireProvider(url);
if (provider == null) {
throw new IllegalArgumentException("Unknown URL " + url);
}
try {
long startTime = SystemClock.uptimeMillis();
Uri createdRow = provider.insert(mPackageName, url, values);
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
return createdRow;
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
return null;
} finally {
releaseProvider(provider);
}
}


这个方法做了什么操作呢?

IContentProvider provider = acquireProvider(url);

我们可以看到这个代码,我之前的理解是,通过Uri来获取ContentProvider对象(通过Uri来区分不同的对象,这个是比较基础的),如果这样想的话,那就有点低估Google工程师了。

这里我们再跟下去,看看acquireProvider()这个方法到底是怎么样呢?

public final IContentProvider acquireProvider(Uri uri) {
if (!SCHEME_CONTENT.equals(uri.getScheme())) {
return null;
}
final String auth = uri.getAuthority();
if (auth != null) {
return acquireProvider(mContext, auth);
}
return null;
}


很显然,返回的一个对象,但是这个对象到底是什么呢?我们继续:

protected abstract IContentProvider acquireProvider(Context c, String name);


这个时候,可以看到,这是一个抽象方法,那肯定在子类重写了。。

在前面的提到ApplicationContentResolver这个类中,我们找到了这个重写的方法:

protected IContentProvider acquireProvider(Context context, String auth) {
return mMainThread.acquireProvider(context,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), true);
}


这里我们可以看到,返回了一个ContentProvider。当然,还可以继续追下去,不过博主技能有限,并且对系统层不了解。就不再进行了解了。不过目前正在学系统层这一块。

整个流程:

1、当我们调用getContentResolver().insert()后,将会通过getContentResolver()得到ContentResolver对象,然后调用该对象的insert()方法。
2、在ContentResolver中,会通过acquireProvider()的方法得到IContentProvider对象,而这个对象的获取首先需要ActivityThread中向ActivityManagerService申请的ContentProvider的详细信息(ContentProviderHolder),然后利用这个Holder去得到(getIContentProvider)ContentProvider的远程代理对象(Transport对象)。
3、拿到这个对象之后,调用其insert方法,该方法将会由ContentProvider传递给其子类(AbstractContactsProvider),并在子类中将insert操作转换为事务处理的方式(InsertInTransaction),AbstractContactsProvider中虽然将处理方式转换成事务的方式,但是却没有具体的实现,而是把具体的操作留给其子类(ContactsProvider2)完成。
4、ContactsProvider2在实现过程中将会用相应的SQLiteOpenHelper去把操作转换成具体的SQLite语句并执行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: