Android ContentProvider源码阅读学习


如果在android当中使用过媒体数据,比如获取手机或平板里面自带的图片路径、音乐路径、视频路径等等都是通过MediaProvider ,或者是通讯录里面的数据库 ContractsProvide, 这些数据在android系统当中是非常重要的,这几个类都是继承自ContentProvider,它是android的四大天王之一。ContentProvider对外共享数据统一了数据的访问方式。

Content providers are one of the primary building blocks of Android applications, providing content to applications. They encapsulate data and provide it to applications through the single ContentResolver interface. A content provider is only required if you need to share data between multiple applications. For example, the contacts data is used by multiple applications and must be stored in a content provider. If you don't need to share data amongst multiple applications you can use a database directly via SQLiteDatabase.


以mediaprovider 为例子:

//得到ContentResolver 对象,通过 contentresolver 可以获取到contenprovider的实例,避免了跨进程调用的细节
ContentResolver cr = context.getContentResover(); 
Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
Cursor cursor = mContext.getContentResolver().query(uri, null, null, null, null);
// 游标移到头部
// 获取数据库,使用while循环拿到你想要的数据信息这里就不写了


首先,需要在manifest xml里面申明:

<!-- android:exported="true" 指示该服务是否能够被其他应用程序组件调用或跟它交互。 -->
    android:enabled="true" >
