web-dev-qa-db-ja.com

android設計上の考慮事項:AsyncTaskとService(IntentService?)

次の手順を実行する必要があるAndroidアプリを設計しています。

  1. ユーザーがボタンを押すか、そうでなければ「データの同期」を指示します。
  2. 同期プロセスは、REST Webサービスを使用して、サーバーとの間でデータを移動します。
  3. データはsqliteデータベースにローカルに保存されます。
  4. 同期プロセスは、ステータスの更新/メッセージをUIに提供する必要があります
  5. ユーザーは、アプリケーションの他の部分に移動して、同期プロセス中にさらに作業を行うことを許可されるべきではありません。

同期プロセスを初めて実行するときは、10〜20分かかる場合があります。最初の同期後、転送および保存されるデータは少なくなり、プロセスには1〜2分以下かかると思います。

私はAndroidのAsyncTaskと、サービスのさまざまな使用例についてたくさん読んでいます...しかし、設計上の考慮事項と、一方の設計を他方から選択することのトレードオフを完全には理解していません。私は現在、AsyncTaskを使用してデモプロジェクトを作成しています。見て(ほとんど)開発中Android RESTクライアントアプリケーション: http://code.google.com/events/io/2010/ sessions/developing-RESTful-Android-apps.html# ここで説明したデザインパターンは、「まだ理解していない」ためか、非常に複雑に感じられて混乱しています。

私はJava、Spring、Web、デスクトップアプリケーションのバックグラウンドを持っています。ハンドヘルドデバイスの観点から考えることやデザインすることは、私にとってはまったく新しいことです。 (画面レイアウトが変更されるとどうなりますか?同期の実行中に電話が鳴ったらどうなりますか?)最初の同期が2つ戻ると、ISが非常に長くなります実行中のプロセス、問題->ソリューション、ユーザーエクスペリエンス、電話で実行されているアプリケーションのユーザーの期待について考えるためのより良い方法はありますか?

より多くの経験豊富なAndroidすでにこれらの質問に取り組んできた開発者からの連絡をお待ちしています。

52
tia

私の意見では、これは主流/平均Android開発の中で最もトリッキー/ハードな部分です。たとえばBlackBerryの場合、これはすぐに簡単です。

もちろん、Serviceを使用する必要があります。

AsyncTaskは、Activityハンドルを介してContextに緊密に「バインド」されているため、適していません(そうしないと、ActivityのUIを更新できなくなります] _(AsyncTaskから)。ただし、Activityは、Activityがバックグラウンドになると、OSによって強制終了できます。バックグラウンドに移行する理由の例としては、着信があることが考えられます。ユーザーが電話アプリケーションに切り替えると、Activityが非表示になります。この場合(現在のRAM状態に応じて))、OSはバックグラウンド(ユーザーには見えない)アクティビティの1つを強制終了する場合があります。

一部の開発者は、内部で長時間実行されるアクションを持つために静的なものを配置することによってこれを回避します。 Applicationインスタンスの使用を推奨する人もいます。これは、アプリのプロセス全体が存在する一方で、静的なものとApplicationが存在するためです。ただし、これらは誤った回避策です。 Android内のプロセスも、OSが期限であると判断したときに強制終了される可能性があります。Android OSは、強制終了できる内容と順序について独自の考慮事項を持っています。すべてのプロセスは、「殺しやすさ」の5つのレベルに分けられます ここにドキュメントがあります これらのレベルが指定されている場所です。

サービスを実行しているプロセスは、バックグラウンドアクティビティを持つプロセスよりも上位にランク付けされるため、長時間実行オペレーションを開始するアクティビティは、単にスレッドを生成するのではなく、そのオペレーションのサービスを開始するのに適している可能性があります。アクティビティ。この例としては、バックグラウンドで音楽を再生したり、カメラで撮影した写真をWebサイトにアップロードしたりします。 サービスを使用すると、アクティビティの状況に関係なく、操作が少なくとも「サービスプロセス」の優先順位を持つことが保証されます。

ユーザーが長期実行アクションを開始するActivityには、アクションの実行中にユーザーが他に何もしないようにするためにProgressDialogを表示する必要があります。ガイドは here です。

また、NotificationManagerが現在表示されていない場合は、Activityを使用して、長期実行アクションの完了(または失敗)をユーザーに通知することをお勧めします。以下が NotificationManager info です。

44
Vit Khudenko

状況にどのように対処するかを最適に決定するために考慮しなければならない考慮事項がいくつかあります。 2つのアプローチを適切に比較する必要があるようです...ハンドヘルドデバイスで作業する際に考慮しなければならない類似点、相違点、追加の考慮事項のリストを次に示します。

サービスは、UIを持たないアプリケーションの一部です。起動するためにUI(Activity)によって呼び出される場合と、アプリケーションの他のコンポーネントによって起動される場合があります。開発時には、別のスレッドに配置したり、別のタスクまたはプロセスで実行したりすることもできます。これにより、最終的にUIから分離できます。さらに、必要に応じて、サービスを開始して独立して実行する(startService)か、アクティビティをバインドする(bindService)ことができます。カスタムハンドラーを使用することにより、コールバックを設定して、進行状況に応じてUIを更新できます。サービスは、ユーザーがアクティビティを変更した場合に必ずしも終了するわけではありませんが、OSによっていつでも終了する場合があります。

