ContentProvider query操作过程源码分析(Android Q)

ContentProvider query操作过程源码分析(Android Q)ContentProvi 调用过程源码分析 AndroidQ ContentProvi 是 Android 的四大组件之一 可以很方便的跨进程查询数据 那么 Android 系统是如何实现 ContentProvi 的查询等操作的呢 ContentProvi 的使用示例我们首先来看一个 ContentProvi 调用示例 publicvoidre Stringselect Cursorcursor

ContentProvider query调用过程源码分析(Android Q)


ContentProvider 是 Android 的四大组件之一,可以很方便的跨进程查询数据,那么 Android 系统是如何实现 ContentProvider 的查询等操作的呢?

ContentProvider 的使用示例

我们首先来看一个 ContentProvider 调用示例:

 public void readData(String selection) { Cursor cursor = null; try { cursor = context.getContentResolver() .query(getTableUri(), null, selection, null, null); …… } catch (Exception e) { LogX.e(TAG, SUB_TAG, getName() + "; " + e.toString()); } } 

这里通过 context 对象的 getContentResolver() 方法,就可以操作 ContentProvider 存储的数据了,如何实现的呢?我们通过源码来分析整个过程。

ContentResolver

ContentResolver 类是一个很关键的类,我们实际使用 ContentProvider 的数据时,都是通过该类的实例来操作的。

ContextImpl 的 getContentResolver() 方法

我们来看 context.getContentResolver(),这里的 context 的实现类是 ContextImpl类(不清楚的可以查看前文),源码如下:

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

这里直接返回了一个 ContentResolver 对象,该对象是什么呢?又是在哪赋值的呢?

ContentResolver 对象的创建
 @UnsupportedAppUsage private final ApplicationContentResolver mContentResolver; private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread, @NonNull LoadedApk packageInfo, @Nullable String splitName, @Nullable IBinder activityToken, @Nullable UserHandle user, int flags, @Nullable ClassLoader classLoader, @Nullable String overrideOpPackageName) { …… mContentResolver = new ApplicationContentResolver(this, mainThread); } 

mContentResolver 是 ApplicationContentResolver 的一个实例对象,它在 ContextImpl 构造函数中创建的。ApplicationContentResolver 类是 ContextImpl 的一个内部类。

