使用 aContentProvider
是正确的做法。其他应用不需要了解内容的结构或组织:内容 URI 可以用作不透明的标识符,并且(在 API 11 及更高版本中)一个 URI 可以有多种类型。
粘贴为文本
如果您实施ContentProvider.openTypedAssetFile
,您的提供商可以将图像提供给请求图像的客户端,并将您的内部数据格式提供给请求您的供应商特定 MIME 类型的客户端。这是ClipData.Item.coerceToText
用于从任意内容 URI 获取文本的机制:它请求 type text/*
,并将返回的流读入字符串。(不要尝试复制无限的文本流!)如果此调用失败,它只会放置 URI 本身的文本。旧版getText
APIcoerceToText
也使用此功能。这会整理出您的旧版和纯文本客户端。
粘贴为图像
只需要图像的客户端应该使用与上述相同的机制,这意味着您ContentProvider.openTypedAssetFile
将用作文本,但请求类型为image/*
. 但我不认为您可以依赖每个客户端都这样做,所以我建议您实现ContentProvider.getType
并ContentProvider.getStreamTypes
返回该 URI 的图像类型(而不是您的供应商特定类型)。
实现query
以返回带有名为 (the value of) 的列的游标MediaStore.Images.ImageColumns.DATA
。MediaStore.Images.ImageColumns
如果您想将元数据提供给这些客户端,您还可以包含其他列。
然后你只需要实现openFile
为图像返回一个文件描述符。请务必检查mode
参数以避免让其他应用程序能够写入您的文件。您可以调用ParcelFileDescriptor.open
以创建ParcelFileDescriptor
您需要从您拥有的路径返回的内容。
粘贴为特定于供应商的对象
这就是处理您服务的所有第三方客户。现在粘贴到您自己的应用程序中怎么样?你可以在这里做两件事。正如我在上一节中提到的,您可以使用ContentResolver.openTypedAssetDescriptorFile
来请求您的供应商特定类型,并实现ContentProvider.openTypedAssetFile
返回该类型的流。如果您的应用程序特定数据是包含序列化数据等的特殊类型的文件,则这是合适的。如果您的特定于应用程序的内容是数据库行,那么您可以使用query
: 它可以将您喜欢的任何特定于应用程序的数据放入返回的游标中,以及MediaStore
上面讨论的列。
这些方法中的任何一种都提供了一种方便的方法,可以ContentProvider
用来从存储机制中抽象出前端。我在一个应用程序中实现共享时这样做了,这是一个非常积极的变化,强加了一个清晰的边界,并迫使我清理我对数据库的所有偷偷摸摸的、违反封装的访问,从而使代码库更易于维护. Loader
它还使在s、Adapter
s 和s中使用内置支持变得更容易,ContentObserver
以减少我的前端代码的大小。
但也许这个强制封装边界对您的应用程序来说是错误的,或者您的粘贴目标需要访问相同的 Java 对象,而不仅仅是游标或序列化数据。在这种情况下,粘贴目标中的代码很容易解析粘贴的 URI 并从中读取标识符。然后它可以直接与您的后端代码对话(使用您拥有的任何现有机制)以获取对相关数据对象的引用:它根本不需要使用ContentResolver
。
结论
所有这一切似乎都像是一大罐要打开的蠕虫,在某种程度上确实如此。但ContentProvider
如果你只想做一件事,实际上很容易实现,一旦你开始使用它,你可能会发现它可以帮助你解决的其他问题。