【问题标题】:Android: looking for effective strategy of copy/paste of complex objectsAndroid:寻找复制/粘贴复杂对象的有效策略
【发布时间】:2012-08-29 07:41:47
【问题描述】:

我正在设计一个适用于复杂对象列表的 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)复制到剪贴板。在这种情况下,我无法在粘贴到自己的应用程序时保留对象的属性。

有什么想法吗?

【问题讨论】:

    标签: android copy-paste clipboardmanager


    【解决方案1】:

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

    粘贴为文本

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

    粘贴为图片

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

    实现query 以返回一个游标,其中包含一个名为MediaStore.Images.ImageColumns.DATA 的列(的值)。如果您想将元数据提供给这些客户端,您还可以包含来自 MediaStore.Images.ImageColumns 的其他列。

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

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

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

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

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

    结论

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

    【讨论】:

    • 你有复制图片的例子吗? @丹·赫尔姆
    猜你喜欢
    • 1970-01-01
    • 2019-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多