一、前言

ContentProvider作为Android四大组件之一,承担着数据存储的作用,本文用一个最典型的删除(delete)操作,按照Android源码, 从应用层的getContentResolver()入手,一步步的分析到ContentProvider内部,最终到达SQLite的操作 。

[java] view plaincopy
  1. getContentResolver().delete();

这个简单的操作其实包含了两个步骤:
         1、通过getContentResolver()得到需要的ContentProvider对象;
        2、通过delete()操作,将ContentProvider中的数据删除;

下面我们就开启此次漫长的旅程。

二、getContentResolver

看标题,我们是要得到一个ContentResolver的对象,这就产生了两个疑问:
        1、ContentResolver对象与ContentProvider有什么关系?
        2、我们是如何得到ContentProvider中的内容呢?

为了解答这两个问题,我们需要从代码的最源头开始分析:

2.1、ContentResolver与ContentProvider的关系

先来看看得到ContentResolver的过程:

[java] view plaincopy
  1. @ContextImpl.java
  2. public ContentResolver getContentResolver() {
  3. return mContentResolver;
  4. }

这里的mContentResolver是在ContextImpl的init中完成初始化的:

[java] view plaincopy
  1. final void init(Resources resources, ActivityThread mainThread, UserHandle user) {
  2. mPackageInfo = null;
  3. mBasePackageName = null;
  4. mResources = resources;
  5. mMainThread = mainThread;
  6. //mContentResolver被初始化为ApplicationContentResolver对象
  7. mContentResolver = new ApplicationContentResolver(this, mainThread, user);
  8. mUser = user;
  9. }

mContentResolver被初始化为ApplicationContentResolver对象,我们再来看ApplicationContentResolver这个类,他是ContextImpl的内部类:

[java] view plaincopy
  1. private static final class ApplicationContentResolver extends ContentResolver {
  2. public ApplicationContentResolver( Context context, ActivityThread mainThread, UserHandle user) { }
  3. protected IContentProvider acquireProvider(Context context, String auth) { }
  4. protected IContentProvider acquireExistingProvider(Context context, String auth) { }
  5. public boolean releaseProvider(IContentProvider provider) { }
  6. protected IContentProvider acquireUnstableProvider(Context c, String auth) { }
  7. public boolean releaseUnstableProvider(IContentProvider icp) { }
  8. public void unstableProviderDied(IContentProvider icp) { }
  9. }

他提供了得到IContentProvider的各种方法,而且继承自ContentResolver类,我们来看这个类的属性:

[java] view plaincopy
  1. @ContentResolver.java
  2. public abstract class ContentResolver { }

可以看到,ContentResolver并没有继承任何的类或者接口,因此,我们可以认为, 从继承关系上来讲,ContentResolver与ContentProvider没有任何关系 。

那么我们是如何最终得到ContentProvider的呢?


2.2、如何通过ContentResolver得到ContentProvider

下面我们来解答第二个疑问,我们是 如何通过ContentResolver去查询到ContentProvider中的内容呢?
        虽然我们知道这两者从继承关系上并没有什么联系,但是ContentResolver的内部却出现了我们熟悉的一些方法,包括:

[java] view plaincopy
  1. public final Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {}
  2. public final int delete(Uri url, String where, String[] selectionArgs){}
  3. public final int update(Uri uri, ContentValues values, String where, String[] selectionArgs) {}
  4. public final Uri insert(Uri url, ContentValues values){}

这就说明,两者在功能上一定有联系,下面我们从最开始的delete操作去分析,看两者究竟有什么关系。
        回到最初的调用地点,当我们需要通过ContentProvider去delete一项数据时,就会调用getContentResolver().delete()方法,上面分析道, getContentResolver()得到的就是ApplicationContentResolver的对象 ,而ApplicationContentResolver又继承自ContentResolver。因此,delete的操作就落在ContentResolver中:

[java] view plaincopy
  1. @ContentResolver.java
  2. public final int delete(Uri url, String where, String[] selectionArgs)
  3. {
  4. IContentProvider provider = acquireProvider(url);
  5. try {
  6. int rowsDeleted = provider.delete(url, where, selectionArgs);
  7. } catch (RemoteException e) {
  8. } finally {
  9. }
  10. }

在这一步中,我们先通过acquireProvider()得到IContentProvider对象,然后调用IContentProvider对象的delete方法进行操作。那么,这里是如何通过acquireProvider()得到IContentProvider对象的呢?

[java] view plaincopy
  1. public final IContentProvider acquireProvider(Uri uri) {
  2. //安全确认
  3. if (!SCHEME_CONTENT.equals(uri.getScheme())) {
  4. return null;
  5. }
  6. final String auth = uri.getAuthority();
  7. if (auth != null) {
  8. //继续调用
  9. return acquireProvider(mContext, auth);
  10. }
  11. return null;
  12. }

继续看:

[java] view plaincopy
  1. protected abstract IContentProvider acquireProvider(Context c, String name);

这里竟然遇到了抽象的acquireProvider,说明这个方法需要到子类中实现,那么我们就去ApplicationContentResolver中去看看:

[java] view plaincopy
  1. @ContextImpl.java
  2. private static final class ApplicationContentResolver extends ContentResolver {
  3. //果然找到了acquireProvider方法
  4. protected IContentProvider acquireProvider(Context context, String auth) {
  5. return mMainThread.acquireProvider(context, auth, mUser.getIdentifier(), true);
  6. }
  7. }

我们确实在ApplicationContentResolver中找到了acquireProvider()方法,而且发现 acquireProvider方法所提供的返回值是来自于mMainThread对象的acquireProvider方法 。
        那么,这个mMainThread是哪里来的呢?

接下来所介绍的流程,比较复杂,各位看好了。

2.3、寻找mMainThread对象来历

在ActivityThread中创建一个Activity之后,就会调用ActivityThread中的createBaseContextForActivity()方法,为当前的Activity创建Context对象和mMainThread对象:

[java] view plaincopy
  1. @ActivityThread.java
  2. private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
  3. //这里就是要创建Context对象的地方
  4. ContextImpl appContext = new ContextImpl();
  5. //并把当前ActivityThread对象传递给ContextImpl的init方法中
  6. appContext.init(r.packageInfo, r.token, this);
  7. }

此时将会调用ContextImpl中的init方法:

[java] view plaincopy
  1. @ContextImpl.java
  2. //这里的mainThread就是ActivityThread对象
  3. final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread) {
  4. init(packageInfo, activityToken, mainThread, null, null, Process.myUserHandle());
  5. }
  6. final void init(LoadedApk packageInfo, IBinder activityToken, ActivityThread mainThread, Resources container, String basePackageName, UserHandle user){
  7. //mMainThread就是ActivityThread对象
  8. mMainThread = mainThread;
  9. mContentResolver = new ApplicationContentResolver(this, mainThread, user);
  10. }

