【Kotlin/Android Studio】Serviceとは?種類とバックグラウンド操作
この記事からわかること
- Android Studio/KotlinのServiceの使い方
- サービスの種類と実装方法
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
環境
- Android Studio:Flamingo
- Kotlin:1.8.20
Serviceとは?
Serviceとはバックグラウンドなどで長時間処理を実装したい場合に使用するUIを実装しないアプリコンポーネントです。
サービスの役割はアプリを操作していない間に処理を行うことです。ユーザーがアプリを操作している間に限り処理をメインスレッド以外で実行したい場合は別のスレッドを使用することが推奨されています。
例えばActivityが実行している間だけ音楽を流す場合はActivityのライフサイクルのonCreate()
でスレッドを作成し、onStart()
で実行を開始して、onStop()
で停止するべきだと公式に記述されています。
そうではなくアプリが起動している間音楽を流したい場合はActivityではActivityが破棄されるたびに音楽が止まってしまうのでバックグラウンドで処理を継続して実行できるサービスを使用します。
Serviceでできること
- 基本はメインスレッドなのでバックグラウンドスレッドへは明示的に移行する
- バックグラウンド(アプリ起動中)での処理継続実行
- バックグラウンド(アプリ停止やキル状態)での処理継続実行
バックグラウンドスレッドでの処理の実行はKotlin Coroutines、バックグラウンド(アプリ停止やキル状態)での処理の継続にはWorkManagerなどを使用する方法もあります。
サービスの種類
AndroidのServiceは3種類に分かれています。
Foreground Service
ユーザーが認識できる操作を行うサービス。Foregroundとあるが実際にはバックグラウンドで動作している。例えば音楽を再生するなど。ユーザーがアプリを操作していない間も動作する。
Foregroundとなっている理由は処理を実行中に実行している内容の通知を表示する必要があるため。
Background Service
ユーザーには直接認識できない操作を行うサービス。API操作やファイルの読み込みや書き込みなど内部的な操作を行いたい場合に使用する。
Bind Service
他のコンポーネント(Activityなど)からbindServiceメソッドを使用してバインドされた状態のサービス。コンポーネントからサービスを操作することができる。サービスは複数のコンポーネントからバインドすることができ、全てアンバインドされるとサービスが破棄される。
Serviceの実装方法
流れ
- Serviceを継承したクラスの作成
- マニフェストファイルへ追記
- Serviceを呼び出す
1.Serviceを継承したクラスの作成
いずれのServiceも実装するためにはService
を継承したサブクラスを定義します。Serviceもライフサイクルを保持しているのでオーバーライドして処理を実装して行きます。
onStartCommand
メソッドは実際にサービスで操作したい処理を記述する部分です。返り値としてサービスが突然Killされた場合の挙動を返します。
またonStartCommand
メソッド内はデフォルトではUIスレッド(メインスレッド)で実行されます。
class ExampleService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d("Service", "onStartCommand")
Log.d("Service", Thread.currentThread().getName()) // main
// Intent経由でデータを受け取れる
intent?.getStringExtra("msg")?.let {
Log.d("Intent:", it)
}
// 返り値にサービスが突然Killされた場合の動作を返す
return START_NOT_STICKY // サービスの再起動なし
}
override fun onCreate() {
super.onCreate()
Log.d("Service", "サービスが作成されたよ")
}
override fun onDestroy() {
super.onDestroy()
Log.d("Service", "サービスが破棄されたよ")
}
override fun onBind(intent: Intent): IBinder {
Log.d("Service", "サービスがバインドされたよ(Bind Service)")
}
override fun onTaskRemoved(rootIntent: Intent?) {
super.onTaskRemoved(rootIntent)
Log.d("Service", "タスクが削除されたよ")
}
}
START_NOT_STICKY
再起動なし。
START_STICKY
再起動しonStartCommandメソッドを呼び出す。ただし再起動時にインテントがnullになることがある。
START_REDELIVER_INTENT
再起動しonStartCommandメソッドを呼び出す。最後に渡されたインテントを再度サービスに渡す。
2.マニフェストファイルへ追記
プロジェクト内にServiceを追加した場合は「AndroidManifest.kt」へ追加したServiceを明記する必要があります。新規ファイルを追加する際に「Service」を選択していればここは自動で記述してくれます。
<manifest ...>
...
<application ...>
<service
android:name=".ExampleService"
android:enabled="true"
android:exported="false" />
</application>
</manifest>
android:enabled
Serviceがシステムによって実行可能かどうか。
android:exported
他のアプリケーションからサービスが起動されるかどうか。
3.Serviceを呼び出す
ActivityからServiceを呼び出す際はstartService
メソッドを使用します。引数にIntent
を渡すことで値を渡すことも可能です。実行されたサービスを停止するためにはstopService
メソッドを使用します。
おすすめ記事:【Kotlin/Android Studio】Intentとは?Activity間のデータの受け渡し
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val buttonStart: Button = findViewById(R.id.button)
val buttonStop: Button = findViewById(R.id.button2)
buttonStart.setOnClickListener {
val intent = Intent(this, ExampleService::class.java)
intent.putExtra("msg", "Hello World!!")
startService(intent)
buttonStart.isEnabled = false
buttonStop.isEnabled = true
}
buttonStop.setOnClickListener {
val intent = Intent(this, ExampleService::class.java)
stopService(intent)
buttonStart.isEnabled = true
buttonStop.isEnabled = false
}
}
}
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。