Android Studio(メモリストのアプリ11_フォアグラウンドサービスと通知)
■終了時の長い処理について
前回、startServiceを使って処理を行っていたけど、アプリを終了した後に長い処理(2分位)をさせようとすると、処理が終了する前にサービスは終了してしまう。何とかならないかと思い、いろいろ試してみると、ForegroundServiceとして明示的に動作させればできた。
ForegroundServiceを使うにあたって、AndroidManifest.xmlにそのuses-permissionを追加する。これがないと、java.lang.SecurityException: Permission Denial: startForeground ... といったエラーになった。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<application ...
MainActivityのonStop()にstartForegroundServiceを追加して、アプリの停止時に動作させるようにする。
protected void onStop() {
super.onStop();
Intent intent = new Intent(this, HelloIntentService.class);
//startService(intent);
startForegroundService(intent);
}
次がHelloIntentServiceのコード。
package com.example.sampleproject010_ondestroy;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.util.Log;
public class HelloIntentService extends IntentService {
public HelloIntentService() {
super("HelloIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel("1234", "Nchannel", importance);
channel.setDescription("Ndesc");
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification =
new Notification.Builder(this, "aa123")
.setContentTitle("Note_Title")
.setContentText("Note_Text")
.setContentIntent(pi)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setTicker("Ticker")
.build();
startForeground(111, notification);
try {
for (int i = 0; i < 100; i++) {
Log.i("dd", Integer.valueOf(i).toString() + "service");
Thread.sleep(1000);
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Log.i("Service", "サービス");
this.stopSelf();
}
}
startForegroundServiceを実施する際には、続けてForegroundServiceを動作させないといけないよう。このコードで、「startForeground(111, notification);」をコメントアウトすると、下のログ出力で「10service」のメッセージが出たくらいのタイミングで処理が止まってしまう。
startForegroundを実施するには、Notificationが必要になり、さらにAPI28(Android 9)以降では、Notificationはチャネルに登録しなければならないよう。そのため、フォアグラウンドサービスを使う場合、NotificationとNotificationChannelもセットになると思ってる。
NotificationとNotificationChannelのチャネルID(ここでは"aa123"と"1234")を一緒にしなければならないといった記載もあったけど、異なる場合でも動いている。たまに下のエラーが出ることもあった。どこかで一時ファイルみたいなものが残っているのかな。
android.app.RemoteServiceException: Bad notification for startForeground: java.lang.RuntimeException: invalid channel for service notification: …
実行結果が下。重要度を高くしているので、サービスが起動した際に音がなり通知の部分に表示される。
1秒ごとに、ログにメッセージを100回出力する。途中でアプリを終了させると、OnDestroyに入れたログ(destroy1: 終了など)が出力され、サービスの出力はそのまま継続する。
最後まで処理が終わると、通知は自動的に消える。
通知は期限がきたときのホップアップみたいに使えそうなので、何かと使い道はありそう。