4

Androidフォンをユーザーの操作なしで実行されるリモートデバイスに変換するように設計されたアプリを開発しています. アプリは、X分ごとにサービス(プロジェクト内のクラス)を実行するようにAlarmManagerを設定するActivityによって作成されます。

これはすべて問題なく動作しますが、5 ~ 6 日連続して実行すると、アプリケーションがクラッシュすることがあります (現在、電話を取得できないため、理由はわかりません)。これは接続の問題ではなく (わかっています)、電話はまだ動作しています (AC に接続されています)。私が推測できる唯一のことは、アプリケーションがダウンしていることです。

prew デバッグではエラーが発生しないため、これはバグによるものではないと思います。

したがって、Android がアクティビティを強制終了したと仮定する必要があります (システムにはより多くのメモリが必要ですか?)。画像が説明しているように、それをバックアップする方法はありません。

フロー図

しかし、疑問があります。私のアプリケーションでは、すべての作業がサービスによって行われるため、アクティビティは重要ではありません。サービス自体は Alarm Manager によって呼び出され、2 つの呼び出しの間で、サービスは StopSelf() によって終了されます。

私の場合、システムがアラーム マネージャ サービス スケジュールを強制終了する可能性がありますか?

Alarm Manager によってサービスを永久に起動するにはどうすればよいですか?

(注意: 現在 WAKE LOCK はまだありますが、これはサービスの実行のみを考慮しています!サービスがアラーム マネージャによって x 分ごとに呼び出され、終了されることを理解していただければ幸いです...この操作を実行したいのは不定時間)

【ソースコードが長いので掲載していません】

4

3 に答える 3

4

ロク、

私自身も同様の問題に取り組んだ後、いくつかの指針があるかもしれません。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 に情報を投稿します。アプリケーションが終了した場合、

他の人は、これらの問題に対処するためのより良い方法やその他の指針を持っているかもしれません (私は確かに他の意見を見ることができてとてもうれしいです)。

于 2012-01-11T00:22:46.203 に答える
0

サービスでの使用の背後にあるポイントAlarmManagerは、短時間実行されるサービスを開始することです。その後、サービスは終了します (例: IntentService)。永続的なサービスを提供しようとする場合、 は必要ありませんAlarmManager。サービス一定期間後に Android によってシャットダウンされます。

永続的なサービスを必要とせず、意図したとおりに使用するようにアプリを書き直すAlarmManagerと、存続可能性が向上するはずです。

于 2011-12-22T21:23:33.280 に答える
0

Lork が達成したいことは、私が取り組んでいることと似ていると思います。彼は、アラーム マネージャーが、アラームを処理するブロードキャスト レシーバーをトリガーすることを望んでいます。これは、その一部であるアプリケーションが (たとえば、Android OS によって) 終了された場合でも同様です。

例: アプリケーションは ELAPSED_REALTIME_WAKEUP または RTC_WAKUP のタイプでアラームを設定し、アプリケーション コンテキストとブロードキャスト レシーバー クラスを参照するインテントを介して、アラームが発生したときにそれを処理するブロードキャスト レシーバーを持っています。レシーバーは、アプリケーション マニフェストで として宣言されます。

通常の状況では、アプリケーションの実行中または一時停止中にアラームが鳴ると、ブロードキャスト レシーバーがトリガーされ、デバイスが起動され、必要に応じてアプリケーションが再開され、アラームが処理されます。ただし、アプリケーションが (たとえば OS によって) 強制終了された場合、アラームは引き続き (まだ登録されているため) 鳴りますが、ブロードキャスト レシーバーはトリガーされず、LogCat はヌル ポインター例外を示します (私が推測する理由は、アプリケーションへの参照はメモリ内にありません)。これは、Context が渡された場合でも発生します。

私 (そして Lork だと思います) はここで簡単な戦略を見逃していますか? それとも無理ですか?ブロードキャスト レシーバーが単独で存在し、必要に応じてアプリをトリガーすることはできますか?

私が試行錯誤してきた不完全な戦略の 1 つは、すべてのアプリ データ アクセスをコンテンツ プロバイダーに移動し、ブロードキャスト レシーバーを実装するだけの別のロー プロファイル アプリを用意することです。コンテンツ プロバイダー経由で必要です。これは OS によって終了される可能性がありますが、可能性は低くなります。

于 2012-01-03T16:09:42.957 に答える