Androidはアプリケーションコンポーネント(アクティビティ、サービス)をいつでも殺す危険にさらされていることはよく知られています。これは、堅牢で漏れのないソリューションを提供したいと同時に、コードをきれいに保ちながら懸念の分離に取り組むためには、事態を本当に複雑にします。良いデザイン:ワーカースレッドとアクティビティの再起動
問題:
活性が(Runnable
、AsyncTask
または他のいずれかの機構の形で)時間のかかるタスクを開始します。進行状況ダイアログが表示されます。タスクはいくつかの接続を開きますが、プログレスバーを更新する手段が必要です。完了までに半分の方法で選択ダイアログを表示する必要があります。また、エラーが発生したとき、または完了したときに、ダイアログを閉じてToastを表示できるようにする必要があります。
活動が殺され、後に、新しいインスタンスが再作成され、私は2つのオプションを考えることができます。
が同様に実行中のタスクを殺す、とするときに、新しい代替別のタスクインスタンスを起動してみてくださいアクティビティインスタンスが作成されます。ユーザーの観点からは、タスクを開始し、80%から0%に進むプログレスバー・インジケーターが明白な理由なく表示されるのを容認できないため、これは長時間実行されるタスクのオプションではありません。しかしこれはShelves example by Romain Guyに続く方法です。どうやらこれは公式の開発者ガイドで推奨されているアプローチです。
タスクを実行し続ける:
onResume
に更新タスクをサブスクライブして(場合によっては開始して)、でサブスクリプションをサブスクライブしない(一時停止する)ことができます。
2番目のオプションの後には、アクティビティが一時的に破棄された場合に収集するタスクを防止する必要があることを意味します。たとえば、カスタムアプリケーションクラス内に宣言することも、アプリケーションの残りの部分にサービスとして提供することもできます(Singleton?Androidサービスを使用していますか?)。アクティビティによってのみ使用されるため、他のクラスで使用できるようにすることは意味がありません。一方、Androidサービスはライフサイクルに対処する必要があります。
オプション2では、古いアクティビティがリークしないようにすることも含まれます。アクティビティが存在しない場合はGUIを更新しないでください。全体の考えはスレッドセーフでなければなりません。最後に、タスクが不要になったことが確認された後でも、タスクはメモリに残りません。しかし同時に、初期アクティビティが破棄され、タスクが実行され続け、新しい代替アクティビティが開始された場合、タスクは直ちにGUIを更新してタスクの現在のステータスを表示する必要があります(完了した場合の結果)。
アクティビティが表示されていないときにタスクが実行されている可能性があるということは、ユーザーの操作(選択ダイアログ)をある時点で同期させる必要があるためです。これは、アクティビティがに達するとすぐにタスクを一時停止する機能を持っていた場合には解決できますが、タスクが一時停止するか、実行できなくなるまでに時間がかかる可能性があります。
私は以前に質問されていることはよく知っていますが、問題の解決方法を具体的に求めているわけではありませんが、疎結合を達成し、可能。
短いで:
- これは、Androidの開発で繰り返し発生する問題であると誰かが、おそらく前に巧妙なデザインを打ち出しています。これを単純化する設計パターン、または十分にテストされたライブラリはありますか?
- #2を実装する場合は、タスク(Runnable、Serviceなど)のためにどのクラスを選択し、アクティビティとどのように通信しますか?
P.S. "orientation | keyboardHidden"ハックXDに基づいてソリューションを投稿することをお控えください。これ以外にも、どんな助けもありがたいです。
UPDATE:
私の最初の試みは少し厄介持っています。このアプリは、BTのステータスを検出する(そして、それが無効になっている場合にそれを有効にするようユーザーに求めます)、ペアになっているデバイスを取得する(そして、複数のデバイスがある場合にユーザーを選択して、最後にユーザーに結果を知らせます。このタスクは80%のIOコード、20%のGUI関連の操作であったため、タスクの始めと終わりにGUIコードをグループ化し、それをタスクからアクティビティに戻す必要がありました。私はIntentService
を持っていますが、それは重い持ち上げをしてから、BroadcastReceiver
を介して活動に報告します。これはほとんどの問題を解決しますが、そのような設計にはいくつかの問題があります。まず、意味的結合を導入するインプットとアウトプットのインテントからフィールドを出し入れするためのキーとして使用される定数ストリングがすべてあります。私は、アクティビティ< - >サービス通信でタイプセーフティを優先させていたでしょう。また、複雑なカスタムオブジェクトをインテントのサービスに渡す方法を解決する必要があります。今はParcelablesとプリミティブパラメータに悩まされています。最後に、アクティビティとサービスの両方が同じAPI(ブルートゥース)を使用しているため、私はBT関連のコードを単一のクラスに持つことを好みました。私はこのデザインを捨てて、スレッドに基づいたカスタムプリントキューを使ってやり直してみましょう。それは、殺されたアクティビティをより扱いにくくします。
アクティビティが再作成されている間、AsyncTaskは一時停止しています。タスクが進行状況/結果に使用するメッセージは、アクティビティが破棄されている間は配信されません(一時停止/再開前にも発生する可能性があります)。非構成インスタンスのものを使用して、アクティビティー・インスタンス間でAsyncTaskを渡すことは、かなりうまくいくはずです。 – zapl