Android サービスの作成

このガイドでは、アクティブなユーザー インターフェイスなしで作業を実行できる Android コンポーネントである Xamarin.Android サービスについて説明します。 サービスは、時間のかかる計算、ファイルのダウンロード、音楽の再生など、バックグラウンドで実行されるタスクに非常に一般的に使用されます。 サービスが適しているさまざまなシナリオについて説明し、実行時間の長いバックグラウンド タスクの実行とリモート プロシージャ 呼び出し用のインターフェイスの提供の両方にサービスを実装する方法を示します。

Android サービスの概要

モバイル アプリはデスクトップ アプリとは似ていません。 デスクトップには、画面の不動産、メモリ、記憶域、接続された電源など、大量のリソースがあり、モバイル デバイスでは使用できません。 これらの制約により、モバイル アプリの動作が異なります。 たとえば、モバイル デバイス上の小さな画面は、通常、一度に 1 つのアプリ (つまりアクティビティ) のみが表示されることを意味します。 他のアクティビティはバックグラウンドに移動され、一時停止状態にプッシュされ、作業を実行できません。 ただし、Android アプリケーションがバックグラウンドにあるからといって、アプリが動作し続けることは不可能という意味ではありません。

Android アプリケーションは、 アクティビティブロードキャスト レシーバーコンテンツ プロバイダーおよびサービスの 4 つの主要コンポーネントの少なくとも 1 つで構成されています。 アクティビティは、ユーザーがアプリケーションと対話できる UI を提供するため、多くの優れた Android アプリケーションの基礎となります。 ただし、同時作業またはバックグラウンド作業の実行に関しては、アクティビティが常に最適な選択とは限りません。

Android でのバックグラウンド作業の主なメカニズムは 、サービスです。 Android サービスは、ユーザー インターフェイスなしで何らかの作業を行うように設計されたコンポーネントです。 サービスは、ファイルのダウンロード、音楽の再生、または画像へのフィルターの適用を行う場合があります。 サービスは、Android アプリケーション間のプロセス間通信 (IPC) にも使用できます。 たとえば、ある Android アプリが別のアプリからの音楽プレーヤー サービスを使用したり、アプリがサービスを介して他のアプリにデータ (個人の連絡先情報など) を公開したりする場合があります。

サービスとそのバックグラウンド作業を実行する能力は、スムーズで流動的なユーザー インターフェイスを提供するために重要です。 すべての Android アプリケーションには、アクティビティが実行される メイン スレッド ( UI スレッドとも呼ばれます) があります。 デバイスの応答性を維持するには、Android が 1 秒あたり 60 フレームの速度でユーザー インターフェイスを更新できる必要があります。 Android アプリがメイン スレッドで実行する作業が多すぎる場合、Android はフレームをドロップします。これにより、UI がぎくしゃく表示されます ( ジャンキーとも呼ばれることもあります)。 つまり、UI スレッドで実行されるすべての作業は、約 16 ミリ秒 (60 フレームごとに 1 秒) の 2 つのフレーム間の期間で完了する必要があります。

この問題に対処するために、開発者はアクティビティ内のスレッドを使用して、UI をブロックするいくつかの作業を実行できます。 ただし、これにより問題が発生する可能性があります。 Android がアクティビティの複数のインスタンスを破棄して再作成する可能性は非常に高いです。 ただし、Android ではスレッドが自動的に破棄されないため、メモリ リークが発生する可能性があります。 その主な例は、デバイスが ローテーションされたときです 。Android はアクティビティのインスタンスを破棄し、新しいアクティビティを再作成します。

When device rotates, instance 1 is destroyed and instance 2 is created

これはメモリ リークの可能性があります。アクティビティの最初のインスタンスによって作成されたスレッドは引き続き実行されます。 スレッドに Activity の最初のインスタンスへの参照がある場合、Android はオブジェクトをガベージ コレクションできなくなります。 ただし、アクティビティの 2 番目のインスタンスは引き続き作成されます (その後、新しいスレッドが作成される可能性があります)。 デバイスを数回連続して回転すると、すべての RAM が使い果たされ、Android がアプリケーション全体を強制的に終了してメモリを回収する可能性があります。