ContentResolver 的 query 方法
 @Override public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri, @Nullable String[] projection, @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal) { …… //获取目标 ContentProvider 对象。 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) { cancellationSignal.throwIfCanceled(); remoteCancellationSignal = unstableProvider.createCancellationSignal(); cancellationSignal.setRemote(remoteCancellationSignal); } try { //调用目标 ContentProvider 对象的 query 方法查询数据。 qCursor = unstableProvider.query(mPackageName, uri, projection, queryArgs, remoteCancellationSignal); } catch (DeadObjectException e) {//ContentProvider 所在进程已死 // 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); stableProvider = acquireProvider(uri); if (stableProvider == null) { return null; } qCursor = stableProvider.query( mPackageName, uri, projection, queryArgs, remoteCancellationSignal); } if (qCursor == null) { return null; } …… //将 Cursor 对象包装到 CursorWrapperInner 对象中。 final IContentProvider provider = (stableProvider != null) ? stableProvider : acquireProvider(uri); final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider); stableProvider = null; qCursor = null; return wrapper; } …… } 

ContentResolver 的 query 方法主要做了以下几个操作:

  1. 获取目标 ContentProvider 对象。
  2. 调用目标 ContentProvider 对象的 query 方法查询数据。
  3. 将 Cursor 对象包装到 CursorWrapperInner 对象中,并返回。

这里的关键点是,如何获取目标 ContentProvider 对象,也就是 acquireUnstableProvider 方法的实现。

acquireUnstableProvider 方法是由 ContentResolver 的子类 ApplicationContentResolver(ContextImpl 的一个内部类)实现的。

acquireUnstableProvider 方法
 private final ActivityThread mMainThread; @Override protected IContentProvider acquireUnstableProvider(Context c, String auth) { return mMainThread.acquireProvider(c, ContentProvider.getAuthorityWithoutUserId(auth), resolveUserIdFromAuthority(auth), false); } 

其实,这里直接调用了主线程对象 ActivityThread 对象的 acquireProvider 方法。

ActivityThread 对象的 acquireProvider 方法

 public final IContentProvider acquireProvider( Context c, String auth, int userId, boolean stable) { //如果 ContentProvider 已经安装,则直接从缓存中获取即可。 final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable); if (provider != null) { return provider; } …… ContentProviderHolder holder = null; try { synchronized (getGetProviderLock(auth, userId)) { //调用 AMS 获取 ContentProvider 对象。 holder = ActivityManager.getService().getContentProvider( getApplicationThread(), c.getOpPackageName(), auth, userId, stable); } } …… //安装、发布 ContentProvider 对象。参考:https://blog.csdn.net/u0/article/details/ holder = installProvider(c, holder, holder.info, true /*noisy*/, holder.noReleaseNeeded, stable); return holder.provider; } 
  1. 如果 ContentProvider 已经安装,则直接从缓存中获取即可。
  2. 调用 AMS 获取 ContentProvider 对象(远程)。
  3. 安装、发布 ContentProvider 对象。参考:https://blog.csdn.net/u0/article/details/

完成后,ContentProvider 已经准备好了,之后的调用,我们都可以通过 ActivityThread 对象的 acquireProvider 方法,直接从缓存中获取了。


PS:更多精彩内容,请查看 –> 《Android底层原理解析》
PS:更多精彩内容,请查看 –> 《Android底层原理解析》
PS:更多精彩内容,请查看 –> 《Android底层原理解析》




版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/212027.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午9:00
下一篇 2026年3月18日 下午9:00


相关推荐

  • qt 气泡聊天界面_微信聊天气泡框素材

    qt 气泡聊天界面_微信聊天气泡框素材目录由于最近的项目需要,做了些相关IM的工作。所以聊天框也是必不可少的一部分。聊天框的制作分很多种,本文以QListWidget+QPainter绘制的Item做了一个Demo。该Demo只是做一个示例,代码已公布如下,需要的拿去!目录效果图实现原理调用样例实现类代码分享效果图实现原理气泡式聊天的显示是由QListWidget作为控件,每个…

    2022年5月3日
    57
  • erlang如何有效地监视大量的并发连接

    erlang如何有效地监视大量的并发连接

    2021年12月30日
    43
  • 2025 AI应用年终观察:从生活助手到职场利器,谁在重塑未来?

    2025 AI应用年终观察:从生活助手到职场利器,谁在重塑未来?

    2026年3月14日
    3
  • 美化包软件_彩色音量进度条插件下载

    美化包软件_彩色音量进度条插件下载前言在我们进行自动化测试的时候,用例往往是成百上千,执行的时间是几十分钟或者是小时级别。有时,我们在调试那么多用例的时候,不知道执行到什么程度了,而pytest-sugar插件能很好解决我们的痛点。

    2022年7月28日
    5
  • java IO流详尽解析「建议收藏」

    java IO流详尽解析「建议收藏」流的概念和作用,好吧,百度了一张图片,不错学习JavaIO,不得不提到的就是JavaIO流。流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。IO流的分类根据处理数据类型的不同分为:字符流和字节流根据数据流向不同分为:输入流和输出流字符流和字节流字符流的由

    2022年5月22日
    40
  • 微端传奇怎么架设_架设

    微端传奇怎么架设_架设1.首下载gmqd引擎包。解压出来,找到里面(微端服务器),里面有两个文件夹,一个是微端程序,一个是微端网关,接下来,把微端程序文件里面的四个文件,复制到微端服务器电脑上面的,热血传奇客户端里面}。见下图2.然后运行updateserver.exe这个程序,等运行完后,看看里面是否加载到补丁文件3.如果都加载到客户端里面的补丁文件。那么微端程序已经运行成功了,要注意的是,PAK格式补丁。如果你的服有要用到PAK格式补丁,那么就要微端程序里面设置PAK补丁密码。见下图4.记住只要在明文密码处,输入PAK补

    2022年10月6日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号