2

わかりました、私はしばらくの間、この問題を解決するための最善の方法を研究してきました.

ニーズ:

  • アクティビティ [SendMsg] は、最大 5 MB の画像の添付ファイルを含むメッセージ本文を構成します。
  • ユーザーがこのメッセージを送信したら、メッセージをサーバーにアップロードする必要があります
  • このアップロードは、完了するか失敗するまでユーザーがアプリを使用できないようにするという意味で、同期的に行う必要があります
  • 完了すると、送信が成功した場合は SendMsg アクティビティが破棄されます。それ以外の場合は、エラー ダイアログが表示されます。
  • アップロードとユーザー エクスペリエンスは、電話のローテーションやホーム ボタンの押下/通話などを考慮して持続する必要があります。

ここでの最後の箇条書きが最も難しいことが判明しました。

調査結果:

静的な AsyncTask で作業を行うことだけを考えましたが、それがうまくいくとは思いません-状態が非常に乱雑になり、アプリがバックグラウンドにあるときにOSがスレッドを強制終了しないという保証がないようです.

私は、サービスが作成され、アクティビティからバインド/アンバインドされるサービスを使用することにしました。サービスは AsyncTask を生成し、作業を実行してから、その結果 (成功/失敗) に従ってアクティビティに通知します。このパラダイムは、私の大きなメッセージを除いてうまく機能しているようです。Service/Activity 通信 Message 通信は、このような大きなペイロードをマーシャリングするためのものではありません。*注意: 不明な場合は、ユーザーが [送信] をクリックしたときに、このフォーム データとファイルをサービスで利用できるようにする必要があります。場合によっては、これはカメラから取得した画像であり、アプリの目的でディスク上に存在することも、存在することもできません。

明らかに、ここで必要なのは、アクティビティからデータを保存できるある種の共有メモリ ストアです。その後、Activity は Service に、そのデータをアップロードできることを知らせることができます。

そのような共有領域はメモリ内に存在できますか? Service から Application オブジェクトを取得して、そこにデータを保存できますか?

もう1つの問題は、アップロードが終了したときに発生しますが、アクティビティがサービスにバインドされていませんが、これを理解した可能性があると思います. 次の意味があるかどうか教えてください。

  1. サービスはアップロードを終了します
  2. アクティビティが現在バインドされているかどうかを確認するサービス
  3. はいの場合、アクティビティがメッセージ キューを介して処理するエラー メッセージを返します
  4. いいえの場合は、その共有メモリ領域に戻りコードを保存し、そこにもブール値のフラグを立てます
  5. クライアント アクティビティが作成/再開されるときは、最初に常にこのブール値をチェックして、プロセスが既に完了しているかどうかを確認する必要があります。その場合は、メッセージを独自のハンドラーにディスパッチし、以前と同じようにコードを処理します
4

3 に答える 3

4

メモリ要件に対処するためにMap、メッセージの詳細をすべて保持するホルダー クラスに UUID を使用することになるでしょう。これをサブクラス Mapのメンバー変数として、または静的変数として保存します。タスクが完了または失敗したときに、これを必ずクリアしてください。このタイプの複数のリクエストが同時に進行しないことが確実な場合は、マップまたはリストの代わりに単一のクラスを使用できます。Application

次に、 WakeLock の助けを借りて、 IntentService を使用して要件を達成できます。画面の回転により操作が難しいため、Android でバインドされたサービスを避ける傾向があります。を開始するインテントで Map から識別子を渡すだけです。IntentService

私の意見では、Service から Activity に通信する最良の方法は、PendingIntent. 基本的に、アクティビティからサービスを開始し、サービスをPendingIntent開始するインテントに a を渡します。サービスが作業を終了するか失敗するとsend()、PendingIntent を呼び出します。次に、Activity はそのonActivityResult()メソッドでコールバックを取得します。

これにはいくつかの利点があります。

  • それは自明にスレッドセーフです。の別のスレッドで実行時間の長いタスクIntentServiceを取得し、完了時に UI スレッドで通知を受け取ります。
  • 画面回転にも対応!必要に応じてアクティビティを回転させることができますが、それでもコールバックを取得できますonActivityResult()。逆に、finish()Activity で PendingIntent が送信される前に新しいアクティビティを開始したとしても、それは配信されません。これはほとんどの場合、希望どおりです。

このアプローチを示すデモアプリケーションがあります。基本的に、いくつかの作業を開始するアクティビティがあり、進行状況ダイアログで UI をブロックします。画面が回転すると、このダイアログが再度表示されます。作業はServiceで行われPendingIntent、Activity に送り返されます。

仕事の最後の部分は、アップロードの実行中にデバイスがスリープ状態にならないようにすることです。Mark Murphy は、 を使用して作業が中断されないようにする良い例Service の実装を書いています。WakeLock

于 2012-12-05T18:15:22.943 に答える
1

まず、サービスを呼び出しでトリガーするフォアグラウンド サービスに切り替える必要がありますstartService()(サービスにバインドするのではなく)。これにより、サービスが可能な限り長く維持されます。サービスにバインドすると、アクティビティが終了するとサービスが停止します (ユーザーがアプリを離れたときに発生する可能性があります)。

また、フォアグラウンド サービスで使用される通知を利用して、ユーザーにアップロードのステータスを知らせます。

サービスからアクティビティに情報を戻すには、ResultReceiver クラスを調べることができます。具体的には、Google が IO アプリケーションの 1 つに実装した DetachableResultReceiver パラダイムを調べてください。

通信要件に加えて大量のメモリ要件があるため、シングルトン オブジェクトを作成して、アクティビティとサービスの間でデータと状態を共有したい場合があります。

于 2012-12-05T18:01:43.987 に答える
0

静的変数を持つクラスを作成し、アクティビティがすべての値をそのクラスに設定できるようにします。次に IntentService を開始し、そのサービスが上記のクラスを調べられるようにします。IntentService がメッセージを処理すると、メッセージがブロードキャストされ、ブロードキャストを待機しているアクティビティがある場合は、メッセージが受信されます。

于 2012-12-05T18:01:14.610 に答える