AndroidStudio: Service の使い方

こちらと同じことを行いました。
[[Android & Kotlin] Service でバックグラウンド処理](https://akira-watson.com/android/kotlin/service-basic.html)

## ツリー構造
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/74efcc80-d054-22c4-5edd-bdf4264fb490.png)

## 環境

```xml:AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<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
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Service05"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:taskAffinity=""
            android:excludeFromRecents="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name=".TestService" />
    </application>

</manifest>
```

```xml:values/strings.xml
<resources>
    <string name="app_name">service05</string>
    <string name="start">Start Service</string>
    <string name="stop">Stop Service</string>
</resources>
```

## プログラム

```MainActivity.kt
package com.example.service05

import android.content.Intent
import android.os.Bundle
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val intent = Intent(application, TestService::class.java)

        val buttonStart = findViewById<Button>(R.id.button_start)
        buttonStart.setOnClickListener {
            intent.putExtra("REQUEST_CODE", 1)

            // Serviceの開始
            startService(intent)
        }

        val buttonStop: Button = findViewById(R.id.button_stop)
        buttonStop.setOnClickListener {
            // Serviceの停止
            stopService(intent)
        }
    }
}
```

```TestService.kt
package com.example.service05

import android.app.*
import android.content.Intent
import android.media.MediaPlayer
import android.os.IBinder
import android.util.Log
import android.widget.Toast

class TestService : Service() {

    private lateinit var mediaPlayer: MediaPlayer

    override fun onCreate() {
        super.onCreate()
        Log.d("debug", "onCreate()")

        // ..\res\raw\sample.mp3
        mediaPlayer = MediaPlayer.create(this, R.raw.kanpai)
    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        Log.d("debug", "onStartCommand()")

        val context = applicationContext

        val channelId = "default"

        val title: String = getString(R.string.app_name)

        val notificationManager = getSystemService(NOTIFICATION_SERVICE)
                as NotificationManager

        val pendingIntent: PendingIntent =
                      Intent(this, MainActivity::class.java).let { notificationIntent ->
                PendingIntent.getActivity(this, 0, notificationIntent,
                    PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
                )
            }

        // Notification　Channel 設定
        val channel = NotificationChannel(
            channelId, title, NotificationManager.IMPORTANCE_DEFAULT
        )

        notificationManager.createNotificationChannel(channel)

        val notification = Notification.Builder(context, channelId)
            .setContentTitle(title) // android標準アイコンから
            .setSmallIcon(android.R.drawable.ic_media_play)
            .setContentText("MediaPlay")
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)
            .setWhen(System.currentTimeMillis())
            .build()

        // startForeground
        startForeground(1, notification)
        audioStart()
        return START_NOT_STICKY
        //return START_STICKY;
        //return START_REDELIVER_INTENT;
    }

    private fun audioStart() {
        // ループ
        mediaPlayer.isLooping = true

        mediaPlayer.start()

        // トースト
        val str = "Start Walking\n(c)Music-Note.jp"
        val toast: Toast = Toast.makeText(this, str, Toast.LENGTH_LONG)
        toast.show()

        // 終了を検知するリスナー
        mediaPlayer.setOnCompletionListener {
            Log.d("debug", "end of audio")
            audioStop()
            // Service終了
            stopSelf()
        }
    }

    private fun audioStop() {
        // 再生終了
        mediaPlayer.stop()
        // リセット
        mediaPlayer.reset()
        // リソースの解放
        mediaPlayer.release()
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d("debug", "onDestroy()")
        audioStop()
        // Service終了
        stopSelf()
    }

    override fun onBind(intent: Intent): IBinder? {
        return null
    }
}
```

## 音源

音源は、こちらから kanpai.mp3 をダウンロードしました。
[フリーWave,MP3](https://www.ne.jp/asahi/music/myuu/wave/wave.htm)

## 実行時の画面
エミュレーターでは、クラッシュします。
実機では、ちゃんと音源が再生されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/2b677976-2497-889b-549a-ec850c2d0395.png)