web-dev-qa-db-ja.com

Androidアプリケーションが強制終了されるとバックグラウンドサービスが再起動します

センサーデータを収集するためのバックグラウンドサービスが作成されるアプリケーションを開発しています。私は自分の活動からサービスを開始しています:

_startService(new Intent(this, MyService.class));
_

サービスを作成したので、アプリケーションが破壊されても、バックグラウンドサービスは引き続きデータを収集します。私はこれを試しましたが、ある程度は機能しました。私の問題は、アプリケーションを強制終了すると、onCreate()サービスとonStart()メソッドが呼び出されるため、サービスが再起動するように見えることです。サービスを再起動しない方法はありますか?

更新:

以下の回答で示唆されているように、私は次のメソッドをサービスに追加しましたが、運はありません。

_@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return START_NOT_STICKY;
}
_
37
duncanportelli

OnStartCommandで返される値に依存します。

START_NOT_STICKYを返す必要があります

ドキュメント によると:

開始されたサービスには、onStartCommand()から返される値に応じて、実行を決定できる2つの追加の主要な操作モードがあります。START_STICKYは、必要に応じて明示的に開始および停止されるサービスに使用されます送信されたコマンドの処理中にのみ実行を継続する必要があるサービスの場合

つまり、START_STICKYを返すと、リソースが利用可能になるたびにサービスが再作成されます。 START_NOT_STICKYを返す場合、新しいインテントを送信するサービスを再度アクティブにする必要があります。

これらすべてが私の好奇心を引き起こしたので、これをテストするためのサンプルアプリを作成しました。すべての sources here でZipを見つけることができます。startServiceボタンとstopServiceボタンがあり、それらから期待することを実行します。サービスはonStartCommandでSTART_NOT_STICKYを返します。 onCreate、onStartCommand、onDestroyにトーストを配置しました。

ここで何が起こるか:

  • スタートを押すと、onCreateとonStartが呼び出されます
  • 停止ボタンを押すと、onDestroyがトリガーされます
  • Startを2回押すと、onCreateが1回呼び出され、onStartCommandが2回呼び出されます

したがって、期待どおりに動作します。

説明したようにサービスを開始してアプリを強制終了すると、onDestroyは呼び出されず、onCreateとonStartのどちらも呼び出されません。

アプリに戻ってもう一度開始を押すと、onCreateが呼び出されます。つまり、前に書いたように、START_NOT_STICKYはサービスの再起動を防ぎます。自動的に。

アプリに何か他のものがあり、サービスを再び開始していると思います(おそらく保留中の意図でしょう)。

20
fedepaol

アプリとサービスは同じプロセスに存在します。つまり、アプリが終了すると、サービスも終了します。 onStartCommandの戻り値を変更しても、このプロセスには影響しません。サービスに指示したとき、または必要な処理を完了したときに、開始/停止するようサービスに指示します。元の投稿へのコメントで述べたように、それをフォアグラウンドプロセスとして設定することは有効でしたが、それは実際には問題を解決するのではなく、サービスの優先度を高くするだけです。

サービスを個別に強制終了するように変更し、onStartCommandの使用によりバインドされたサービスではなく開始されたサービスであると想定するには、そのサービスのマニフェストにプロセス名を指定します。

プロセスおよびスレッド開発者ガイド から:

コンポーネント要素の各タイプのマニフェストエントリ-<activity>, <service>, <receiver>, and <provider>—コンポーネントを実行するプロセスを指定できるAndroid:process属性をサポートします。この属性を設定して、各コンポーネントが独自のプロセスで実行されるようにしたり、一部のコンポーネントがプロセスを共有し、他のコンポーネントが共有しないようにすることができます。 Android:processを設定して、異なるアプリケーションのコンポーネントが同じプロセスで実行されるようにすることもできます。ただし、アプリケーションが同じLinuxユーザーIDを共有し、同じ証明書で署名されている場合に限ります。

Androidは、メモリが少なく、ユーザーにより迅速にサービスを提供している他のプロセスに必要なときに、ある時点でプロセスをシャットダウンすることを決定する場合があります。そのため、強制終了されたプロセスで実行されているアプリケーションコンポーネントは破棄されます。それらのコンポーネントが行うべき作業が再びある場合、それらのコンポーネントのプロセスが再び開始されます。

から <service>マニフェストファイル

Android:プロセス

サービスを実行するプロセスの名前。通常、アプリケーションのすべてのコンポーネントは、そのアプリケーション用に作成されたデフォルトプロセスで実行されます。アプリケーションパッケージと同じ名前です。要素のプロセス属性は、すべてのコンポーネントに異なるデフォルトを設定できます。ただし、コンポーネントは独自のプロセス属性でデフォルトをオーバーライドできるため、アプリケーションを複数のプロセスに分散できます。

この属性に割り当てられた名前がコロン(「:」)で始まる場合、アプリケーション専用の新しいプロセスが必要に応じて作成され、そのプロセスでサービスが実行されます。プロセス名が小文字で始まる場合、サービスはその名前のグローバルプロセスで実行されますが、許可されている場合に限ります。これにより、さまざまなアプリケーションのコンポーネントがプロセスを共有できるようになり、リソースの使用量が削減されます。

これに言及した他の答えがなぜ反対票を投じられたかは定かではありません。私は過去にこの方法を使用していましたが、今日、私が夢中になっていないことを確認するために、別のプロセスでサービスを備えたシンプルな1つのActivityアプリを作成しました。 Android Device Monitorを使用してアプリのプロセスを強制終了しました。ADMで個別のプロセスを確認できます。アプリのプロセスが強制終了されてもサービスは強制終了されません。

4
Plumbus

スティッキーではない開始はKitKatより上では機能せず、他のonTaskRemovedはMarshmellowより上では機能しません。 onTaskRemovedは、いくつかの例外を処理することで使用できます。それに取り組みませんでした。しかし、それを試してください。

1
Minkoo

IntentServiceを使用している場合、

onHandleIntent() 

実行する必要があるコードを配置するメソッド。アプリケーションが実行されるUIスレッドではなく、別のスレッドで実行されるため、アプリは影響しません。コードの実行が終了すると、スレッドは終了し、サービスは自動的に停止します。

0
Marcin S.

私はこの質問に答えるのがかなり遅れていることを知っていますが、他の人に役立つかもしれません。これは、ミュージックプレーヤーアプリで本当に役立ちました。

混乱を招く可能性がある、または音楽などのユーザーエクスペリエンスに影響を与える可能性のあるサービスがある場合、その場合は通知を使用する必要があり、サービスが正常に開始されたら、通知を作成して関数を使用します

startForeground(int Notification_id,Notification);

これにより、メソッドを再起動および再起動することなく、サービスがバックグラウンドで実行されます

https://developer.Android.com/reference/Android/app/Service.html

0
abissa