这个过程我们发现, mMainThread就是ActivityThread对象 ,因此在2.2中我们介绍的mMainThread.acquireProvider()相当于:

[java] view plaincopy
  1. ActivityThread.acquireProvider();

我们继续看:

[java] view plaincopy
  1. @ActivityThread.java
  2. public final IContentProvider acquireProvider( Context c, String auth, int userId, boolean stable) {
  3. final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
  4. if (provider != null) {
  5. return provider;
  6. }
  7. IActivityManager.ContentProviderHolder holder = null;
  8. try {
  9. holder = ActivityManagerNative.getDefault().getContentProvider( getApplicationThread(), auth, userId, stable);
  10. } catch (RemoteException ex) {
  11. }
  12. holder = installProvider(c, holder, holder.info, true , holder.noReleaseNeeded, stable);
  13. return holder.provider;
  14. }

这里可以看到, ActivityThread中存在一个HashMap用来缓存所有的provider。每一次对provider的请求,都会先通过acquireExistingProvider()查询是否已经被缓存,如果没有缓存,就去创建该provider的ContentProviderHolder对象,同时缓存下来方便下次调用 。

我们假设当前没有ContactsProvider的缓存,那么将会通过ActivityManagerNative.getDefault().getContentProvider()创建该provider,下面我们来分析这个创建的过程。

2.4、ActivityThread创建ContentProvider的过程。

前面说过,ActivityThread创建ContentProvider是通过以下方式实现的:

[java] view plaincopy
  1. ActivityManagerNative.getDefault().getContentProvider( getApplicationThread(), auth, userId, stable);

这个过程可以分为两步:

        1、我们来看通过ActivityManagerNative.getDefault()所得到的对象;

        2、我们再来分析这个对象的getContentProvider方法

2.4.1、ActivityManagerNative对象。

我们先介绍一下ActivityManagerService服务。
        当系统启动后,在SystemServer中就会将一些重要的Server启动起来,其中就包括ActivityManagerService:

[java] view plaincopy
  1. @SystemServer.java
  2. public void run() {
  3. //启动ActivityManagerService
  4. context = ActivityManagerService.main(factoryTest);
  5. //注册ActivityManagerService
  6. ActivityManagerService.setSystemProcess();
  7. }

上面调用ActivityManagerService.main方法的结果就是启动ActivityManagerService,然后调用setSystemProcess把ActivityManagerService注册给系统:

[java] view plaincopy
  1. @ActivityManagerService.java
  2. public static void setSystemProcess() {
  3. try {
  4. ActivityManagerService m = mSelf;
  5. //将自己注册为“activity”的Server
  6. ServiceManager.addService("activity", m, true);
  7. ServiceManager.addService("meminfo", new MemBinder(m));
  8. ServiceManager.addService("gfxinfo", new GraphicsBinder(m));
  9. ServiceManager.addService("dbinfo", new DbBinder(m));
  10. } catch (PackageManager.NameNotFoundException e) {
  11. }
  12. }

我们再来看ActivityManagerService的继承关系:

[java] view plaincopy
  1. public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {}

说明这个Server继承自ActivityManagerNative,而且父类主要完成一些Binder的操作。
        这样我们就对ActivityManagerNative的结构有了大致的了解, 根据Binder通讯机制,如果我们跨进程去请求ActivityManagerService的服务时,就会调用他的asBinder()方法,并把他的IBinder对象返回给客户端使用 。
        接着我们上面的分析,我们在2.4节中把创建ContentProvider分为两步, 第一步就是得到ActivityManagerNative.getDefault()对象 ,现在我们来看源码:

[java] view plaincopy
  1. @ActivityManagerNative.java
  2. static public IActivityManager getDefault() {
  3. return gDefault.get();
  4. }

我们看,调用ActivityManagerNative的getDefault()方法的结果就是得到gDefault对象里面的数据,那么gDefault里面究竟放着怎样的数据呢?我们来看他的定义:

[java] view plaincopy
  1. private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
  2. protected IActivityManager create() {
  3. IBinder b = ServiceManager.getService("activity");
  4. IActivityManager am = asInterface(b);
  5. return am;
  6. }
  7. };

原来,在gDefault变量的初始化过程中(create),完成了两步重要的操作:
         1、通过getService("activity")得到ActivityManagerService的远程Binder;
        2、利用得到的Biner对象通过asInterface()方法,得到这个服务的远程代理;
        对于得到Binder对象,这是由Binder系统决定的,我们无需多看,我们来看一下如何通过Binder得到服务的远程代理:

[java] view plaincopy
  1. static public IActivityManager asInterface(IBinder obj) {
  2. if (obj == null) {
  3. return null;
  4. }
  5. IActivityManager in = (IActivityManager)obj.queryLocalInterface(descriptor);
  6. if (in != null) {
  7. return in;
  8. }
  9. return new ActivityManagerProxy(obj);
  10. }

通过asInterface()的细节我们发现, 我们得到的远程代理对象就是ActivityManagerProxy对象 。也就是说我们当初的:

[java] view plaincopy
  1. ActivityManagerNative.getDefault().getContentProvider( getApplicationThread(), auth, userId, stable);

其实相当于:

[java] view plaincopy
  1. ActivityManagerProxy.getContentProvider(getApplicationThread(), auth, userId, stable);;

现在我们已经弄明白了2.4中提到的第一步操作,下面我们来分析第二部操作。

2.4.2、代理对象的getContentProvider操作

这一步当然是在ActivityManagerProxy类中发生的:

[java] view plaincopy
  1. @ActivityManagerNative.java
  2. class ActivityManagerProxy implements IActivityManager{
  3. public ContentProviderHolder getContentProvider(IApplicationThread caller,
  4. String name, int userId, boolean stable) throws RemoteException {
  5. Parcel data = Parcel.obtain();
  6. Parcel reply = Parcel.obtain();
  7. data.writeInterfaceToken(IActivityManager.descriptor);
  8. data.writeStrongBinder(caller != null ? caller.asBinder() : null);
  9. data.writeString(name);
  10. data.writeInt(userId);
  11. data.writeInt(stable ? 1 : 0);
  12. //向ActivityManagerNative发送请求
  13. mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);
  14. reply.readException();
  15. int res = reply.readInt();
  16. ContentProviderHolder cph = null;
  17. if (res != 0) {
  18. cph = ContentProviderHolder.CREATOR.createFromParcel(reply);
  19. }
  20. data.recycle();
  21. reply.recycle();
  22. return cph;
  23. }
  24. }

