Android系统源码分析之-ContentProvider

作者 : 开心源码 本文共17936个字,预计阅读时间需要45分钟 发布时间: 2022-05-12 共208人阅读

距离上一次写博客已经半年多了,这半年发生了很多事情,也有了很多感触,最主要是改变了忙碌了工作,更加重视身体的健康,为此也把工作地点从深圳这个一线城市换到了珠海,工作相对没有那么累,身体感觉也好了很多。所以在工作完成之余,也有了更多的时间来自我学习和提高,后续会用更多时间来写更多实用的东西,帮助我们了解安卓系统的原理,帮助我们快速、稳固的开发。
这一篇我们接着之前的计划,完成四大组件的最后一个ContentProvider的分析。ContentProvider是一个笼统类,用来提供访问数据的统一格式的接口。ContentProvider的作用是多应用间共享数据,假如客户需要直接使用则可以直接在里面使用数据库来保存数据,也可以通用ContentResolver使用URI来存储数据,使用URI客户不需要知道内部怎样存储只要要知道如何使用该存储方式。

ContentProvider

ContentProvider的形容及使用:

在之前我们分析过ContentProvider的启动比Application的启动早,所以使用时需要知道这种情况。在使用ContentResolver时是通过URI来访问的,URI的结构:content://cn.codemx.myprovider/item/123,我们划分一下:

