3

我正在设计一个适用于复杂对象列表的 Android 应用程序。一个对象包括带有一组属性(例如,重要性级别和上次查看时间)的文本或图形数据。我想通过遵循 3 条规则的复制和粘贴功能来帮助我的应用程序:

  • 当用户复制对象然后将其粘贴到我的应用程序时,将添加具有相同属性的对象的完整副本。
  • 当用户复制一个对象,然后将其粘贴到使用新的复制/粘贴 API (android.content.ClipboardManager) 的其他应用程序时,该应用程序将接收文本或图像,具体取决于对象表示的文本数据还是图形数据。如果是图像,该应用程序将接收文件路径或媒体库内容 URI 形式的图像。
  • 当用户复制一个对象,然后将其粘贴到使用老式已弃用 API (android.text.ClipboardManager) 的其他应用程序时,该应用程序将只接收由该对象表示的文本。如果对象表示图像,则该应用程序将接收文本表示形式的 URI,甚至是空文本。

到目前为止,我已经研究了 Google 文档并浏览了各种编程论坛,但没有找到任何关于如何执行此操作的答案或解释它不可行的解释。目前我有两个弊端可供选择:
1)创建一个与对象一起使用的内容提供者,并将内容URI复制到剪贴板。不幸的是,这意味着第 3 方应用程序,为了检索文本或图像,必须知道我的内容提供者的内部组织,我当然不能假设。
2) 仅将文本数据(类型为 ClipDescription.MIMETYPE_TEXT_PLAIN)或仅复制到图像的 URI(类型为 ClipDescription.MIMETYPE_TEXT_URILIST)复制到剪贴板。在这种情况下,粘贴到我自己的应用程序时,我无法保留对象的属性。

有任何想法吗?

4

1 回答 1

0

使用 aContentProvider是正确的做法。其他应用不需要了解内容的结构或组织:内容 URI 可以用作不透明的标识符,并且(在 API 11 及更高版本中)一个 URI 可以有多种类型。

粘贴为文本

如果您实施ContentProvider.openTypedAssetFile,您的提供商可以将图像提供给请求图像的客户端,并将您的内部数据格式提供给请求您的供应商特定 MIME 类型的客户端。这是ClipData.Item.coerceToText用于从任意内容 URI 获取文本的机制:它请求 type text/*,并将返回的流读入字符串。(不要尝试复制无限的文本流!)如果此调用失败,它只会放置 URI 本身的文本。旧版getTextAPIcoerceToText也使用此功能。这会整理出您的旧版和纯文本客户端。

粘贴为图像

只需要图像的客户端应该使用与上述相同的机制,这意味着您ContentProvider.openTypedAssetFile将用作文本,但请求类型为image/*. 但我不认为您可以依赖每个客户端都这样做,所以我建议您实现ContentProvider.getTypeContentProvider.getStreamTypes返回该 URI 的图像类型(而不是您的供应商特定类型)。

实现query以返回带有名为 (the value of) 的列的游标MediaStore.Images.ImageColumns.DATAMediaStore.Images.ImageColumns如果您想将元数据提供给这些客户端,您还可以包含其他列。

然后你只需要实现openFile为图像返回一个文件描述符。请务必检查mode参数以避免让其他应用程序能够写入您的文件。您可以调用ParcelFileDescriptor.open以创建ParcelFileDescriptor您需要从您拥有的路径返回的内容。

粘贴为特定于供应商的对象

这就是处理您服务的所有第三方客户。现在粘贴到您自己的应用程序中怎么样?你可以在这里做两件事。正如我在上一节中提到的,您可以使用ContentResolver.openTypedAssetDescriptorFile来请求您的供应商特定类型,并实现ContentProvider.openTypedAssetFile返回该类型的流。如果您的应用程序特定数据是包含序列化数据等的特殊类型的文件,则这是合适的。如果您的特定于应用程序的内容是数据库行,那么您可以使用query: 它可以将您喜欢的任何特定于应用程序的数据放入返回的游标中,以及MediaStore上面讨论的列。

这些方法中的任何一种都提供了一种方便的方法,可以ContentProvider用来从存储机制中抽象出前端。我在一个应用程序中实现共享时这样做了,这是一个非常积极的变化,强加了一个清晰的边界,并迫使我清理我对数据库的所有偷偷摸摸的、违反封装的访问,从而使代码库更易于维护. Loader它还使在s、Adapters 和s中使用内置支持变得更容易,ContentObserver以减少我的前端代码的大小。

但也许这个强制封装边界对您的应用程序来说是错误的,或者您的粘贴目标需要访问相同的 Java 对象,而不仅仅是游标或序列化数据。在这种情况下,粘贴目标中的代码很容易解析粘贴的 URI 并从中读取标识符。然后它可以直接与您的后端代码对话(使用您拥有的任何现有机制)以获取对相关数据对象的引用:它根本不需要使用ContentResolver

结论

所有这一切似乎都像是一大罐要打开的蠕虫,在某种程度上确实如此。但ContentProvider如果你只想做一件事,实际上很容易实现,一旦你开始使用它,你可能会发现它可以帮助你解决的其他问题。

于 2013-08-02T13:13:02.023 回答