使用ContentProviderClient与ContentResolver来访问内容提供者

Android内容提供者的文档描述了使用从getContentResolver()获得的ContentResolver来访问内容。

但是也有一个ContentProviderClient ,它可以从getContentResolver().acquireContentProviderClient(authority) 。 似乎在ContentResolver提供了或多或less相同的方法来访问提供者的内容。

什么时候应该使用ContentProviderClient而不是直接使用ContentResolver ? 有什么好处?

你的android设备有很多数据库,每个数据库都由一个唯一的内容pipe理机构来标识。 这是内容中的“域名”等效部分:// uri – 第一个斜杠之前的所有内容。

ContentResolver存储提供从String contentAuthorityContentProvider的映射的数据。 当你调用ContentResolver.query()update()或你有什么时,URI被分解成组件,contentAolicystring被标识,contentResolver必须search匹配的string,然后将查询指向正确的提供者 这种昂贵的search在每次调用期间都会发生,因为URI可能与调用呼叫不同,具有不同的contentAuthority。 此外,设置和拆除与特定提供商的连接可能会涉及一些成本 – 不能在通话期间重复使用。 我不确定那里涉及的开销,这是一些非常深的OS级代码。

相反,当你调用acquireContentProviderClient(authority) ,那个“我需要什么提供者?” 查找一次就完成了,并且给你一个ContentProviderClient ,它实质上是一个到ContentProvider的直接链接。 (你和提供者之间有一点粘连,涉及到跨线程通信和并发locking)。 但是,当您使用ContentProviderClient ,您将根据您请求的权限直接与提供程序通话。 这消除了不断重新计算“我想要哪个提供者?”的浪费。

注意:每获得一个ContentConviderClient()文档 :如果你获得一个ContentProviderClient, “调用者必须通过调用ContentProviderClient.release()来表明他们已经完成了,这将允许系统释放提供者它确定没有其他保持活跃的原因“。 所以本质上,将一个陈旧的客户端打开将迫使提供者继续作为服务在后台运行。 所以,记得清理!

概要:

许多调用不同的contentAuthorities:使用ContentResolver

重复调用同一个权限:获取并使用ContentProviderClient 。 请记住在完成时释放()它。

好的,但请注意,只有在与Activity相同的进程中运行ContentProvider时,它才有效。

注意来自方法getLocalContentProvider()文档:

如果ContentProvider在不同的进程中运行,则返回null。 如果您知道您在与提供程序相同的进程中运行,并希望直接访问其实现细节,则可以使用此方法。

我认为另一个导入区别是ContentProviderClient可以被转换成你的自定义提供者对象并访问除CRUD之外的其他方法。

 ContentProvider cp = getContentResolver().acquireContentProviderClient(mCurUri).getLocalContentProvider(); yourProvider fld = (yourProvider)cp; fld.query(...); // you can query as ContentResolver fld.addFolder(newFolder); // also can invoke the extend method of your custom ContentProvider 

我发现了以下区别:我在应用程序A中编写了自己的自定义contentprovider。我在应用程序B中编写了一个主屏幕Widget。当我尝试通过ContentResolver从我的窗口小部件访问应用程序A的ContentProvider时,发现“找不到提供程序信息“错误。 当我反而通过ContentResolver获取ContentProviderClient并通过ContentProviderClient查询时,它将工作。 我不得不改变别的,只使用ContentProviderClient而不是ContentResolver。 我对这种行为没有真正的解释,也没有在互联网上find任何信息,至于为什么它是这样的。 我不知道,如果这是一个小部件的特殊怪癖,因为我没有尝试从应用程序B中的活动(应用程序B是一个小工具,没有活动)。

ContentProviderClient的用法之一是有助于访问ContentProvider的一些testing方法。 例如我在unit testing中使用shutdown()方法来避免多个testing实例化多个内容提供者。

像这样实现ContentProvider#shutdown()

 @Override public void shutdown() { openHelper.close(); super.shutdown(); } 

在testing方法结束时,使用ContentProviderClient调用shutdown()来清理testing,以便其他testing可以使用内容提供者:

 getContext() .getContentResolver() .acquireContentProviderClient(URI) .getLocalContentProvider() .shutdown();