源码分析之ContentProvider 启动

本文详细分析了Android中ContentProvider的启动过程,从ContentProvider的作用、查询流程开始,逐步深入到源码层面,包括query方法的调用、AMS的交互、ContentProvider的安装和启动等关键步骤,揭示了Android系统中进程间数据交互的实现机制。
摘要由CSDN通过智能技术生成

标题前言

我们熟知一般 Android 工程师都是在应用层上开发,不会涉及系统源码,但是如果你想往底层发展,或者深入插件化、Framework 系统层等开发工作,如果不了解 Android 源码可是不行的,那么接下来我基于自己的理解跟学习来记录跟 Android 开发息息相关的源码分析,大概从 Android 中的 SystemServer 启动、四大组件启动、AMS、PMS 等几个维度来介绍,下面是我的计划,当然在未来也有可能改变。

介绍

ContentProvider (内容提供者) 属于四大组件之一,可以说它是在四大组件中开发者使用率最少的一个,它的作用就是进程间进行数据交互,底层采用 Binder 机制进行进程间通信。使用方式我这里就不在具体说明了,想要了解使用的可以参考 [Android:关于ContentProvider的知识都在这里了!(https://blog.csdn.net/carson_ho/article/details/76101093) 下面我们就以分析 ContentProvider 工作流程为主来进行全面分析。

源码分析

query 到 AMS 调用过程

下面先来看一个代码示例,代码如下:

```
fun getContactsLists(): MutableList<String> {
    var contactsLists: MutableList<String> = mutableListOf<String>()
    lateinit var cursor: Cursor
    try {
    //使用 getContentResolver() 查询联系人列表
    cursor = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null)
    //对 cursor 进行遍历
    if (cursor != null) {
        while (cursor.moveToNext()) {
    //获取姓名
        val displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME))
    //电话号码
        val number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
        contactsLists.add("姓名:$displayName 电话:$number")
        }
    }
cursor.close()
    } catch (error: Exception) {
        logger.error("error:$error")
    }
    return contactsLists
}

//测试
val contactsLists = getContactsLists()
contactsLists.forEach { it -> println("通过ContentResolver获取联系人: $contactsLists") }

```

上面代码就是通过内容提供者来获取手机中的通讯录列表,输出为:

I/System.out: 通过ContentResolver获取联系人: [姓名:Xiao 电话:110, 姓名:ming 电话:112, 姓名:华为客服 电话:4008308300]

那么这一流程内部是怎么运行的,这才是我们这篇文章主要分析内容,有没有发现上面代码示例是用 kotlin 代码写的例子。

老规矩,还是先看一下该小节分析流程,这里以时序图为主

通过上面代码示例想要 query 数据先要拿到 contentResolver 对象,通过父类 getContentResolver()方法获得,代码如下:

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

这里的 mBase 是 Context 对象,根据前面几篇文章我们知道,它的实现类就是 ContextImpl 我们直接看它具体实现,代码如下:

//ContextImpl.java
    @Override
    public ContentResolver getContentResolver() {
        return mContentResolver;
    }

这里的 getContentResolver 方法中返回了 ApplicationContentResolver 对象,它是 ContextImpl 的静态内部类,继承自 ContentResolver ,它在 ContextImpl 的构造方法中被创建,这说明当我们调用它的 query、insert、update 方法的时候,就会启动 ContentProvider,这里以上面我们示例 query 来进行分析,我们看它的具体实现,代码如下:

//ContentResolver.java
    public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
            @Nullable String[] projection, @Nullable Bundle queryArgs,
            @Nullable CancellationSignal cancellationSignal) {
        Preconditions.checkNotNull(uri, "uri");
        /**
         * 1. 拿到 IContentProvider 对象,它是 ContentProvider 的本地代理
         */
        IContentProvider unstableProvider = acquireUnstableProvider(uri);
        if (unstableProvider == null) {
            return null;
        }
        IContentProvider stableProvider = null;
        Cursor qCursor = null;
        try {
            
            try {
                /**
                 * 2. 调用 IContentProvider 的 query 函数来进行 query 
                 */
                qCursor = unstableProvider.query(mPackageName, uri, projection,
                        queryArgs, remoteCancellationSignal);
            } catch (DeadObjectException e) {
                

            //...
            return wrapper;
        } catch (RemoteException e) {
            return null;
        } finally {
            ...
        }
    }

在注释处通过 acquireUnstableProvider 方法拿到 ContentProvider 的本地代理对象,然后注释 2 调用本地代理对象的 query 方法返回一个 Cursor 对象,我们先来看下注释 1 的 acquireUnstableProvider 方法怎么拿到 ContentProvider 本地代理对象,代码如下:


   //ContentResolver.java 
   public final IContentProvider acquireUnstableProvider(Uri uri) {
        if (!SCHEME_CONTENT.equals(uri.getScheme())) {
            return null;
        }
        String auth = uri.getAuthority(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值