ロク、
私自身も同様の問題に取り組んだ後、いくつかの指針があるかもしれません。Android デバイスを一種のリモート '組み込みコントローラー' として使用していると仮定します。これは、最小限のユーザー操作でその機能を実行します。私はあなたがそこに 95% いると信じており、アーキテクチャに若干の変更を加える必要があるだけです。コードを提供していないので、コード例を示すのではなく、抽象的な用語で説明します。
CommonsWare は、AlarmManager を使用する必要があることは正しいですが、既にそれを知っていると思います。すべてが理解できることを確認するために、最初にいくつかの背景コメントがあります。AlarmManager によって作成されたアラームは、システム レベルで存在します。つまり、アラームを作成したアクティビティとアプリケーションのライフサイクルを超えて存在できます。アラームを設定したが、アプリの状態が変化した場合 (たとえば、アプリが破棄された後) にアラームを鳴らしたくない場合は、alarmManager.cancel(pendingIntent) を使用してアラームをキャンセルできます。インテントとアラーム マネージャーを作成するだけです。同じパラメータと Android がアラームに一致します)。同様に、BroadcastReceivers はシステム レベルで登録され (少なくとも manifest.xml で宣言されている場合)、それらを作成したアクティビティとアプリケーションのライフサイクルを超えて存在できます。アプリの状態が変更された後 (たとえばアプリが破棄された後) に発生したイベントに応答して BroadcastReceiver が起動しないようにする場合は、そのコードで明示的に登録を解除する必要があります。プログラムで登録された場合は、context.unregisterReceiver(broadcastReceiver); を使用します。マニフェストに静的に登録されている場合は、それほど簡単ではありません。PackageManager と ComponentName を使用してレシーバーを取得する必要があります (以下を参照)。Android - マニフェストで作成されたレシーバーの登録を解除する方法は? ) - また、受信機が再び必要になった場合は、受信機を再度有効にする必要があることに注意してください。
あなたはすでにアラームを設定したと言います。アラーム タイプに ELAPSED_REALTIME_WAKEUP または RTC_WAKUP を指定して、電話が「スリープ」モードの場合でも確実に実行されるようにしてください。また、アラーム イベントを処理するために、関連付けられた BroadcastReceiver を既に作成しているとも言います。BroadcastReceiver は最小限の作業を行う必要があるため、すべての処理を別のスレッドで処理するか、サービスを起動する必要があります。Service を起動し、終了時に stopSelf() を使用して終了することを選択したため、システム リソースが使い果たされません。ここまでは順調ですね。
アプリの実行中は問題ありませんが、無期限に確実に実行する必要があるため、アプリが一時停止している、デバイスが「スリープしている」、アプリがクラッシュしたなどの「例外」状況を確実に管理する必要があります。 /terminated、またはデバイスが再起動しました (および考えられるその他の例外シナリオ)。対処する必要があると私が特定した問題は次のとおりです。
最初: WakeLock は、BroadcastReceiver の onReceive() メソッドの期間中のみ保証されます。サービスが終了した後、サービスが開始されていない、または完了していなくても、デバイスは「スリープ」に戻る可能性があるため、サービスを停止する前に WakeLock を作成し、それをサービスに渡し、解放する必要があります。(注: アプリケーションには、PARTIAL_WAKE_LOCK が必要です)。WakeLock の使用には細心の注意を払ってください。WakeLock を使用するとバッテリーが過度に消耗する可能性があるため、必要最小限の時間だけ WakeLock を保持し、リリースするようにしてください)。 WakeLocks の使用例については、http://www.netmite.com/android/mydroid/development/pdk/docs/power_management.htmlを参照してください。
2 番目: コードでアラームをリセットする場合 (自動的に繰り返されるものを定義するのではなく)、BroadcastReceiver の OnReceive() メソッドで、または起動したサービスで最初にこれを行います。これにより、アラームが確実に繰り返されます。アプリケーションまたはデバイスの状態に関係なく。
3 番目: 使用するコンテキストが null 以外の値になることを確認します。getApplicationContext() を使用して、サービス内のコンテキストを動的に取得できます。それ以外の場合は、Context をアプリケーションからアラームに明示的に渡し、BroadcastReceiver および関連するスレッドとサービスを介して確実に渡されるようにすることで実現できます。アプリケーションに Context を静的に保存してどこからでも取得できる場合、アプリケーションが終了すると null 値が返されます。Context を使用して (たとえば、リソースの取得、データベースへのアクセスなど)、それが null の場合、null ポインター例外が発生し、Service または BroadcastReceiver がクラッシュします。これが、アプリが終了したときにブロードキャスト レシーバーが機能しない最も可能性の高い理由だと思います。
4 番目: Service または BroadcastReceiver の完全修飾 (. R.drawable.icon) または渡されたコンテキストから生成された ResourceID (R.drawable.icon など) への参照を作成することができます。これが必要であるとはまだわかっていませんが、賢明かもしれません。
5 番目: 別の BroadcastReceiver を実装して、デバイスの再起動シナリオ (ON_BOOT_COMPLETE イベント) を処理します。必要に応じてこのレシーバーにアプリを再起動させるか、サービスを起動してアプリがアクティブであることを確認し、必要なパラメーターを設定して関連するアラームを設定し、stopSelf() を使用して終了させることができます。または、アラームを再度設定して、その受信機にすべて処理させます。サービスがその期間中 WakeLock を持っていることを確認し、サービスが完了したら WakeLock を解放することを忘れないでください。アプリまたはサービス (アプリケーションの一部として宣言されている) を再起動するだけでなく、必要に応じて正しいコンテキストを BroadcastReceiver のクラス属性として静的に保存し、アクセスできるようにする必要があります。資力。
あなたが考慮したい他のいくつかのこと: あなたのセットアップはリモートであるため、SQLite データベース テーブルに永続的なデータを保存することを真剣に検討します。これにより、データを再生成することなく、アプリケーションの終了とデバイスの再起動の間でデータを確実に回復できます。アプリケーションがサーバー サービスと通信する場合は、アプリが定期的にポーリングするのではなく、サーバーが開始する通信にプッシュ通知を使用することを検討してください。プッシュ通知は、「サービスとアプリを起動して起動する」ためにも使用できるため、デバイスとアプリケーションのステータスを照会するリモート メカニズムの一部として使用できます。このアプローチは、より電力効率が高く、タイムリーでもあります。デバッグのために、コードの重要なポイントで LogCat に情報を投稿します。アプリケーションが終了した場合、
他の人は、これらの問題に対処するためのより良い方法やその他の指針を持っているかもしれません (私は確かに他の意見を見ることができてとてもうれしいです)。