我们看到,在getContentProvider的过程中,ActivityManagerProxy把请求通过mRemote发送给远端的ActivityManagerNative去处理,请求码为GET_CONTENT_PROVIDER_TRANSACTION。
        而ActivityManagerNative需要在onTransact()中去接收请求:

[java] view plaincopy
  1. @ActivityManagerNative.java
  2. public abstract class ActivityManagerNative extends Binder implements IActivityManager{
  3. //处理各种请求
  4. public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
  5. switch (code) {
  6. case GET_CONTENT_PROVIDER_TRANSACTION: {
  7. data.enforceInterface(IActivityManager.descriptor);
  8. IBinder b = data.readStrongBinder();
  9. IApplicationThread app = ApplicationThreadNative.asInterface(b);
  10. String name = data.readString();
  11. int userId = data.readInt();
  12. boolean stable = data.readInt() != 0;
  13. //调用ActivityManagerService的getContentProvider方法
  14. ContentProviderHolder cph = getContentProvider(app, name, userId, stable);
  15. reply.writeNoException();
  16. if (cph != null) {
  17. reply.writeInt(1);
  18. cph.writeToParcel(reply, 0);
  19. } else {
  20. reply.writeInt(0);
  21. }
  22. return true;
  23. }
  24. }
  25. }
  26. }

在onTransact中把该请求又发送给了真正的服务端ActivityManagerService.getContentProvider():

[java] view plaincopy
  1. @ActivityManagerService.java
  2. public final ContentProviderHolder getContentProvider( IApplicationThread caller, String name, int userId, boolean stable) {
  3. return getContentProviderImpl(caller, name, null, stable, userId);
  4. }

继续看服务端的操作:

[java] view plaincopy
  1. private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller, String name, IBinder token, boolean stable, int userId) {
  2. ContentProviderRecord cpr;
  3. ContentProviderConnection conn = null;
  4. ProviderInfo cpi = null;
  5. synchronized(this) {
  6. //查询缓存中是否已经存在该ContentProviderRecord
  7. cpr = mProviderMap.getProviderByName(name, userId);
  8. boolean providerRunning = cpr != null;
  9. if (providerRunning) {
  10. //如果该provider已经被运行过
  11. //得到该ContentProviderRecord的ProviderInfo
  12. cpi = cpr.info;
  13. if (r != null && cpr.canRunHere(r)) {
  14. //直接将ContentProviderHolder传给客户端即可
  15. ContentProviderHolder holder = cpr.newHolder(null);
  16. //清空其provider,由客户端自己去初始化provider的对象
  17. holder.provider = null;
  18. return holder;
  19. }
  20. }
  21. if (!providerRunning) {
  22. //当前没有运行
  23. //加载该provider的包,得到ProviderInfo
  24. cpi = AppGlobals.getPackageManager().resolveContentProvider(name, STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
  25. //为当前provider创建ContentProviderRecord
  26. ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
  27. cpr = mProviderMap.getProviderByClass(comp, userId);
  28. //缓存当前的ContentProviderRecord
  29. mProviderMap.putProviderByName(name, cpr);
  30. conn = incProviderCountLocked(r, cpr, token, stable);
  31. }
  32. }
  33. //将ContentProviderHolder传给客户端
  34. return cpr != null ? cpr.newHolder(conn) : null;
  35. }

在上面这个过程中,我们发现, 在ActivityManagerService中有存在着一个mProviderMap的变量用于保存当前系统中所有的provider,其中每一项都是一个ContentProviderRecord型的数据 ,通过这个数据可以完成两个重要作用:
         1、通过ContentProviderRecord.info可以得到当前provider的详细信息 ,包括该provider的authority、readPermission、writePermission、uriPermissionPatterns等重要信息;
         2、可以通过ContentProviderRecord.newHolder()方法,生成一个针对当前provider的详细信息 ,我们需要把这些信息打包为Holder传递给ActivityThread使用。
        我们再回到ActivityThread中的acquireProvider()里面:

[java] view plaincopy
  1. public final IContentProvider acquireProvider( Context c, String auth, int userId, boolean stable) {
  2. final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
  3. IActivityManager.ContentProviderHolder holder = null;
  4. try {
  5. //得到ContentProviderHolder对象
  6. holder = ActivityManagerNative.getDefault().getContentProvider( getApplicationThread(), auth, userId, stable);
  7. } catch (RemoteException ex) {
  8. }
  9. //用provider信息去初始化当前的provider
  10. holder = installProvider(c, holder, holder.info, true , holder.noReleaseNeeded, stable);
  11. //得到provider对象
  12. return holder.provider;
  13. }

在前面的过程中,我们通过ActivityManagerService得到了ContentProviderHolder对象,该对象是对provider的详细描述, 下面我们需要用这些描述在installProvider()方法中开启provider,并获得该provider的代理对象 。

[java] view plaincopy
  1. private IActivityManager.ContentProviderHolder installProvider(Context context, IActivityManager.ContentProviderHolder holder, ProviderInfo info, boolean noisy, boolean noReleaseNeeded, boolean stable) {
  2. ContentProvider localProvider = null;
  3. IContentProvider provider;
  4. if (holder == null || holder.provider == null) {
  5. //当前客户端没有得到过该provider,因此需要获得该provider远程代理
  6. Context c = null;
  7. ApplicationInfo ai = info.applicationInfo;
  8. if (context.getPackageName().equals(ai.packageName)) {
  9. //如果要获得的provider就在当前发出请求的客户端
  10. c = context;
  11. } else if (mInitialApplication != null && mInitialApplication.getPackageName().equals(ai.packageName)) {
  12. c = mInitialApplication;
  13. } else {
  14. try {
  15. //为要创建的provider创建Context对象
  16. c = context.createPackageContext(ai.packageName, Context.CONTEXT_INCLUDE_CODE);
  17. } catch (PackageManager.NameNotFoundException e) {
  18. }
  19. }
  20. try {
  21. final java.lang.ClassLoader cl = c.getClassLoader();
  22. //载入provider的类
  23. localProvider = (ContentProvider)cl.loadClass(info.name).newInstance();
  24. //得到该provider的IContentProvider对象
  25. provider = localProvider.getIContentProvider();
  26. localProvider.attachInfo(c, info);
  27. } catch (java.lang.Exception e) {
  28. }
  29. } else {
  30. //如果已经为该客户端创建过相应的provider,直接返回即可
  31. provider = holder.provider;
  32. }
  33. IActivityManager.ContentProviderHolder retHolder;
  34. synchronized (mProviderMap) {
  35. IBinder jBinder = provider.asBinder();
  36. //重新构建ContentProviderHolder类型的retHolder
  37. if (localProvider != null) {
  38. ComponentName cname = new ComponentName(info.packageName, info.name);
  39. ProviderClientRecord pr = mLocalProvidersByName.get(cname);
  40. if (pr != null) {
  41. provider = pr.mProvider;
  42. } else {
  43. //得到ContentProvider的远程代理对象
  44. holder = new IActivityManager.ContentProviderHolder(info);
  45. holder.provider = provider;
  46. holder.noReleaseNeeded = true;
  47. pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
  48. mLocalProviders.put(jBinder, pr);
  49. mLocalProvidersByName.put(cname, pr);
  50. }
  51. retHolder = pr.mHolder;
  52. } else {
  53. ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
  54. if (prc != null) {
  55. if (!noReleaseNeeded) {
  56. incProviderRefLocked(prc, stable);
  57. try {
  58. ActivityManagerNative.getDefault().removeContentProvider( holder.connection, stable);
  59. } catch (RemoteException e) {
  60. }
  61. }
  62. } else {
  63. ProviderClientRecord client = installProviderAuthoritiesLocked(provider, localProvider, holder);
  64. if (noReleaseNeeded) {
  65. prc = new ProviderRefCount(holder, client, 1000, 1000);
  66. } else {
  67. prc = stable
  68. ? new ProviderRefCount(holder, client, 1, 0)
  69. : new ProviderRefCount(holder, client, 0, 1);
  70. }
  71. mProviderRefCountMap.put(jBinder, prc);
  72. }
  73. retHolder = prc.holder;
  74. }
  75. }
  76. return retHolder;
  77. }

我们清晰的看到,在installProvider的方法中,我们 用ActivityManagerService中得到的ContentProvider信息,去加载该ContentProvider(localProvider),并调用他的getIContentProvider()方法得到该provider的代理对象 。
        然后我们再回到ActivityThread中的acquireProvider():

[java] view plaincopy
  1. public final IContentProvider acquireProvider( Context c, String auth, int userId, boolean stable) {
  2. final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
  3. IActivityManager.ContentProviderHolder holder = null;
  4. try {
  5. //得到ContentProviderHolder对象
  6. holder = ActivityManagerNative.getDefault().getContentProvider( getApplicationThread(), auth, userId, stable);
  7. } catch (RemoteException ex) {
  8. }
  9. //用provider信息去初始化当前的provider
  10. holder = installProvider(c, holder, holder.info, true , holder.noReleaseNeeded, stable);
  11. //将得到provider代理对象返回给客户端调用
  12. return holder.provider;
  13. }

经过上面的分析,我们从最初的getContentResolver()一步步的分析,经过ContextImpl、ActivityThread、ActivityManagerNative、ActivityManagerService,最终得到了ContentProvider的代理对象。


三、ContentProvider调用分析

在上面一节中我们对getContentResolver()的过程进行分析,发现这样操作的结果不仅可以载入需要的ContentProvider(如果当前ContentProvider还没有被载入),并且调用了该ContentProvider的getIContentProvider()方法。这一节我们就要从这个方法入手,看看如何通过这个方法得到ContentProvider对象,又如何通过该对象传递对数据库的操作。
        我们先来看一下通过getIContentProvider()方法得到的究竟是什么对象。

[java] view plaincopy
  1. @ContentProvider.java
  2. public IContentProvider getIContentProvider() {
  3. return mTransport;
  4. }

这里得到的只是IContentProvider类型的mTransport变量,而这个变量的来历呢?

[java] view plaincopy
  1. private Transport mTransport = new Transport();

这就说明,通过getIContentProvider()的方法得到的只是Transport对象,他是ContentProvider的内部类:

[java] view plaincopy
  1. class Transport extends ContentProviderNative {
  2. ContentProvider getContentProvider() { }
  3. public String getProviderName() { }
  4. public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal) { }
  5. public Uri insert(Uri uri, ContentValues initialValues) { }
  6. public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) throws OperationApplicationException { }
  7. public int delete(Uri uri, String selection, String[] selectionArgs) { }
  8. public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { }
  9. }