[    1     ][         2          ][  3  ][ 4  ][content://][cn.codemx.myprovider.settings][/item][/123]
  • 第一个组件:是一个协议名称,它的值固定为:“content://”,是Content Provider组件的专用访问协议
  • 第二个组件:是一个Content Provider组件的android:authority属性值。这个组件相似于URL中的域名,因而我们要保证它是全局唯一的,一般使用它所形容的ContentProvider组件的包名来命名。
  • 第三个组件:是一个资源相对路径,用来形容要访问的资源类型。假如一个ContentProvider只有一种资源,那么忽略这个组件,否则通过它来指定要访问的资源的类型。
  • 第四个组件:是一个资源ID,用来形容具体的资源。

举个例子:

<provider    android:name="com.android.launcher3.LauncherProvider"    android:authorities="cn.codemx.myprovider.settings"    android:exported="true"    android:readPermission="cn.codemx.myprovider.permission.READ_SETTINGS"    android:writePermission="cn.codemx.myprovider.permission.WRITE_SETTINGS"/>

我有个LauncherProvider继承ContentProvider,在AndroidManifest.xml中要像上面一样公告,其中authorities是位置认证,在使用时是这样使用的:

public static final String TABLE_NAME = "favorites";/** * The content:// style URL for this table */public static final Uri CONTENT_URI = Uri.parse("content://" +        ProviderConfig.AUTHORITY + "/" + TABLE_NAME);

其中ProviderConfig.AUTHORITY为:

public class ProviderConfig {    public static final String AUTHORITY = "cn.codemx.myprovider.settings".intern();}

这个就是上面AndroidManifest.xml中公告的那个authorities属性值。上面获取了Uri即可以通过Uri来获取或者者保存数据了。

ContentProvider启动过程:

  • Activity通过MyContentProvider.CONTENT_URI来访问MyContentProvider组件,以便可以取得它的内容
  • Activity组件所运行在的应用程序进程发现它里面不存在一个用来访问MyContentProvider组件的代理商对象,于是通过MyContentProvider.CONTENT_URI来请求AMS返回一个用来访问MyContentProvider组件的代理商对象
  • AMS发现MyContentProvider还没有起来,于是先创立一个新的应用进程,而后在这个新创立的应用进程中启动MyContentProvider组件
  • MyContentProvider组件启动之后,就会将自己发布到AMS中,以便AMS可以将它的一个代理商对象返回Activity组件。

ContentProvider方法:

onCreate()                                      // 执行初始化工作;insert(Uri, ContentValues)                      // 插入新数据;delete(Uri, String, String[])                   // 删除已有数据;update(Uri, ContentValues, String, String[])    // 升级数据;query(Uri, String[], String, String[], String)  // 查询数据;getType(Uri)                                    // 获取数据MIME类型。

ContentProvider不像Activity一样有生命周期,只有一个onCreate方法用来创立。而后就是提供了增、删、改、查用来操作数据的接口,通过Uri来管理数据。

ContentResolver的获取:

上面我们提到ContentProvider主要是提供接口,并没有具体实现,假如需要具体实现,一种是通过操作数据库,一种是通过URI操作ContentResolver,数据库的这里不再详情,只详情一下ContentResolver。

通常我们获取ContentResolver的代码如下:

ContentResolver cr = context.getContentResolver();  //获取ContentResolver

前面Android系统源码分析–Context章节我们分析过Context的子类及继承关系,知道,Context的所有实现都是在ContextImp中,所以context.getContentResolver()方法的实现也是一样。

ContextImpl.getContentResolver():

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

mContentResolver是定义在ContextImpl中类型为ApplicationContentResolver的变量:

    private final ApplicationContentResolver mContentResolver;

这里我们可以知道我们获取到的ContentResolver实际上是ApplicationContentResolver,所以具体操作应该都是在ApplicationContentResolver中实现的。我们先看看这个mContentResolver是在哪里初始化的。

    private ContextImpl(ContextImpl container, ActivityThread mainThread,                        LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags,                        Display display, Configuration overrideConfiguration, int createDisplayWithId) {                        ...                                                mContentResolver = new ApplicationContentResolver(this, mainThread, user);    }                        

上面代码可以知道这个是在ContextImpl构造函数中初始化的。而ContentResolver中的所有操作都在ApplicationContentResolver实现。

ContentResolver.query

先看时序图:

ContentProvider启动时序图

1.ContentResolver.query

public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,            @Nullable String[] projection, @Nullable String selection,            @Nullable String[] selectionArgs, @Nullable String sortOrder,            @Nullable CancellationSignal cancellationSignal) {        Preconditions.checkNotNull(uri, "uri");        // 返回的是ContentProvider的中的mTransport(Transport)        IContentProvider unstableProvider = acquireUnstableProvider(uri);        if (unstableProvider == null) {            return null;        }        IContentProvider stableProvider = null;        Cursor qCursor = null;        try {            ...            try {                qCursor = unstableProvider.query(mPackageName, uri, projection,                        selection, selectionArgs, sortOrder, remoteCancellationSignal);            } catch (DeadObjectException e) {                // The remote process has died...  but we only hold an unstable                // reference though, so we might recover!!!  Let's try!!!!                // This is exciting!!1!!1!!!!1                unstableProviderDied(unstableProvider);                // 返回的是ContentProvider的中的mTransport(Transport)                stableProvider = acquireProvider(uri);                if (stableProvider == null) {                    return null;                }                qCursor = stableProvider.query(mPackageName, uri, projection,                        selection, selectionArgs, sortOrder, remoteCancellationSignal);            }            if (qCursor == null) {                return null;            }            ...            // Wrap the cursor object into CursorWrapperInner object.            final IContentProvider provider = (stableProvider != null) ? stableProvider                    : acquireProvider(uri);            final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);            stableProvider = null;            qCursor = null;            return wrapper;        } catch (RemoteException e) {            ...            return null;        } finally {            // 释放资源            ...        }    }

首先是判断Uri能否是空,假如空抛出异常,假如不是获取unstableProvider,从名字看是不稳固的Provider,往下看还有个stableProvider(稳固的Provider),其实从代码看没有区别,只是第一次获取是不稳固的,出现异常就再次获取就是稳固的。所以我们只看一个就可。从注释可以知道unstableProvider其实是ContentProvider中的Transport对象mTransport,这个我们先提出来,后面通过代码看是不是对的。

2.ContentResolver.acquireUnstableProvider

    public final IContentProvider acquireUnstableProvider(Uri uri) {        // uri以"content"开头        if (!SCHEME_CONTENT.equals(uri.getScheme())) {            return null;        }        // 获取Manifest文件中的authorities属性(例如:cn.codemx.myprovider.settings)        String auth = uri.getAuthority();        if (auth != null) {            // 具体实现ApplicationContentResolver中            return acquireUnstableProvider(mContext, uri.getAuthority());        }        return null;    }

这里主要是验证协议名是不是content,而后验证属性是不是存在,假如存在则开始获取实现IContentProvider接口的对象。

3.ApplicationContentResolver.acquireUnstableProvider

        protected IContentProvider acquireUnstableProvider(Context c, String auth) {            return mMainThread.acquireProvider(c,                    ContentProvider.getAuthorityWithoutUserId(auth),                    resolveUserIdFromAuthority(auth), false);        }

这里调用的是ActivityThread.acquireProvider方法。

4.ActivityThread.acquireProvider

    public final IContentProvider acquireProvider(            Context c, String auth, int userId, boolean stable) {        // 返回的是ContentProvider的中的mTransport(Transport)        final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);        if (provider != null) {// 假如不为空,说明访问过,假如是第一次访问,为空            return provider;        }        ...        IActivityManager.ContentProviderHolder holder = null;        try {            // 核心部分            holder = ActivityManagerNative.getDefault().getContentProvider(                    getApplicationThread(), auth, userId, stable);        } catch (RemoteException ex) {            throw ex.rethrowFromSystemServer();        }        if (holder == null) {            Slog.e(TAG, "Failed to find provider info for " + auth);            return null;        }        // Install provider will increment the reference count for us, and break        // any ties in the race.        holder = installProvider(c, holder, holder.info,                true /*noisy*/, holder.noReleaseNeeded, stable);        return holder.provider;    }

先根据auth获取能否存在实现IContentProvider的类,假如存在直接返回,不存在则获取IActivityManager.ContentProviderHolder对象,而后获取实现IContentProvider接口的类。我们先看acquireExistingProvider方法。

5.ActivityThread.acquireExistingProvider

    public final IContentProvider acquireExistingProvider(            Context c, String auth, int userId, boolean stable) {        synchronized (mProviderMap) {            final ProviderKey key = new ProviderKey(auth, userId);            // mProviderMap保存当前应用程序进程访问过的ContentProvider组件代理商对象            final ProviderClientRecord pr = mProviderMap.get(key);            if (pr == null) {// 假如不存在说明还没有访问过                return null;            }            // 返回的是ContentProvider的中的mTransport(Transport)            IContentProvider provider = pr.mProvider;            IBinder jBinder = provider.asBinder();            // 检查线程能否还存在            if (!jBinder.isBinderAlive()) {                ...                return null;            }            // Only increment the ref count if we have one.  If we don't then the            // provider is not reference counted and never needs to be released.            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);            if (prc != null) {                // 添加引用计数                incProviderRefLocked(prc, stable);            }            return provider;        }    }

首先是去缓存中获取,能否存在封装了ContentProvider对象的ProviderClientRecord对象,假如不存在则说明第一次启动,还没增加到缓存中,假如存在,那么说明已经启动过,则会有需要的实现IContentProvider接口的对象。再看第4步中假如返回对象不为空则直接返回,假如是空则要先获取IActivityManager.ContentProviderHolder。

6.ActivityManagerProxy.getContentProvider

    public ContentProviderHolder getContentProvider(IApplicationThread caller,                                                    String name, int userId, boolean stable) throws RemoteException {        ...        // 通过Binder代理商对象mRemote发送一个类型为GET_CONTENT_PROVIDER_TRANSACTION的进程间通信消息        mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);        ...        return cph;    }

这里我们在前面几章涉及到了很屡次,就不再说了,主要是从这里调用AMS(ActivityManagerService)中的对应方法getContentProvider

7.AMS.getContentProvider

    public final ContentProviderHolder getContentProvider(            IApplicationThread caller, String name, int userId, boolean stable) {        ...        return getContentProviderImpl(caller, name, null, stable, userId);    }

这里比较简单,调用AMS.getContentProviderImpl方法。

8.AMS.getContentProviderImpl

    private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,                                                         String name, IBinder token, boolean stable, int userId) {        ContentProviderRecord cpr;        ContentProviderConnection conn = null;        ProviderInfo cpi = null;        synchronized (this) {            // 形容进程信息的对象            ProcessRecord r = null;            if (caller != null) {// 假如调用者的线程存在,根据caller获取对应的进程                r = getRecordForAppLocked(caller);                    // 假如找不到caller对应的进程抛出异常                    ...            }            ...            // 根据名称和userId获取ContentProviderRecord对象,用来检测是不是ContentProvider已经发布了            cpr = mProviderMap.getProviderByName(name, userId);            // If that didn't work, check if it exists for user 0 and then            // verify that it's a singleton provider before using it.            if (cpr == null && userId != UserHandle.USER_SYSTEM) {// 假如不存在并且不是系统的userId                // 检测mProviderMap中能否存在系统的ContentProviderRecord对象,假如已经启动则存在                cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM);                if (cpr != null) {                    cpi = cpr.info;                    if (isSingleton(cpi.processName, cpi.applicationInfo,                            cpi.name, cpi.flags)                            && isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) {                        ...                    } else {                        cpr = null;                        cpi = null;                    }                }            }            // 检查ContentProvider能否正在运行(第一次还没有运行)            boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;            if (providerRunning) {// ContentProvider已经运行                ...                if (r != null && cpr.canRunHere(r)) {// 进程存在                    ContentProviderHolder holder = cpr.newHolder(null);                    holder.provider = null;                    return holder;                }                ...                // provider实例已经存在,因而我们直接返回                conn = incProviderCountLocked(r, cpr, token, stable);                // 如何stable和unstable的总引用计数为1,那么升级LruProcess列表                if (conn != null && (conn.stableCount + conn.unstableCount) == 1) {                    if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {                        ...                        updateLruProcessLocked(cpr.proc, false, null);                    }                }                final int verifiedAdj = cpr.proc.verifiedAdj;                //  升级provider进程的adj                boolean success = updateOomAdjLocked(cpr.proc);                ...                if (!success) {// 假如升级不成功,那么减少引用计数并杀死provider进程                    ...                    ppDiedLocked(cpr.proc);// 杀死进程                    ...                    // 已经杀死了,所以要恢复初始状态                    providerRunning = false;                    conn = null;                } else {// 升级成功了                    cpr.proc.verifiedAdj = cpr.proc.setAdj;                }                ...            }            if (!providerRunning) {// 还没有运行,第一次启动                try {                    // 根据ContentProvider的AUTHORITY来获取对应的配置信息(ProviderInfo)                    cpi = AppGlobals.getPackageManager().                            resolveContentProvider(name,                                    STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);                } catch (RemoteException ex) {                }                // 没有找到对应的ProviderInfo,因而返回空                if (cpi == null) {                    return null;                }                // Provider能否为单例                boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,                        cpi.name, cpi.flags)                        && isValidSingletonCall(r.uid, cpi.applicationInfo.uid);                ...                // 通过ComponentName获取providerMap中的cpr                ComponentName comp = new ComponentName(cpi.packageName, cpi.name);                // 先去缓存中找                cpr = mProviderMap.getProviderByClass(comp, userId);                // 能否是第一次启动                final boolean firstClass = cpr == null;                if (firstClass) {// 第一次启动                    final long ident = Binder.clearCallingIdentity();                    try {                        // 获取应用信息                        ApplicationInfo ai =                                AppGlobals.getPackageManager().                                        getApplicationInfo(                                                cpi.applicationInfo.packageName,                                                STOCK_PM_FLAGS, userId);                        ...                        // 创立一个cpr(ContentProviderRecord)                        cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);                    } catch (RemoteException ex) {                        ...                    } finally {                        ...                    }                }                ...                if (r != null && cpr.canRunHere(r)) {// 进程存在且正在运行                    return cpr.newHolder(null);                }                ...                final int N = mLaunchingProviders.size();                int i;                for (i = 0; i < N; i++) {                    if (mLaunchingProviders.get(i) == cpr) {                        break;                    }                }                // ContentProvider还没有被启动                if (i >= N) {                    final long origId = Binder.clearCallingIdentity();                    try {                        ...                        // 获取运行ContentProvider的进程                        ProcessRecord proc = getProcessRecordLocked(                                cpi.processName, cpr.appInfo.uid, false);                        // 假如进程已经存在并且没有被杀死                        if (proc != null && proc.thread != null && !proc.killed) {                            if (!proc.pubProviders.containsKey(cpi.name)) {                               // 将形容ContentProvider的对象(ContentProviderRecord)以包名为键放到进程进行缓存                                proc.pubProviders.put(cpi.name, cpr);                                try {                                    // 安装ContentProvider                                    proc.thread.scheduleInstallProvider(cpi);                                } catch (RemoteException e) {                                }                            }                        } else {// 进程不存在                            // 启动进程                            proc = startProcessLocked(cpi.processName,                                    cpr.appInfo, false, 0, "content provider",                                    new ComponentName(cpi.applicationInfo.packageName,                                            cpi.name), false, false, false);                            if (proc == null) {// 进程启动失败                                return null;                            }                        }                        cpr.launchingApp = proc;                        mLaunchingProviders.add(cpr);                    } finally {                        ...                    }                }                if (firstClass) {// 第一次启动要保存ContentProvider                    mProviderMap.putProviderByClass(comp, cpr);                }                // 保存                mProviderMap.putProviderByName(name, cpr);                conn = incProviderCountLocked(r, cpr, token, stable);                if (conn != null) {                    conn.waiting = true;                }            }        }        ...        return cpr != null ? cpr.newHolder(conn) : null;    }

这里代码比较多,但是思路比较清晰,首先是找对应的进程能否存在,由于我们正在启动ContentProvider,所以正常进程时存在的,而后根据进程找形容ContentProvider的形容对象ContentProviderRecord,假如第一次启动,这个形容对象是不存在的,假如不是第一次那么则存在该对象,其中providerRunning参数用来判断ContentProvider能否已经运行的,假如运行了直接返回,假如没有运行则创立ContentProvider的形容对象ContentProviderRecord,而后判断进程能否存在,存在则调用ApplicationThread.scheduleInstallProvider方法安装ContentProvider,不存在则直接启动进程。安装完成后缓存这些创立的ContentProvider相关的对象,方便下次使用直接从缓存获取。

9.ApplicationThread.scheduleInstallProvider

        public void scheduleInstallProvider(ProviderInfo provider) {            sendMessage(H.INSTALL_PROVIDER, provider);        }

这里是发送消息到ApplicationThread中的H(继承Handler)中,而后调用ActivityThread.handleInstallProvider

10.ActivityThread.handleInstallProvider

    public void handleInstallProvider(ProviderInfo info) {        final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();        try {            installContentProviders(mInitialApplication, Lists.newArrayList(info));        } finally {            StrictMode.setThreadPolicy(oldPolicy);        }    }

调用installContentProviders方法。

11.ActivityThread.installContentProviders

    private void installContentProviders(            Context context, List<ProviderInfo> providers) {        final ArrayList<IActivityManager.ContentProviderHolder> results =                new ArrayList<IActivityManager.ContentProviderHolder>();        for (ProviderInfo cpi : providers) {            ...            // 加载ContentProvider,而后调用ContentProvider的onCreate方法            IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);            if (cph != null) {                cph.noReleaseNeeded = true;                results.add(cph);            }        }        try {            ActivityManagerNative.getDefault().publishContentProviders(                    getApplicationThread(), results);        } catch (RemoteException ex) {            throw ex.rethrowFromSystemServer();        }    }

这里有两步,第一步:安装ContentProvider,而后调用ContentProvider.onCreate方法,第二步:调用AMP.publishContentProviders发布ContentProvider。我们先看第一步。

12.ActivityThread.installProvider

    private IActivityManager.ContentProviderHolder installProvider(Context context,                                                                   IActivityManager.ContentProviderHolder holder, ProviderInfo info,                                                                   boolean noisy, boolean noReleaseNeeded, boolean stable) {        ContentProvider localProvider = null;        IContentProvider provider;        if (holder == null || holder.provider == null) {            ...            try {                final java.lang.ClassLoader cl = c.getClassLoader();                // 根据名字通过类加载方式加载ContentProvider                localProvider = (ContentProvider) cl.                        loadClass(info.name).newInstance();                // 获取provider,也就是ContentProvider中的mTransport(Transport),这个provider赋值给了retHolder,所以前面在获取的时候就是这个provider(Transport)                provider = localProvider.getIContentProvider();                ...                // 增加ProviderInfo,而后调用ContentProvider的onCreate方法                localProvider.attachInfo(c, info);            } catch (java.lang.Exception e) {                ...                return null;            }        } else {// localProvider == null            provider = holder.provider;            ...        }        IActivityManager.ContentProviderHolder retHolder;        // 创立IActivityManager.ContentProviderHolder并且缓存ContentProvider相关信息        ...        return retHolder;    }

这里通过反射获取ContentProvider,而后调用ContentProvider的onCreate方法。创立完成后会缓存到IActivityManager.ContentProviderHolder中,并且返回IActivityManager.ContentProviderHolder对象。在11步中我们提到两步,一个就是安装,一个是发布,下面我看发布的代码。

13.AMP.publishContentProviders

    public void publishContentProviders(IApplicationThread caller,                                        List<ContentProviderHolder> providers) throws RemoteException {        ...        mRemote.transact(PUBLISH_CONTENT_PROVIDERS_TRANSACTION, data, reply, 0);        ...    }

通过这里调用AMS.publishContentProviders方法。

14.AMS.publishContentProviders

    public final void publishContentProviders(IApplicationThread caller,                                              List<ContentProviderHolder> providers) {        if (providers == null) {            return;        }        synchronized (this) {            // 获取进程形容对象            final ProcessRecord r = getRecordForAppLocked(caller);            ...            final long origId = Binder.clearCallingIdentity();            final int N = providers.size();            for (int i = 0; i < N; i++) {                ContentProviderHolder src = providers.get(i);                if (src == null || src.info == null || src.provider == null) {                    continue;                }                // 获取每个ContentProvider的形容对象ContentProviderRecord放到mProviderMap中                ContentProviderRecord dst = r.pubProviders.get(src.info.name);                if (dst != null) {                    ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);                    mProviderMap.putProviderByClass(comp, dst);                    String names[] = dst.info.authority.split(";");                    for (int j = 0; j < names.length; j++) {                        // 缓存                        mProviderMap.putProviderByName(names[j], dst);                    }                                        int launchingCount = mLaunchingProviders.size();                    ...                    synchronized (dst) {                        dst.provider = src.provider;                        dst.proc = r;                        // 通知AMS provider已经"发布"成功                        dst.notifyAll();                    }                    ...                }            }            ...        }    }

这里主要是从ContentProvider列表中获取对应的形容对象进行缓存,而后通知AMS中的ContentProvider发布完成。

15.ActivityThread.installProvider

这个方法我们上面12中分析了。只是一个是第一次启动,一个已经存在缓存了。

16.Transport.query

结合第1步和第12步我们知道IContentProvider unstableProvider返回的是ContentProvider中的mTransport,因而这里调用的是Transport.query方法

        public Cursor query(String callingPkg, Uri uri, String[] projection,                String selection, String[] selectionArgs, String sortOrder,                ICancellationSignal cancellationSignal) {            ...            if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {                ...                // 回调目标ContentProvider所定义的query方法                Cursor cursor = ContentProvider.this.query(uri, projection, selection,                        selectionArgs, sortOrder, CancellationSignal.fromTransport(                                cancellationSignal));                if (cursor == null) {                    return null;                }                // Return an empty cursor for all columns.                return new MatrixCursor(cursor.getColumnNames(), 0);            }            final String original = setCallingPackage(callingPkg);            try {                return ContentProvider.this.query(                        uri, projection, selection, selectionArgs, sortOrder,                        CancellationSignal.fromTransport(cancellationSignal));            } finally {                ...            }        }

最终调用了ContentProvider.this.query方法。到此我们对于ContentProvider.this.query方法分析完成了。其实还有其余方法(insert,delete,update)逻辑也是差不多的,分析完一个其余也就很好分析。

到此Android系统四大组件都分析完了,可能感觉还是不够详细,其实还是要自己多看,多看几遍源码就熟习了。后面开始分析View的绘制流程,由于这个相对来说非常复杂,假如一篇写完会写很长,看的话也很累,所以后面改用分章节去写,没章尽量分离开,尽量简短清晰,一看就能明白。

参考

从源码角度看ContentProvider
了解ContentProvider原理

代码地址:

直接拉取导入开发工具(Intellij idea或者者Android studio)

因为coding与腾讯云合作,改变很多,所以后续代码切换到Gitlab。

https://gitlab.com/yuchuangu85/android-25

首发地址:http://www.codemx.cn

Android开发群:192508518

微信公众账号:Code-MX

注:本文原创,转载请注明出处,多谢。

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » Android系统源码分析之-ContentProvider

发表回复