Xamarin.Android で開始されたサービス

開始されたサービスの概要

開始されたサービスでは、通常、クライアントに直接フィードバックや結果を提供することなく、作業単位を実行します。 作業単位の例として、ファイルをサーバーにアップロードするサービスがあります。 クライアントは、デバイスから Web サイトにファイルをアップロードするようにサービスに要求します。 サービスはファイルを静かにアップロードし (アプリにフォアグラウンドのアクティビティがない場合でも)、アップロードが完了すると自ら終了します。 開始されたサービスがアプリケーションの UI スレッドで実行されることを認識することが重要です。 つまり、サービスが UI スレッドをブロックする作業を実行する場合、必要に応じてスレッドを作成して破棄する必要があります。

バインドされたサービスとは異なり、"純粋な" 開始されたサービスとそのクライアントの間に通信チャネルはありません。 つまり、開始されたサービスでは、バインドされたサービスとは異なるライフサイクル メソッドを実装します。 次の一覧では、開始されたサービスの一般的なライフサイクル メソッドが示されています。

  • OnCreate – サービスが最初に開始されたときに 1 回呼び出されます。 ここで初期化コードを実装する必要があります。
  • OnBind – このメソッドはすべてのサービス クラスで実装する必要があります。しかし、開始されたサービスには通常、クライアントがバインドされません。 このため、開始されたサービスからは null が返されるだけです。 これに対し、ハイブリッド サービス (バインドされたサービスと開始されたサービスの組み合わせ) は、クライアントの Binder を実装して返す必要があります。
  • OnStartCommand - StartService の呼び出しまたはシステムによる再起動に応答して、サービスを開始する要求ごとに呼び出されます。 ここで、サービスは実行時間の長いタスクを開始できます。 このメソッドからは、メモリ不足のためシャットダウン後にサービスの再起動をシステムが処理する方法または処理する必要があるかどうかを示す StartCommandResult 値が返されます。 この呼び出しはメイン スレッドで行われます。 この方法については、以下で詳しく説明します。
  • OnDestroy – このメソッドは、サービスが破棄されるときに呼び出されます。 これは、必要な最終的なクリーンアップを実行するために使用されます。

開始されたサービスの重要なメソッドは、OnStartCommand メソッドです。 これは、サービスが何らかの作業を行う要求を受け取るたびに呼び出されます。 次のコード スニペットは OnStartCommand の例です。

public override StartCommandResult OnStartCommand (Android.Content.Intent intent, StartCommandFlags flags, int startId)
{
    // This method executes on the main thread of the application.
    Log.Debug ("DemoService", "DemoService started");
    ...
    return StartCommandResult.Sticky;
}

最初のパラメーターは、実行する作業に関するメタデータを含む Intent オブジェクトです。 2 番目のパラメーターには、メソッド呼び出しに関する情報を提供する StartCommandFlags 値が含まれています。 このパラメーターには、次の 2 つの値のいずれかを指定できます。

  • StartCommandFlag.Redelivery - これは、Intent が以前の Intent の再配信であることを意味します。 この値は、サービスが StartCommandResult.RedeliverIntent を返したものの、適切にシャットダウンされる前に停止された場合に指定されます。 -StartCommandFlag.Retry ‐ この値は、以前の OnStartCommand 呼び出しが失敗し、Android が前回失敗した試行と同じインテントでサービスを再度開始しようとしたときに受け取られます。

最後に、3 番目のパラメーターは、要求を識別するアプリケーションに固有の整数値です。 複数の呼び出し元が同じサービス オブジェクトを呼び出す可能性があります。 この値は、サービスを停止する要求と、サービスを開始する特定の要求を関連付けるために使用されます。 詳細については、「サービスの停止」セクションで説明します。

StartCommandResult 値は、リソースの制約によりサービスが強制終了された場合の処理に関する Android への提案として、サービスによって返されます。 StartCommandResult に有効な値は次の 3 つです。

  • StartCommandResult.NotSticky – この値は、強制終了したサービスを再起動する必要がないことを Android に伝えるものです。 この例として、アプリ内のギャラリーのサムネイルを生成するサービスを考えてみましょう。 サービスが強制終了された場合、サムネイルをすぐに再作成することは重要ではありません。サムネイルは、次回アプリが実行されるときに再作成できます。
  • StartCommandResult.Sticky – これは、サービスを再起動しても、サービスを開始した最後のインテントを配信しないように Android に伝えるものです。 処理する保留中のインテントがない場合は、Intent パラメーターに null が指定されます。 その例として、音楽プレーヤー アプリがあります。サービスは音楽を再生する準備ができて再起動しますが、最後の曲を再生します。
  • StartCommandResult.RedeliverIntent – この値は、サービスを再起動して最後の Intent を配信し直すよう Android に伝えるものです。 その例として、アプリのデータ ファイルをダウンロードするサービスがあります。 サービスが強制終了された場合でも、データ ファイルをダウンロードする必要があります。 StartCommandResult.RedeliverIntent を返すことで、Android がサービスを再起動すると、(ダウンロードするファイルの URL を保持する) インテントもサービスに提供されます。 これにより、(コードの正確な実装に応じて) ダウンロードを再起動または再開できます。

StartCommandResult には 4 番目の値 StartCommandResult.ContinuationMask があります。 この値は OnStartCommand によって返され、Android が強制終了したサービスを継続する方法について説明するものです。 通常、この値はサービスの開始には使用されません。

開始されたサービスの主要なライフサイクル イベントを次の図に示します。

A diagram showing the order in which the lifecycle methods are called

サービスの停止

開始されたサービスは無期限に実行され続けます。十分なシステム リソースがある限り、Android はサービスを実行し続けます。 クライアントがサービスを停止する必要があるか、サービスがその作業の完了時に自ら停止する可能性があります。 サービスを停止するには、次の 2 つの方法があります。

  • Android.Content.Context.StopService() –クライアント (アクティビティなど) は、StopService メソッドを呼び出すことによってサービス停止を要求できます。

    StopService(new Intent(this, typeof(DemoService));
    
  • Android.App.Service.StopSelf() - StopSelf を呼び出すことによって、サービスが自らシャットダウンする場合があります。

    StopSelf();
    

startId を使用したサービスの停止

複数の呼び出し元がサービスの開始を要求できます。 未処理の開始要求がある場合、サービスは、OnStartCommand に渡される startId を使用して、サービスが途中で停止されないようにすることができます。 startId は、StartService の最新の呼び出しに対応し、呼び出されるたびにインクリメントされます。 したがって、StartService に対する後続の要求によって、まだ OnStartCommand が呼び出されていない場合、サービスは StopSelfResult を呼び出し、受け取った startId の最新の値を渡すことができます (StopSelf を呼び出すだけでなく)。 StartService の呼び出しによって、まだ対応する OnStartCommand の呼び出しが行われていない場合、StopSelf 呼び出しで使用される startId は最新の StartService 呼び出しに対応しないため、システムはサービスを停止しません。