而且我们发现这个内部类提供了用于查询数据库的各项操作。那么当我们进行delete操作的时候呢?

[java] view plaincopy
  1. public int delete(Uri uri, String selection, String[] selectionArgs) {
  2. enforceWritePermission(uri);
  3. return ContentProvider.this.delete(uri, selection, selectionArgs);
  4. }

既然Transport内部把delete操作传递给了ContentProvider去操作,那么我们就来看看ContentProvider本身对delete()的处理:

[java] view plaincopy
  1. public abstract int delete(Uri uri, String selection, String[] selectionArgs);

这里我们遇到了抽象的方法,也就是说,delete操作的具体细节需要在ContentProvider的子类中实现了,这也符合ContentProvider框架的设计理念,即: ContentProvider负责抽象部分的表述,具体的操作需要各自private自己去实现 。
        我们此时来看一下ContentProvider本身提供了哪些重要的方法:

[java] view plaincopy
  1. public abstract class ContentProvider implements ComponentCallbacks2 {
  2. private Transport mTransport = new Transport();
  3. //构造函数
  4. public ContentProvider() { }
  5. //权限相关操作
  6. protected final void setReadPermission(String permission) { }
  7. public final String getReadPermission() { }
  8. protected final void setWritePermission(String permission) { }
  9. public final String getWritePermission() { }
  10. //增、删、改、查操作。
  11. public abstract Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);
  12. public abstract Uri insert(Uri uri, ContentValues values);
  13. public abstract int delete(Uri uri, String selection, String[] selectionArgs);
  14. public abstract int update(Uri uri, ContentValues values, String selection, String[] selectionArgs);
  15. public IContentProvider getIContentProvider() { }
  16. public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) throws OperationApplicationException { }
  17. }

从ContentProvider提供的方法我们发现,除了权限管理类的方法外,其他的就是一些与delete类似的、与数据库处理相关的抽象方法。
        此时我们结合Transport来分析不难发现,这个Transport对象作为ContentProvider的代理,可以对此对象发起各项请求。该代理得到请求后,就会把请求“转发”给ContentProvider本身。
        结合上一节我们分析的内容,我们可以总结如下:

我们在应用层调用getContentResolver().delete()的操作,将会调用到ContentResolver对象的delete操作,而ContentResolver对象就相当于通过getIContentProvider()得到的Transport对象,而Transport对象作为ContentProvider的代理将会把各项请求转移到ContentProvider中,因此就调用到ContentProvider的delete方法