AsyncTaskは常にUIスレッドからインスタンス化されます。特定のコールバックのみを許可しますが、本質的にアクティビティによって実行されるアクションに関連付けられている(専用の個別のスレッドサービスと比較して)比較的短いトランザクションのために、マルチスレッドのプロセスを簡素化します。ユーザーがアクティビティを変更すると、AsyncTaskが「一時停止」され、アクティビティのUIスレッドがなくなったために停止することもあります。

私が最も心配することは、アプリが最初に10〜20分かかる場合、ユーザーがタスクを一時的に変更するか、完了するまで電話を下​​に置くと想定します(これにより、電話が眠っている場合と同じ合併症)。この点を考慮すると、アクティビティにバインドされたスレッド化されたサービスが最良の選択になる場合があります。 UIを保護するために、進行状況コールバックを受け取るアクティビティの進行状況ダイアログを作成します。これにより、アプリでのユーザー入力が制限され、サービスが必要な方法を継続できるようになります。次に、アクティビティのonResumeをオーバーライドして、サービスのステータスと実行中かどうかを確認します。その後、ダイアログをすぐにリセットできます。

これが私の好ましい方法であることを考えると、OSがいつでもアプリを強制終了する可能性があることも考慮に入れます。そのため、不完全な同期または部分的な同期を検出する方法があることを確認してください。その後、アクティビティまたはサービスの再起動時に自動的に再開できます。

12
Fuzzical Logic

AsyncTaskを使用すると、ユーザーが別のアクティビティに移動した場合、そのオブジェクトを他のアクティビティに転送できないため、そのオブジェクトは終了します。ユーザーが画面を回転させたときなどに再生できるトリックはありますが、それは汎用的な破壊には及ばないものです。 AsyncTaskはランダムに死ぬ可能性があります。

Google Syncは、同期が完了するまでに時間がかかることがあるため、サービスとしてバックグラウンドで実行されます。それらのパスに従い、通信できる独自の同期サービスを作成する必要がある場合があります。これを実現する方法について、いくつか考えてみます。

http://mylifewithandroid.blogspot.com/2008/01/about-binders.html

あなたは間違いなくサービスとアクティビティの間で通信することができますが、それを正しく行うのは難しいです。

5
chubbsondubs

選択は主にアプリのデザインに依存します。 AsyncTaskとIntentServiceの両方が土台を固めているため、アプリ(ユーザーエクスペリエンス)から何を望むかがより重要であり、どちらかまたは両方を選択します。いくつかのシナリオを以下に示します(主にアプリの開発中に経験したもの)

  • フィードページがあるアプリを想定します。ページを表示可能にするために複数のAPI呼び出しが行われる場合(/ getFriends、/ getDates、/ getPicturesなど)、そのようなすべてのAPI呼び出しを、マルチスレッドであるexecutorを使用して単一のAsyncTaskにワープできます。実行の順序は関係ありません。単一のワーカースレッドですべての呼び出しを順番に実行するIntentServiceとは対照的です。マルチコアのハイエンドデバイスの場合、AsyncTaskからの呼び出しがより効果的です。そして、UIスレッドでAsyncTaskを開始した場合、IUの更新は簡単なことです(ボイラープレートのコードは少なくなります)。また、ユーザーがページを離れた場合でも、コンテキストを保持しないというインテリジェントな使用により、アプリはクラッシュしません。

  • ユーザーがビュー/アクティビティ/フラグメントにいる必要のないアプリを作成しようとしており、何かを表示するための合計実行時間がミッションクリティカルではない場合(同期サービスまたはユーザー通知/アラームを想定)、IntentServiceの方が適しています選択。 (UIスレッドでAsynctaskを開始する手間がないので、UIなどで変更を強制するハンドラーを記述する必要がなく、ボイラープレートコードも少なくなります)

私の経験から-両方の小さなアプリを作成し、長所と短所を比較して、より良いアイデアを得ます。 (p.sより良いアイデアを得るために、Googleのioschedアプリを確認することをお勧めします-彼らはAsynctaskとIntentServiceの両方を使用しています)

3
raj

私はIntentService + BroadcastReceiverコンボを好む傾向があります。これは、非常に強力な制御ができるためです。

画面上の何かを更新する場合は、UIが実行されていることを確認する必要があります。 ASyncTaskクラッシュは、Androidクラッシュの主な原因の1つであるとすぐに報告されました。これは、何らかの "activityIsAlive"変数を保持し、アクティビティがデッド。

ほとんどのチュートリアルではBroadcastReceiver onPauseまたはonStopをオフにするように指示されているため、IntentService + BroadcastReceiverコンボはクラッシュに対する耐性が少し高くなります。これを行わない場合は、UIの更新をオフにする必要があります。 UIの更新に役立つrunOnUiThreadコマンドがどこかにあります。

IntentService + BroadcastReceiverコンボもより拡張可能です。関数を作成し、BroadcastReceiverを拡張して、より洗練されたREST処理ソリューションを作成できます。ただし、ASyncTaskよりも多くの配管が必要です。

UIの更新を遅らせる場合は、OnWindowFocusChangedListenerにリギングできる可能性があります。その関数がtrueを受け取ると、UIが有効であることを意味します。

tldr;バックグラウンドで何かを実行している場合は、UIを更新する前に、アクティビティやフラグメントが有効であることを確認してください

2015編集:ローダーもチェックしてください。舞台裏で多くのことが起こっているため、少し把握するのが難しい

2
Joe Plante