// 实现里面的若干接口,然后里面你在封装一层去操作具体的数据库。
public class DatabaseProvider extends ContentProvider {
    public boolean onCreate() {
        return true;
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
                        String sortOrder) {
        return null;
    public Uri insert(Uri uri, ContentValues values) {
        return null;
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        return 0;
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        return 0;
    public String getType(Uri uri) {
        return null;

通过代码我们可以知道返回mContext.getContentResolver()的ContentResolver对象是ApplicationContentResolver类,而ApplicationContentResolver类又是继承于ContentResolver的(This class provides applications access to the content model.)我们就先看看这个类里面的query方法里面的,

     * Query the given URI, returning a {@link Cursor} over the result set
     * with optional support for cancellation.
     * <p>
     * For best performance, the caller should follow these guidelines:
     * <ul>
     * <li>Provide an explicit projection, to prevent
     * reading data from storage that aren't going to be used.</li>
     * <li>Use question mark parameter markers such as 'phone=?' instead of
     * explicit values in the {@code selection} parameter, so that queries
     * that differ only by those values will be recognized as the same
     * for caching purposes.</li>
     * </ul>
     * </p>
     * @param uri The URI, using the content:// scheme, for the content to
     *         retrieve.
     * @param projection A list of which columns to return. Passing null will
     *         return all columns, which is inefficient.
     * @param selection A filter declaring which rows to return, formatted as an
     *         SQL WHERE clause (excluding the WHERE itself). Passing null will
     *         return all rows for the given URI.
     * @param selectionArgs You may include ?s in selection, which will be
     *         replaced by the values from selectionArgs, in the order that they
     *         appear in the selection. The values will be bound as Strings.
     * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
     *         clause (excluding the ORDER BY itself). Passing null will use the
     *         default sort order, which may be unordered.
     * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
     * If the operation is canceled, then {@link OperationCanceledException} will be thrown
     * when the query is executed.
     * @return A Cursor object, which is positioned before the first entry, or null
     * @see Cursor
    public final @Nullable Cursor query(final @NonNull Uri uri, @Nullable String[] projection,
            @Nullable String selection, @Nullable String[] selectionArgs,
            @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) {
        Preconditions.checkNotNull(uri, "uri");
        IContentProvider unstableProvider = acquireUnstableProvider(uri);
        if (unstableProvider == null) {
            return null;
        IContentProvider stableProvider = null;
        Cursor qCursor = null;
        try {
            long startTime = SystemClock.uptimeMillis();

            ICancellationSignal remoteCancellationSignal = null;
            if (cancellationSignal != null) {
                remoteCancellationSignal = unstableProvider.createCancellationSignal();
            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
                stableProvider = acquireProvider(uri);
                if (stableProvider == null) {
                    return null;
                qCursor = stableProvider.query(mPackageName, uri, projection,
                        selection, selectionArgs, sortOrder, remoteCancellationSignal);
            if (qCursor == null) {
                return null;

            // Force query execution.  Might fail and throw a runtime exception here.
            long durationMillis = SystemClock.uptimeMillis() - startTime;
            maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);

            // Wrap the cursor object into CursorWrapperInner object.
            CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
                    stableProvider != null ? stableProvider : acquireProvider(uri));
            stableProvider = null;
            qCursor = null;
            return wrapper;
        } catch (RemoteException e) {
            // Arbitrary and not worth documenting, as Activity
            // Manager will kill this process shortly anyway.
            return null;
        } finally {
            if (qCursor != null) {
            if (cancellationSignal != null) {
            if (unstableProvider != null) {
            if (stableProvider != null) {

IContentProvider unstableProvider = acquireUnstableProvider(uri);最终会走到acquireUnstableProvider(Context c, String name)
protected abstract IContentProvider acquireUnstableProvider(Context c, String name); 可以看到这是个抽象方法具体实现由其子类来实现,也就是在 ApplicationContentResolver里面了(它是ContexImp.java中的一内部类继承自ContentResolver)

private final ActivityThread mMainThread;
        protected IContentProvider acquireUnstableProvider(Context c, String auth) {
            return mMainThread.acquireProvider(c,
                    resolveUserIdFromAuthority(auth), false);

下面就到了 ActivityThread 的acquireProvider 这里了,

 public final IContentProvider acquireProvider(
            Context c, String auth, int userId, boolean stable) {
        final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
        if (provider != null) {
            return provider;

        // There is a possible race here.  Another thread may try to acquire
        // the same provider at the same time.  When this happens, we want to ensure
        // that the first one wins.
        // Note that we cannot hold the lock while acquiring and installing the
        // provider since it might take a long time to run and it could also potentially
        // be re-entrant in the case where the provider is in the same process.
        IActivityManager.ContentProviderHolder holder = null;
        try {
          //得到了contentprovider ,ActivityManagerService里面实现
            holder = ActivityManagerNative.getDefault().getContentProvider(
                    getApplicationThread(), auth, userId, stable);getContentProvider
        } catch (RemoteException ex) {
        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,,
                true /*noisy*/, holder.noReleaseNeeded, stable);
        return holder.provider;


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

private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
            String name, IBinder token, boolean stable, int userId) {
    ContentProviderRecord cpr;

    // First check if this content provider has been published...
    cpr = mProviderMap.getProviderByName(name, userId);
    if (!providerRunning) {
        cpi = AppGlobals.getPackageManager().resolveContentProvider(name, STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
    cpr = mProviderMap.getProviderByClass(comp, userId);
    if (firstClass) {
        try {
            ApplicationInfo ai = AppGlobals.getPackageManager().
                getApplicationInfo(cpi.applicationInfo.packageName, STOCK_PM_FLAGS, userId);
            cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
        } finally {
    if (firstClass) {
        mProviderMap.putProviderByClass(comp, cpr);
    mProviderMap.putProviderByName(name, cpr);
    // Wait for the provider to be published... 
    synchronized (cpr) {  
        while (cpr.provider == null) {  
            try {  
    return cpr != null ? cpr.newHolder(conn) : null;




  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 155,770评论 4 358
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,116评论 1 286
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 105,656评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,372评论 0 201
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,704评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,166评论 1 204
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,535评论 2 306
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,259评论 0 193
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,882评论 1 236
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,218评论 2 239
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,760评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,126评论 2 249
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,667评论 3 228
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,935评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,644评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,171评论 2 265
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,119评论 2 258