【问题标题】:Android uploading pictures to server in most efficient wayAndroid以最有效的方式将图片上传到服务器
【发布时间】:2011-07-07 01:34:29
【问题描述】:

我需要将图像和其他数据(非常类似于带有附件的电子邮件)发送到服务器。我还需要以可靠的方式进行操作,以便在失败时重试等。

服务器是 WCF REST 服务器,我与它进行了许多其他通信(JSON),但刚刚收到了上传图像的新要求。

由于我使用 JSON 将数据发布到我的服务器 - 我在 Android 端使用 GSON 来序列化数据。

这是我到目前为止的实现方式(其他一切都是这样工作的,但我只是从图像开始)

  1. 用户填写活动字段(文本数据)
  2. 用户通过相机意图拍摄一些照片。目前我只使用 1 个文件的图片
  3. 我从 SDCard 拍照,加载/调整大小 - 在 ImageView 上显示并存储在 byte[] 中
  4. 用户提交 - 我从 byte[] 获取所有数据以及图像并将其放入 Java 对象中
  5. 调用 GSON 转换器并序列化对象
  6. 将对象保存到 SQLite 中
  7. AsyncTask 在 SQLite 中查找记录,打开游标并获取文本
  8. AsyncTask 创建 HttpConnection 并将文本数据发布到我的服务器。
  9. 结束

现在我的问题.. 显然在#3 - 我用我的字节数组“爆炸” ram。有时我什至觉得我的 Nexus S 变得迟钝。但是通过这样做 - 我避免用许多文件填充 SD 卡或应用程序文件夹。我拍照然后抓住它。下一张图片会覆盖上一张。

第 5 步很慢。我没有在 GSON 上尝试自定义序列化程序,而是将字节数组序列化为 [1,-100,123,-12] 之类的东西,但我可以使用 Base64 获得更小的大小,但仍然如此。它会很慢。我最多可以有 20 张图片...

第 6 步没问题。但是对于一定的尺寸(我尝试了 300px 的图像),我在 OpenCursor 的第 7 步中开始出现错误

07-06 20:28:47.113: ERROR/CursorWindow(16292): need to grow: mSize = 1048576, size = 925630, freeSpace() = 402958, numRows = 2
07-06 20:28:47.113: ERROR/CursorWindow(16292): not growing since there are already 2 row(s), max size 1048576
07-06 20:28:47.113: ERROR/Cursor(16292): Failed allocating 925630 bytes for text/blob at 1,1

所以,这整件事不是我喜欢的。理想情况下,我希望将所有数据一次性上传到服务器。

我在想也许可以将带有时间戳的图像存储在 SD 卡上,并且只将它们的名称存储在 DB 中。比我在发送到服务器之前处理它们。如果成功,我会删除这些图像。这种逻辑会使 SQLite 模式变得更加复杂,但也许没有更好的方法?!

我想我正在寻找处理图像的最佳实践。如何以最少的内存/CPU 使用率进行后续操作:

  1. 拍照
  2. 显示缩略图
  3. 调整大小
  4. 发送到服务器

编辑 1:

目前我正在研究将整个 shizang 作为多部分 MIME 消息上传的可能性。这需要在我的 Android 包中添加一些 JAR。此外,我不确定 Apache 代码加载图像和发送它们的效果如何(我想比我的代码更好) http://okandroidletsgo.wordpress.com/2011/05/30/android-to-wcf-streaming-multi-part-binary-images/

我将不得不在 WCF 端解析所有这些,因为没有办法使用内置的 .NET 框架来完成。

http://antscode.blogspot.com/2009/11/parsing-multipart-form-data-in-wcf.html

如果您尝试过,请告诉我!

编辑 2:

MIME 不好。没有意义,因为它使用 Base64 序列化二进制文件,这是同一件事..

【问题讨论】:

  • 所以你将图片保存到数据库中?这会增加数据库的大小,您的用户会抱怨该应用程序在手机内部存储上占用了太多空间,并且无论如何都会要求 app2sd 支持 - 为什么不将图像保留在 sd 卡上?
  • @denis 我发现 Android 1MB 上的光标大小限制,所以这不仅仅是内部存储的问题,而且我只需将此类数据保存在 SQLite 中即可轻松达到该限制。看起来使用外部存储是处理此类事情的唯一正确方法

标签: android android-image android-imageview


【解决方案1】:

没有人回答,但这是我很难想象的:

规则 #1:处理图像时 - 避免使用对象/内存。听起来很明显,但事实并非如此。我认为将图像大小调整为 800x600 是可以的。任何更大的东西 - 您可以考虑保持原样,因为可以在更大的文件上执行 http 流,但是当您将图像加载到内存中进行处理时,很难处理 OOM 异常

规则 #2:使用 GSON 时 - 使用 JsonWriter 填充流。否则内存会爆炸。比将该流传递给 HttpClient。 JsonWriter 将分块写入,数据将在处理过程中发送。

规则#3:见规则#2。它适用于多个小图像。这样,GSON 将一个接一个地序列化它们并输入到流中。无论如何,每个图像都会被加载到内存中。

规则 #4:这可能是最好的解决方案,但需要与服务器进行更多协调。在将消息发送到服务器之前,图像被 1 个 1 发送。它们作为流发送,没有任何编码。这样它们就不必进行 base64 编码,也不必加载到设备的内存中。传输的大小也会更小。当所有图像发送 - 发布主要信息对象并在服务器上收集所有包。

规则 #5:忘记在 SQLite 中存储 BLOB

底线:

  • 在不调整大小的情况下发送图像的资源要便宜得多。仅当图像达到大约 800x600-ish 时,调整大小才有意义
  • 当图像变得像 600x400-ish 这样的小图像时,在一个包中发送多个图像是有意义的
  • 只要您需要上传文件 - 就开始考虑无处不在的流。不要将东西加载到内存中。

【讨论】:

  • 嘿 Katit,谢谢,听起来合乎逻辑。设备和服务器端是否有sn-p?我想将图像上传到服务器。我现在正在使用 php。
猜你喜欢
  • 2018-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-11
  • 2014-06-05
  • 2011-05-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多