経験則として、実行する作業がアクティビティを上回る場合は、その作業を実行するためにサービスを作成する必要があります。 ただし、アクティビティのコンテキストでのみ作業が適用される場合は、作業を実行するスレッドを作成する方が適切な場合があります。 たとえば、フォト ギャラリー アプリに追加したばかりの写真のサムネイルを作成すると、サービスで発生する可能性があります。 ただし、アクティビティがフォアグラウンドにある間にのみ聞こえる音楽を再生するには、スレッドの方が適している場合があります。

バックグラウンド作業は、次の 2 つの大きな分類に分けることができます。

  1. 実行時間の長いタスク – これは、明示的に停止するまで進行中の作業です。 実行時間の長いタスクの例として、音楽をストリーミングするアプリや、センサーから収集されたデータを監視する必要があるアプリがあります。 アプリケーションに表示されるユーザー インターフェイスがない場合でも、これらのタスクを実行する必要があります。
  2. 定期的なタスク – ( ジョブと呼ばれることもあります) 定期的なタスクは、比較的短い期間 (数秒) であり、スケジュールに従って実行されます (つまり、1 日に 1 週間に 1 回、または次の 60 秒間に 1 回だけ実行される場合もあります)。 たとえば、インターネットからファイルをダウンロードしたり、画像のサムネイルを生成したりします。

Android サービスには次の 4 種類があります。

  • バインドされたサービスバインドされたサービス は、他のコンポーネント (通常はアクティビティ) がバインドされているサービスです。 バインドされたサービスは、バインドされたコンポーネントとサービスが相互に対話できるようにするインターフェイスを提供します。 サービスにバインドされたクライアントがなくなったら、Android によってサービスがシャットダウンされます。

  • IntentService – An IntentService は、サービスの作成と使用を Service 簡略化するクラスの特殊なサブクラスです。 An IntentService は、個々の自律呼び出しを処理するためのものです。 複数の呼び出しを同時に処理できるサービスとは異なり、IntentService作業キュー プロセッサに似ています。作業はキューに入れられ、IntentService1 つのワーカー スレッドで各ジョブが一度に 1 つずつ処理されます。 通常、アクティビティIntentService またはフラグメントにはバインドされません。

  • 開始済みサービス開始されたサービス は、他の Android コンポーネント (アクティビティなど) によって開始され、サービスに停止を明示的に指示されるまでバックグラウンドで継続的に実行されるサービスです。 バインドされたサービスとは異なり、開始されたサービスに直接バインドされたクライアントはありません。 このため、必要に応じて適切に再起動できるように、開始されたサービスを設計することが重要です。

  • ハイブリッド サービスハイブリッド サービスは、開始されたサービスとバインドされたサービスの特性を持つサービスです。 ハイブリッド サービスは、コンポーネントがそれにバインドされたとき、または何らかのイベントによって開始された場合に開始できます。 クライアント コンポーネントは、ハイブリッド サービスにバインドされる場合とバインドされていない場合があります。 ハイブリッド サービスは、明示的に停止するように言われるまで、またはクライアントがバインドされるまで実行を続けます。

使用するサービスの種類は、アプリケーションの要件に大きく依存します。 経験則として、Android アプリケーションが実行する必要があるほとんどのタスクには、 IntentService 1 つまたはバインドされたサービスで十分であるため、これら 2 種類のサービスのいずれかに優先する必要があります。 A IntentService は、ファイルのダウンロードなどの "ワンショット" タスクに適していますが、アクティビティ/フラグメントとの頻繁な対話が必要な場合は、バインドされたサービスが適しています。