getContentResolver==>ContentResolver==>Transport==>ContentProvider


四、ContentProvider到ContactsProvider

4.1、ContactsProvider综览

经过上面的过程,我们把操作转移到了ContentProvider中,接下来我们需要借助具体的provider来继续分析, 我们挑选联系人数据库(ContactsProvider)作为示例来研究
        联系人数据库源码位于\packages\providers\ContactsProvider\中,我们先来看一下他的AndroidManifest.xml文件:

[java] view plaincopy
  1. @AndroidManifest.xml
  2. <provider android:name="ContactsProvider2"
  3. android:authorities="contacts;com.android.contacts"
  4. android:label="@string/provider_label"
  5. android:multiprocess="false"
  6. android:exported="true"
  7. android:readPermission="android.permission.READ_CONTACTS"
  8. android:writePermission="android.permission.WRITE_CONTACTS">
  9. <path-permission
  10. android:pathPrefix="/search_suggest_query"
  11. android:readPermission="android.permission.GLOBAL_SEARCH" />
  12. <path-permission
  13. android:pathPrefix="/search_suggest_shortcut"
  14. android:readPermission="android.permission.GLOBAL_SEARCH" />
  15. <path-permission
  16. android:pathPattern="/contacts/.*/photo"
  17. android:readPermission="android.permission.GLOBAL_SEARCH" />
  18. <grant-uri-permission android:pathPattern=".*" />
  19. </provider>

这段声明告诉系统该provider的name、authorities、permission等信息,简单来说,这个数据库的名字叫做ContactsProvider2,可以通过contacts或者com.android.contacts的前缀来匹配,而且访问这个数据库需要相应的权限READ_CONTACTS、WRITE_CONTACTS等。

4.2、ContactsProvider结构

ContactsProvider结构中涉及到五个重要的类:ContentProvider、SQLiteTransactionListener、AbstractContactsProvider、ContactsProvider2、ProfileProvider。下面我们先简单说一下他们的关系。
        ContactsProvider在ContentProvider的基础上与SQLiteTransactionListener结合共同组件了AbstractContactsProvider,这是ContactsProvider最基础的类,然后在AbstractContactsProvider的基础上,扩展出来了ContactsProvider2和ProfileProvider这两个类,如下图所示:
        
        接下来我们来分别介绍这五个类的作用。

4.2.1、ContactsProvider

这个不用多说,是系统提供的ContactsProvider架构,里面遗留了对数据库操作的接口,需要子类去实现。

4.2.2、SQLiteTransactionListener

这是一个接口,里面内容也比较简单,只有3个方法:

[java] view plaincopy
  1. public interface SQLiteTransactionListener {
  2. /**
  3. * Called immediately after the transaction begins.
  4. */
  5. void onBegin();
  6. /**
  7. * Called immediately before commiting the transaction.
  8. */
  9. void onCommit();
  10. /**
  11. * Called if the transaction is about to be rolled back.
  12. */
  13. void onRollback();
  14. }

从注释中可以看出,他主要提供与事务处理相关的回调方法,其中onBegin是事务开始处理之后时调用的回调函数,onCommit是事务提交之后的回调函数,onRollback是事务回滚时的回调函数,由此推断, 在ContactsProvider中使用了事务的方式对数据库进行操作 。

4.2.3、AbstractContactsProvider

这是ContactsProvider结构中最底层的类,我们来看一下他内部主要的方法:

[java] view plaincopy
  1. public abstract class AbstractContactsProvider extends ContentProvider implements SQLiteTransactionListener {
  2. public SQLiteOpenHelper getDatabaseHelper() { }
  3. public Uri insert(Uri uri, ContentValues values) { }
  4. public int delete(Uri uri, String selection, String[] selectionArgs) { }
  5. public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { }
  6. public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) { }
  7. private ContactsTransaction startTransaction(boolean callerIsBatch) { }
  8. private void endTransaction(boolean callerIsBatch) { }
  9. protected abstract SQLiteOpenHelper getDatabaseHelper(Context context);
  10. protected abstract ThreadLocal<ContactsTransaction> getTransactionHolder();
  11. protected abstract Uri insertInTransaction(Uri uri, ContentValues values);
  12. protected abstract int deleteInTransaction(Uri uri, String selection, String[] selectionArgs);
  13. protected abstract int updateInTransaction(Uri uri, ContentValues values, String selection, String[] selectionArgs);
  14. protected abstract void notifyChange();
  15. }

这些方法都很好理解,均是对数据库的各项操作。还记得我们在分析ContentProvider的delete操作时提到,ContentProvider把对数据库的各项操作放到子类中处理,对当前环境来说,就是需要在AbstractContactsProvider中处理的,因此delete的操作就应该调用的这里:

[java] view plaincopy
  1. public int delete(Uri uri, String selection, String[] selectionArgs) {
  2. //开始事务操作
  3. ContactsTransaction transaction = startTransaction(false);
  4. try {
  5. //用事务进行delete的操作
  6. int deleted = deleteInTransaction(uri, selection, selectionArgs);
  7. if (deleted > 0) {
  8. transaction.markDirty();
  9. }
  10. transaction.markSuccessful(false);
  11. return deleted;
  12. } finally {
  13. endTransaction(false);
  14. }
  15. }

继续看deleteInTransaction的实现:

[java] view plaincopy
  1. protected abstract int deleteInTransaction(Uri uri, String selection, String[] selectionArgs);

这仍然是个虚函数,具体定义需要留给子类去实现。
        到这里我们发现,在AbstractContactsProvider中把insert、delete、update的操作转换成了事务的处理方式XXXInTransaction,并且把具体的实现留给了子类,这里的子类就是ContactsProvider2和ProfileProvider。也就是说, AbstractContactsProvider的作用就是把对数据库的操作转换成事务的处理方式,至于具体的事务操作,需要在其子类中实现 。
        另外,我们注意到,所转换的只是insert、delete、update操作,而没有query的操作,也就是说,在ContentProvider中的query操作直接遗留给了子类的子类去实现,而跨过了AbstractContactsProvider的转换。这就说明, query的操作并不需要转换成事务的处理方式 。

4.2.4、ProfileProvider

我们现在来看ProfileProvider的结构:

[java] view plaincopy
  1. public class ProfileProvider extends AbstractContactsProvider {
  2. public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder){}
  3. protected Uri insertInTransaction(Uri uri, ContentValues values){}
  4. protected int updateInTransaction(Uri uri, ContentValues values, String selection, String[] selectionArgs) {}
  5. protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs){}
  6. public void onBegin() { }
  7. public void onCommit() { }
  8. public void onRollback() { }
  9. }

