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: 終了など)が出力され、サービスの出力はそのまま継続する。


最後まで処理が終わると、通知は自動的に消える。

通知は期限がきたときのホップアップみたいに使えそうなので、何かと使い道はありそう。