ほとんどのサービスはバックグラウンドで実行されますが、 フォアグラウンド サービスと呼ばれる特別なサブカテゴリがあります。 これは、(通常のサービスと比較して) ユーザーに対して何らかの作業を実行する (音楽の再生など) 優先順位が高いサービスです。

また、同じデバイス上で独自のプロセスでサービスを実行することもできます。これは、 リモート サービス または アウトプロセス サービスと呼ばれることもあります。 作成にはより多くの労力が必要ですが、アプリケーションが他のアプリケーションと機能を共有する必要がある場合に役立ち、場合によってはアプリケーションのユーザー エクスペリエンスを向上させることができます。

Android 8.0 でのバックグラウンド実行の制限

Android 8.0 (API レベル 26) 以降、Android アプリケーションではバックグラウンドで自由に実行する機能がなくなりました。 フォアグラウンドの場合、アプリは制限なくサービスを開始して実行できます。 アプリケーションがバックグラウンドに移動すると、Android によってアプリにサービスの開始と使用に一定の時間が与えられます。 その時間が経過すると、アプリはサービスを開始できなくなり、開始されたサービスは終了します。 この時点では、アプリで作業を実行することはできません。 Android では、次のいずれかの条件が満たされている場合、アプリケーションがフォアグラウンドにあると見なされます。

  • 目に見えるアクティビティ (開始または一時停止) があります。
  • アプリがフォアグラウンド サービスを開始しました。
  • 別のアプリがフォアグラウンドにあり、それ以外の場合はバックグラウンドにあるアプリのコンポーネントを使用しています。 この例は、フォアグラウンドにあるアプリケーション A がアプリケーション B によって提供されるサービスにバインドされている場合です。アプリケーション B もフォアグラウンドで検討され、Android によってバックグラウンドで終了されません。

アプリがバックグラウンドにある場合でも、Android がアプリを起動し、数分間これらの制限を緩和し、アプリがいくつかの作業を実行できるようにする状況がいくつかあります。

  • 優先度の高い Firebase Cloud Message がアプリによって受信されます。
  • アプリはブロードキャストを受信します。
  • アプリケーションは、通知に応答して受信して実行 PendingIntent します。

既存の Xamarin.Android アプリケーションでは、Android 8.0 で発生する可能性のある問題を回避するために、バックグラウンド処理の実行方法を変更する必要がある場合があります。 Android サービスの実用的な代替手段を次に示します。

  • Android ジョブ スケジューラまたは Firebase ジョブ ディスパッチャーを使用してバックグラウンドで実行する作業をスケジュールする – これら 2 つのライブラリは、バックグラウンド作業をジョブに分離するためのフレームワークを提供します。この 2 つのライブラリは、個別の作業単位であるジョブにバックグラウンド作業を分離するためのフレームワークを提供します。 その後、アプリは、ジョブを実行できるタイミングに関するいくつかの条件と共に、オペレーティング システムでジョブをスケジュールできます。
  • フォアグラウンドでサービスを開始 する – フォアグラウンド サービスは、アプリがバックグラウンドで何らかのタスクを実行する必要があり、ユーザーがそのタスクと定期的に対話する必要がある場合に役立ちます。 フォアグラウンド サービスは永続的な通知を表示し、アプリがバックグラウンド タスクを実行していることをユーザーが認識し、タスクを監視または操作する方法も提供します。 この例としては、ポッドキャストをユーザーに再生したり、ポッドキャスト エピソードをダウンロードして後で楽しむことができるポッドキャスト アプリがあります。
  • 優先度の高い Firebase Cloud Message (FCM) を使用 する - Android がアプリの優先度の高い FCM を受け取ると、そのアプリで短時間、バックグラウンドでサービスを実行できるようになります。 これは、バックグラウンドでアプリをポーリングするバックグラウンド サービスを使用する代わりに適しています。
  • アプリがフォアグラウンドに入ったときに作業を延期 する - 前のソリューションが実行可能でない場合、アプリは、アプリがフォアグラウンドになったときに作業を一時停止および再開するための独自の方法を開発する必要があります。