我们从ProfileProvider的结构看出,他具备独立的query操作,以及插入、删除、更新的事务操作,以及事务相关的回调函数,可以说,他具备了完整的数据访问、修改能力。但是他的作用呢?
        这个问题我们待会儿就会明白。

4.2.5、ContactsProvider2

这是ContactsProvider中最重要也是最上层的类,当初我们在AndroidManifest中只对他进行了注册。
        我们来看一下他里面重要的方法:

[java] view plaincopy
  1. public class ContactsProvider2 extends AbstractContactsProvider implements OnAccountsUpdateListener {
  2. public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder) {}
  3. public int delete(Uri uri, String selection, String[] selectionArgs) {}
  4. public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {}
  5. public Uri insert(Uri uri, ContentValues values) {}
  6. protected Uri insertInTransaction(Uri uri, ContentValues values) {}
  7. protected int updateInTransaction(Uri uri, ContentValues values, String selection, String[] selectionArgs) {}
  8. protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {}
  9. }

与ProfileProvider类似,他也提供了完整的数据访问、修改能力。

五、ContactsProvider与SQLite

我们需要明白一点,ContentProvider的底层仍然依靠SQLite来实现的,ContentProvider只是将SQLite的操作进行了封装,更容易操作和理解
        在ContactsProvider的底层设计上,ContactsDatabaseHelper承担着与SQLite直接沟通的角色,在此之上又有差异化扩展了ProfileDatabaseHelper这个类。因此可以认为,在ContactsProvider的底层有两个与SQLite的帮助类。先来看一下他们的结构:

[java] view plaincopy
  1. public class ProfileDatabaseHelper extends ContactsDatabaseHelper {}
  2. public class ContactsDatabaseHelper extends SQLiteOpenHelper {}

继承关系如下:
         
        这两个SQLiteOpenHelper类均是在ContactsProvider2的onCreate()时被初始化的:

[java] view plaincopy
  1. public boolean onCreate() {
  2. super.onCreate();
  3. return initialize();
  4. }
  5. private boolean initialize() {
  6. //初始化ContactsDatabaseHelper
  7. mContactsHelper = getDatabaseHelper(getContext());
  8. mDbHelper.set(mContactsHelper);
  9. //初始化ProfileDatabaseHelper
  10. mProfileHelper = mProfileProvider.getDatabaseHelper(getContext());
  11. return true;
  12. }

我们先看ContactsDatabaseHelper初始化过程:

[java] view plaincopy
  1. protected ContactsDatabaseHelper getDatabaseHelper(final Context context) {
  2. return ContactsDatabaseHelper.getInstance(context);
  3. }
  4. @ContactsDatabaseHelper.java
  5. public static synchronized ContactsDatabaseHelper getInstance(Context context) {
  6. if (sSingleton == null) {
  7. //new出一个ContactsDatabaseHelper完成初始化
  8. sSingleton = new ContactsDatabaseHelper(context, DATABASE_NAME, true);
  9. }
  10. return sSingleton;
  11. }

再来看ProfileDatabaseHelper初始化过程:

[java] view plaincopy
  1. protected ProfileDatabaseHelper getDatabaseHelper(Context context) {
  2. return ProfileDatabaseHelper.getInstance(context);
  3. }
  4. public static synchronized ProfileDatabaseHelper getInstance(Context context) {
  5. if (sSingleton == null) {
  6. //new出一个ProfileDatabaseHelper完成初始化
  7. sSingleton = new ProfileDatabaseHelper(context, DATABASE_NAME, true);
  8. }
  9. return sSingleton;
  10. }

因为在ContactsProvider中存在两个“不同”的SQLiteOpenHelper,因此在具体的数据库操作时,需要根据不同需要来切换(switchToXXXMode)不同的SQLiteOpenHelper去操作。切换的过程我们稍后再讲。
        既然SQLiteOpenHelper存在两个,配套的,应该就有两个ContentProvider去操作这两个SQLiteOpenHelper,事实确实如此,在这两个SQLite操作类之上,分别搭建了ProfileProvider与ContactsProvider2这两个与ContentProvider相关的类,也就是说,这四者的对应关系类似与下图:
        

下面我们借助一次delete()操作来看看这两对数据库的操作流向。

5.1、仍然继续delete()

我们不妨再次回顾一下,当我们进行delete操作时,我们调用getContentResolver最终将会调用到ContentProvider中的delete方法,进而调用到ContactsProvider2中的delete方法:

[java] view plaincopy
  1. @ContactsProvider2.java
  2. public int delete(Uri uri, String selection, String[] selectionArgs) {
  3. waitForAccess(mWriteAccessLatch);
  4. //权限管理
  5. enforceSocialStreamWritePermission(uri);
  6. //查看是否需要放到ProfileProvider中处理
  7. if (mapsToProfileDb(uri)) {
  8. switchToProfileMode();
  9. //在ProfileProvider中处理
  10. return mProfileProvider.delete(uri, selection, selectionArgs);
  11. } else {
  12. switchToContactMode();
  13. //回到父类中处理delete操作
  14. return super.delete(uri, selection, selectionArgs);
  15. }
  16. }

在delete的过程中,根据mapsToProfileDb()的判断,需要切换两种模式:Profile与Contact模式,这也是我们刚刚讲的,需要根据不同的情况切换不同的SQLiteOpenHelper去操作数据库,我们现在来看一下区分两种模式的依据:

[java] view plaincopy
  1. private boolean mapsToProfileDb(Uri uri) {
  2. return sUriMatcher.mapsToProfile(uri);
  3. }

这里是根据给出的uri去sUriMatcher中查找是否有匹配的项,如果有,就认为需要转换到Profile模式去处理,那么sUriMatcher中究竟有哪些项呢?

