使用ContentProviderClient和ContentResolver访问内容提供程序

RTS*_*lio 63 android android-contentresolver android-contentprovider

Android内容提供商文档描述了使用ContentResolver,从中获取getContentResolver(),访问内容.

然而,还有一个ContentProviderClient,可以从中获得getContentResolver().acquireContentProviderClient(authority).它似乎提供了或多或少相同的方法,ContentResolver用于从提供者访问内容.

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

jcw*_*ger 92

您的Android设备有许多数据库,每个数据库都由唯一的内容管理机构标识.这是内容中的"域名"等效部分:// uri - 第一个斜杠之前的所有内容.

ContentResolver存储数据从提供映射String contentAuthorityContentProvider.当您调用ContentResolver.query()update()拥有什么时,URI将被分解为其组件,标识contentAuthority字符串,并且contentResolver必须在该映射中搜索匹配的字符串,并将查询定向到正确的提供者.这种昂贵的搜索发生在每次调用期间,因为URI可能与呼叫不同,具有不同的contentAuthority.此外,设置和拆除与特定提供商的连接可能会涉及一些成本 - 它不能在呼叫之间重复使用.我不确定那里涉及的开销,这是一些相当深的操作系统级代码.

相比之下,当你打电话acquireContentProviderClient(authority)时,"我需要什么提供者?" 查询已完成一次,并且您将获得一个ContentProviderClient基本上是指向的链接ContentProvider.(您和提供程序之间存在一些涉及跨线程通信和并发锁定的粘合剂).但是,在您使用时ContentProviderClient,您将直接与提供商讨论您请求的权限.这消除了不断重新计算"我想要哪个提供商?"的浪费.

注意:每个acquireContentProviderClient()文档:如果您获得ContentProviderClient,"调用者必须通过调用ContentProviderClient.release()来指示他们已完成提供程序,这将允许系统释放提供程序,它确定没有其他让它保持活跃的原因." 因此,实际上,将陈旧的客户端保持打开状态将迫使提供程序在后台继续作为服务运行.所以,记得清理!

摘要:

许多人呼吁改变内容权限: 使用ContentResolver.

重复呼叫同一权限: 获取并使用ContentProviderClient.记得在完成后释放()它.

  • 我会在每个活动的基础上保持它.如果您正在进行单个查询并保留游标,就像您使用CursorAdapter绑定到ListView一样,那么请不要打扰 - 只需直接转到解析器即可.如果您执行该模型,ContentObservers将确保在基础数据库更改时发生自动更新.这是一个很好的模型. (5认同)
  • 谢谢.我很好奇保持一个`ContentProviderClient`多久.我有一个应用程序浏览特定提供商的内容; 它包括许多活动.我可以在每个活动中获取并释放它,可以在`onCreate` /`onDestroy`或`onStart` /`onStop`; 或者我可以在"应用程序"级别缓存一个副本,该副本仅在所有活动(或根活动)被销毁时释放.有什么想法吗? (3认同)

Jok*_*kii 7

好的,但请注意,仅当ContentProvider在与Activity相同的过程中运行时,它才有效.

方法文档说明getLocalContentProvider():

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


小智 6

我认为另一个重要区别是 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
Run Code Online (Sandbox Code Playgroud)