8

サーバーに他のデータ (添付ファイル付きの電子メールに非常に似ています) と一緒に画像を取得する必要があります。また、失敗したときに再試行できるように、信頼できる方法で行う必要があります。

サーバーはWCF RESTサーバーであり、私はそれ(JSON)と他の多くの通信を行いますが、画像をアップロードするためのこの新しい要件を取得しました.

JSON を使用してデータをサーバーに投稿するため、Android 側で GSON を使用してデータをシリアル化します。

これまでに実装した方法は次のとおりです(他のすべてはこのように機能しますが、画像から始めたばかりです)

  1. ユーザー入力アクティビティ フィールド (テキスト データ)
  2. ユーザーはカメラ インテントを介して写真を撮ります。現在、写真用に1つのファイルを使用しています
  3. SDカードから写真を撮り、ロード/サイズ変更します-ImageViewに表示し、バイト[]に保存します
  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

だから、この全体は私が好きなものではありません。理想的には、すべてのデータを 1 つにまとめてサーバーにアップロードする必要があります。

タイムスタンプ付きの画像をSDカードに保存し、その名前だけをDBに保存することを考えていました。サーバーに送信する直前にそれらを処理するよりも。成功したら、それらの画像を削除します。この種のロジックは SQLite スキーマをより複雑にしますが、これ以上の方法はないのではないでしょうか?!

画像を処理するためのベストプラクティスを探していると思います。最小限のメモリ/CPU 使用率でフォローインを行う方法:

  1. 写真を撮る
  2. サムネイル表示
  3. サイズ変更
  4. サーバーに送信

編集1:

現在、シザン全体をマルチパート MIME メッセージとしてアップロードする可能性を調査しています。それには、私の Android パッケージにいくつかの JAR を追加する必要があります。また、画像をロードして送信するためのApacheコードがどれほど効果的かはわかりません(私のコードよりも優れていると思います) http://okandroidletsgo.wordpress.com/2011/05/30/android-to-wcf-streaming-マルチパートバイナリイメージ/

そして、組み込みの.NETフレームワークではこれを行う方法がないため、WCF側でこれらすべてを解析する必要があります。

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

これを試したら教えてください!

編集2:

MIME はダメです。同じものであるBase64を使用してバイナリをシリアル化するため、意味がありません..

4

1 に答える 1

16

誰も答えませんでしたが、ここに私が難しい方法で考え出したものがあります:

ルール #1: 画像を扱う場合 - オブジェクト/メモリの使用を避ける。明白に聞こえますが、そうではありません。画像のサイズを 800x600 に変更しても問題ないと思いました。それより大きいもの - そのままにしておくことを検討してください。より大きなファイルで http ストリームを実行することは可能ですが、処理のために画像をメモリにロードするときに OOM 例外を処理するのは難しいためです。

ルール #2: GSON を使用する場合 - JsonWriter を使用してストリームに入力します。そうしないと、メモリが爆発します。そのストリームを HttpClient に渡すより。JsonWriter はチャンクで書き込み、処理中にデータが送信されます。

ルール #3: ルール #2 を参照してください。複数の小さな画像でも問題なく動作します。このようにして、GSON はそれらを 1 つずつシリアル化し、ストリームにフィードします。とにかく、各画像はメモリにロードされます。

ルール #4: これはおそらく最良の解決策ですが、サーバーとの調整がさらに必要です。メッセージがサーバーに送信される前に、画像が 1 つずつ送信されます。エンコードなしでストリームとして送信しました。この方法では、base64 でエンコードする必要がなく、デバイスのメモリにロードする必要もありません。送信サイズも小さくなります。すべての画像が送信されたら - 主な情報オブジェクトを投稿し、すべてのパッケージをサーバーにまとめます。

ルール #5: BLOB を SQLite に格納することを忘れる

結論:

  • サイズを変更せずに画像を送信する方が、リソースの点ではるかに安価です。サイズ変更は、画像が約 800x600 程度になる場合にのみ意味があります
  • 複数の画像を 1 つのパッケージで送信することは、画像が 600x400 のように小さい場合に意味があります。
  • ファイルをアップロードする必要があるとすぐに、どこでもストリームを考え始めます。ものをメモリにロードしないでください。
于 2011-07-11T14:41:57.913 に答える