[java] view plaincopy
  1. @ContactsProvider2.java
  2. static {
  3. final UriMatcher matcher = sUriMatcher;
  4. matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS);
  5. matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID);
  6. matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_ID_DATA);
  7. matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/entities", CONTACTS_ID_ENTITIES);
  8. matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions", AGGREGATION_SUGGESTIONS);
  9. matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/suggestions/*", AGGREGATION_SUGGESTIONS);
  10. matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/photo", CONTACTS_ID_PHOTO);
  11. matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/display_photo", CONTACTS_ID_DISPLAY_PHOTO);
  12. matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/stream_items", CONTACTS_ID_STREAM_ITEMS);
  13. matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter", CONTACTS_FILTER);
  14. matcher.addURI(ContactsContract.AUTHORITY, "contacts/filter/*", CONTACTS_FILTER);
  15. matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*", CONTACTS_LOOKUP);
  16. matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/data", CONTACTS_LOOKUP_DATA);
  17. matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/photo", CONTACTS_LOOKUP_PHOTO);
  18. matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID);
  19. matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/data", CONTACTS_LOOKUP_ID_DATA);
  20. matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/photo", CONTACTS_LOOKUP_ID_PHOTO);
  21. matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/display_photo", CONTACTS_LOOKUP_DISPLAY_PHOTO);
  22. //......
  23. }

我们发现,在ContactsContract中定义的URI都在这个MAP中,也就是说,我们用ContactsContract中的URI去操作数据库时,都应该满足mapsToProfileDb的条件。

下面我们分别看这两种情况具体的操作。

5.2、ContactsProvider2的操作

我们先来分析这个数据流操作,再去分析ProfileProvider操作。也就是说我们需要switchToContactMode():

[java] view plaincopy
  1. private void switchToContactMode() {
  2. //将mDbHelper切换到mContactsHelper,也就是ContactsDatabaseHelper
  3. mDbHelper.set(mContactsHelper);
  4. mTransactionContext.set(mContactTransactionContext);
  5. mAggregator.set(mContactAggregator);
  6. mPhotoStore.set(mContactsPhotoStore);
  7. mInProfileMode.set(false);
  8. }

这里最重要的操作就是将mDbHelper中内容置换为mContactsHelper,也就是ContactsDatabaseHelper。接下来就是super.delete()的操作,这里的super对ContactsProvider2来说就是AbstractContactsProvider:

[java] view plaincopy
  1. @AbstractContactsProvider.java
  2. public int delete(Uri uri, String selection, String[] selectionArgs) {
  3. ContactsTransaction transaction = startTransaction(false);
  4. try {
  5. int deleted = deleteInTransaction(uri, selection, selectionArgs);
  6. transaction.markSuccessful(false);
  7. return deleted;
  8. } finally {
  9. endTransaction(false);
  10. }
  11. }
  12. protected abstract int deleteInTransaction(Uri uri, String selection, String[] selectionArgs);

这个“转换”的操作我们之前分析过,就是把delete操作转换为事务处理的方式,具体操作需要在子类中实现,因此又回到了ContactsProvider2中的deleteInTransaction:

[java] view plaincopy
  1. protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {
  2. //得到SQLiteOpenHelper,当前是ContactsDatabaseHelper
  3. final SQLiteDatabase db = mDbHelper.get().getWritableDatabase();
  4. //根据当前uri匹配结果
  5. final int match = sUriMatcher.match(uri);
  6. switch (match) {
  7. case CONTACTS: {
  8. invalidateFastScrollingIndexCache();
  9. return 0;
  10. }
  11. case CONTACTS_ID: {
  12. invalidateFastScrollingIndexCache();
  13. long contactId = ContentUris.parseId(uri);
  14. return deleteContact(contactId, callerIsSyncAdapter);
  15. }
  16. default: {
  17. mSyncToNetwork = true;
  18. return mLegacyApiSupport.delete(uri, selection, selectionArgs);
  19. }
  20. }
  21. }

这里我们假设匹配的是CONTACTS_ID:

[java] view plaincopy
  1. private int deleteContact(long contactId, boolean callerIsSyncAdapter) {
  2. //得到SQLiteOpenHelper
  3. final SQLiteDatabase db = mDbHelper.get().getWritableDatabase();
  4. mSelectionArgs1[0] = Long.toString(contactId);
  5. //先查询相关信息
  6. Cursor c = db.query(Tables.RAW_CONTACTS, new String[]{RawContacts._ID}, RawContacts.CONTACT_ID + "=?", mSelectionArgs1, null, null, null);
  7. try {
  8. while (c.moveToNext()) {
  9. long rawContactId = c.getLong(0);
  10. markRawContactAsDeleted(db, rawContactId, callerIsSyncAdapter);
  11. }
  12. } finally {
  13. c.close();
  14. }
  15. mProviderStatusUpdateNeeded = true;
  16. //删除SQLite
  17. return db.delete(Tables.CONTACTS, Contacts._ID + "=" + contactId, null);
  18. }

在deleteContact的过程中,要先得到可用的SQLiteDatabase,当前来说就是得到ContactsDatabaseHelper的SQLiteDatabase,然后查询数据库得到Cursor,并遍历每一项标记其删除的标记,最后再调用SQLiteDatabase的delete()方法将该条记录删除。
        我们详细看一下SQLiteDatabase的delete()过程:

[java] view plaincopy
  1. @SQLiteDatabase.java
  2. public int delete(String table, String whereClause, String[] whereArgs) {
  3. acquireReference();
  4. try {
  5. //构建SQL语句
  6. SQLiteStatement statement =  new SQLiteStatement(this, "DELETE FROM " + table + (!TextUtils.isEmpty(whereClause) ? " WHERE " + whereClause : ""), whereArgs);
  7. try {
  8. //执行删除命令
  9. return statement.executeUpdateDelete();
  10. } finally {
  11. statement.close();
  12. }
  13. } finally {
  14. releaseReference();
  15. }
  16. }

我们看到,delete操作中,先 通过SQLiteStatement生成SQL语句(DELETE FROM XXX WHERE XXX),然后通过executeUpdateDelete()方法去应用该SQL操作,从而完成delete的操作 。

到这里,我们终于完成了从ContentProvider到SQLite的“历程”。

5.3、ProfileProvider的操作

首先要切换数据库为ProfileDatabaseHelper:

[java] view plaincopy
  1. private void switchToProfileMode() {
  2. //为mDbHelper设置ProfileDatabaseHelper
  3. mDbHelper.set(mProfileHelper);
  4. mTransactionContext.set(mProfileTransactionContext);
  5. mAggregator.set(mProfileAggregator);
  6. mPhotoStore.set(mProfilePhotoStore);
  7. mInProfileMode.set(true);
  8. }

然后进行删除动作:

[java] view plaincopy
  1. mProfileProvider.delete(uri, selection, selectionArgs);

也就是调用ProfileProvider中的delete方法,但是在ProfileProvider没有找到delete方法,我们只能去其父类AbstractContactsProvider中调用delete():

[java] view plaincopy
  1. @AbstractContactsProvider.java
  2. public int delete(Uri uri, String selection, String[] selectionArgs) {
  3. ContactsTransaction transaction = startTransaction(false);
  4. try {
  5. //把delete转换为事务的处理方式
  6. int deleted = deleteInTransaction(uri, selection, selectionArgs);
  7. if (deleted > 0) {
  8. transaction.markDirty();
  9. }
  10. transaction.markSuccessful(false);
  11. return deleted;
  12. } finally {
  13. endTransaction(false);
  14. }
  15. }
  16. protected abstract int deleteInTransaction(Uri uri, String selection, String[] selectionArgs);

经过AbstractContactsProvider的“转换”,将delete操作转换到子类中的deleteInTransaction():

[java] view plaincopy
  1. @ProfileProvider.java
  2. protected int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {
  3. enforceWritePermission();
  4. useProfileDbForTransaction();
  5. return mDelegate.deleteInTransaction(uri, selection, selectionArgs);
  6. }

这里的mDelegate就是ContactsProvider2本身,因此在ProfileProvider中扰了一圈,又回到了ContactsProvider2中的deleteInTransaction(),而这个方法我们在5.2节已经介绍过详细的流程。

六、总结

现在我们回顾一下整个流程:
        1、当我们调用getContentResolver().delete()后,将会通过getContentResolver()得到ContentResolver对象,然后调用该对象的delete()方法。
        2、在ContentResolver中,会通过acquireProvider()的方法得到IContentProvider对象,而这个对象的获取首先需要ActivityThread中向ActivityManagerService申请的ContentProvider的详细信息(ContentProviderHolder),然后利用这个Holder去得到(getIContentProvider)ContentProvider的远程代理对象(Transport对象)。
        3、拿到这个对象之后,调用其delete方法,该方法将会由ContentProvider传递给其子类(AbstractContactsProvider),并在子类中将delete操作转换为事务处理的方式(deleteInTransaction),AbstractContactsProvider中虽然将处理方式转换成事务的方式,但是却没有具体的实现,而是把具体的操作留给其子类(ContactsProvider2)完成。
        4、ContactsProvider2在实现过程中将会用相应的SQLiteOpenHelper去把操作转换成具体的SQLite语句并执行。

        下面我们用一张图来结束本次的学习。
        

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

ContentProvider源码分析(原)相关推荐

  1. Linux内核 eBPF基础:kprobe原理源码分析:源码分析

    Linux内核 eBPF基础 kprobe原理源码分析:源码分析 荣涛 2021年5月11日 在 <Linux内核 eBPF基础:kprobe原理源码分析:基本介绍与使用>中已经介绍了kp ...

  2. Android 双开沙箱 VirtualApp 源码分析(六)ContentProvider

    上一章:Android 双开沙箱 VirtualApp 源码分析(五)BroadcastReceiver Provider 注册 回顾前面,Activity 启动的时候会检查 Application ...

  3. Android 源码分析 (十一) ContentProvider 启动

    ContentProvider (内容提供者) 属于四大组件之一,可以说它是在四大组件中开发者使用率最少的一个,它的作用就是进程间进行数据交互,底层采用 Binder 机制进行进程间通信. 下面我们就 ...

  4. 基于比原链开发Dapp(四)-bufferserver源码分析

    ##简介 ​    本章内容主要直接分析bufferserver源码,也就是比原链官方Dapp-demo的后端接口,里面包含了UTXO的托管逻辑.账单逻辑等,还会介绍一些改进的源码内容. [储蓄分红合 ...

  5. 基于比原链开发Dapp(三)-Dapp-demo前端源码分析

    # 简介 ​    本章内容会针对比原官方提供的dapp-demo,分析里面的前端源码,分析清楚整个demo的流程,然后针对里面开发过程遇到的坑,添加一下个人的见解还有解决的方案. ### 储蓄分红合 ...

  6. Binder源码分析之Java层(原)

    前面的几节中我们介绍了Native层Binder通讯的原理和用法,那么在Java层如何使用Binder通讯呢?其原理又与Native层的Binder有什么关系呢?         与Native层的S ...

  7. Binder源码分析之驱动层(原)

    前言 在< Binder源码分析之ServiceManager >一文中我们介绍了利用Binder进行通讯的流程,即ServiceManager把自己注册为"管理员"之 ...

  8. Binder源码分析之ServiceManager(原)

    ServiceManager作为Native层Service的管理员,有着极其重要的作用,主要表现两个方面:         1.对于服务端来说,系统所有的服务提供者都需要向ServiceManage ...

  9. 图片加载框架Picasso - 源码分析

    简书:图片加载框架Picasso - 源码分析 前一篇文章讲了Picasso的详细用法,Picasso 是一个强大的图片加载缓存框架,一个非常优秀的开源库,学习一个优秀的开源库,,我们不仅仅是学习它的 ...

最新文章

  1. s5pv210启动debian出错提示bash: cannot set terminal process group (-1): Inappropriate ioctl for device...
  2. 据说一般人轻易做不了技术支撑…
  3. *hdu5632Rikka with Array
  4. redis发布订阅c接口_Redis 发布/订阅机制原理分析
  5. SELECT INTO和INSERT INTO SELECT的区别 类似aaa?a=1b=2c=3d=4,如何将问号以后的数据变为键值对 C# 获取一定区间的随即数 0、1两个值除随机数以外...
  6. http 标准超时时间_Go 中 http 超时问题的排查
  7. 模糊综合评价模型 ——第三部分,一级模糊综合评价模型应用:例题1,对员工进行年终综合评定
  8. 欧拉回路专题 POJ - 1637网络流+混合图的欧拉回路
  9. 湖南信息学院大一C语言考试,2003级信息学院《C语言程序设计》考试试题
  10. Kaggle一周30小时Tesla P100教程~
  11. 搭建一个属于自己的博客平台
  12. 微信小程序个人中心、我的界面(示例一)
  13. linux多线程调用同一个函数解析
  14. 算法笔记:找考试座位号问题
  15. Intel芯片组大全最新版
  16. python 用画布组件画直方图_7招用Python画出酷酷的|散点直方图
  17. Vue中监听键盘事件
  18. java字符串format_JAVA字符串格式化-String.format()的使用
  19. 《大众创业做电商——淘宝与微店 开店 运营 推广 一册通》一一2.1 电子商务的发展历史...
  20. 阿里云服务器ECS年终特惠,云服务器报价出炉

热门文章

  1. java进阶08 GUI图形界面
  2. 常用chrome插件
  3. android版记账本
  4. asp动态树菜单集合(3/3)
  5. 系统安装操作优化:chapter4 多系统的安装与管理
  6. Redhat 或 CentOS 发行版本号
  7. CBLAS的安装与使用
  8. [云炬创业管理笔记]第三章测试5
  9. 成功解决C4996: ‘fopen‘: This function or variable may be unsafe. Consider using fopen_s instead
  10. 骁龙845_骁龙845为什么这么快就不受欢迎了?手机更新节奏有多快