Service
サービスにはインターフェイスがなく、バックグラウンドで実行されるため、デバイスのリソースを消費し、リソースの使用量が多すぎるなど、ユーザーエクスペリエンスが低下し、デバイスがスムーズに動作しなくなる可能性があります。この問題を軽減するために、Android Oバージョンではバックグラウンドサービスにいくつかの制限が課せられています。ただし、この制限はバックグラウンドサービスのみに適用され、フォアグラウンドサービスは影響を受けません。
フロントエンド・アプリケーションとは
バックエンド・サービスの制限を説明するには、まず、フロントエンド・アプリケーションとは何か、バックエンド・アプリケーションとは何かを知る必要があります。
フロントエンド・アプリケーションは、以下のいずれかの条件を満たす必要があります。
- レジューム状態でもポーズ状態でも、目に見えるアクティビティがあります。
- FrontendServiceがあります。
- サービスをバインドするか、ContentProviderを使用して、現在のアプリに接続する他のアプリがあります。
フロントエンドサービスとバックグラウンドサービス
では、フロントエンド・サービスとバックエンド・サービスをどのように区別するのでしょうか?
フォアグラウンドサービスは通知を送信するため、ユーザーはサービスが実行されていることを認識できますが、バックグラウンドサービスには通知がないため、ユーザーはサービスが実行されていることを認識できません。
では、フロントエンドのサービスとバックエンドのサービスはどのように開始されるのでしょうか?
Context.startService()
バックグラウンド・サービスの場合は簡単です。
フォアグラウンドサービスの場合は、少し複雑です。Context.startService()
Service.startForeground()
しかし、Android 8.0以降、バックグラウンドアプリがバックグラウンドServiceを作成することが制限され、同じ方法でバックグラウンドServiceをフォアグラウンドServiceに昇格させることができなくなりました。Context.startForegroundService()
Service.startForeground()
Android 8.0では、バックグラウンドアプリがフォアグラウンドサービスを作成できない問題を解決するため、フォアグラウンドサービスを直接起動する新しい方法を導入しましたが、システムがこのフォアグラウンドサービスを作成する際、アプリは5秒以内に通知を表示するよう呼び出す必要があり、そうでない場合、システムはこのフォアグラウンドサービスを停止し、ANRをポップアップ表示します。
android.permission.FOREGROUND_SERVICE
Android 9.0から、フォアグラウンドServiceを作成する場合は、AndroidManifest.xmlでパーミッションも宣言する必要があります。 これは、システムが自動的にアプリに付与する共通のパーミッションです。これを行わないと、例外がスローされます。
フロントエンドサービスの作成方法の例を以下に示します。
まず、アプリのターゲットバージョンがAndroid 10(API 29)である場合、マニフェストファイルでパーミッションを宣言する必要があります。
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
Android 8.0との互換性を保つため、コードは次のようになります。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mIntent = new Intent(this, MyService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(mIntent);
} else {
startService(mIntent);
}
}
アクティビティのonDestroy()でstopService()を呼び出すこともできますし、ServiceのstopSelf()を呼び出すこともできます。どちらを呼び出すかは、具体的な要件に応じて選択する必要があります。
サービスが作成されたらService.startForeground()
public void onCreate() {
super.onCreate();
// 通知を送信し、サービスをフォアグラウンドに置く
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
// アンドロイド8より.0開始するには、通知チャネルを登録する必要がある
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID,
"Service notification channel", NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(notificationChannel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Service");
// 最初のパラメーターを0にすることはできない。
startForeground(666, builder.build());
}
バックグラウンドサービスの制限
アプリがフォアグラウンドにあるときは、バックグラウンド・サービスを自由に作成して使用できます。アプリがバックグラウンドにある場合、サービスを作成して使用できるのは数分のウィンドウだけです。このウィンドウが終わると、システムはアプリをアイドル状態とみなし、アプリのバックグラウンド・サービスを停止します。
バックグラウンドサービスの制限の解決
公式の推奨は、バックグラウンドServiceを置き換えるためにJobSchedulerを使用することであり、公式はまた、アプリがフォアグラウンドで実行されていなくても、現在のユーザーが友人から共有されたイメージを受け取ったかどうかを検出する必要があるギャラリーアプリの例を示しました。Android 8.0では、アプリのクラウドストレージを検出するためにバックグラウンドのServiceを使用することができましたが、これには問題がありました。しかし、Android 8.0からは、バックグラウンドサービスの代わりにJobSchedulerを使用し、定期的にタスクを開始し、サーバーに照会を行い、終了します。バックグラウンドのサービスと比べて、消費するリソースが大幅に少なくなり、間接的に電話のパフォーマンスが向上します。
JobSchedulerの使い方については、次回の記事でイメージをダウンロードするケーススタディを紹介します。