では、AndroidStudioを使ってServiceを追加してみよう。
特に何かしたいわけでもないので、毎分logcatで何か出し続けるようにしてみる。そうすればいつアプリが終了させられたのかもわかりやすいんじゃなかろうか。
デフォルトをちょっと変更したプロジェクトの設定はこんな感じ。
家にあるAndroid端末で一番古いのがNougatなので、Min SDK Versionはこの辺にしている。
プロジェクトを新規作成して取りあえずビルドしてみたのだが、トップディレクトリにあるbuild.gradleのjcenter()でwarningが出ていた。
JCenter サービスの更新 | Android デベロッパー | Android Developers
https://developer.android.com/studio/build/jcenter-migration
既存のものは無期限にダウンロードできます、といっても「閉鎖されるまでは」という条件が付くだろう。メンテナンスしないとしても電気代はかかるし、自社サーバだったらストレージが故障したりするし、クラウドだったらストレージの費用も馬鹿にならんし。
Serviceを追加する!と気合いを入れずとも、AndroidStudioならメニュー操作で基本的なところはやってくれそうだ。
2つある・・・?
"Service"の場合
"Service(IntentService)"の場合
ちなみにActivityのあるディレクトリ?以外で実行するとどこに組み込むかのコンボボックスが増えていた。
main, debug, releaseの3択だったのだが、特定のVariantにだけ追加する(debug, release)か、全部に追加する(main)かを選んでいるのだろうか。
Build Variantsを追加すると増えていたので、たぶんそうなんだろう。
まずは、ただのServiceを追加した場合。
ファイルの追加
app\src\main\java\com\example\sample0\MyService.kt
01: package com.example.sample0
02:
03: import android.app.Service
04: import android.content.Intent
05: import android.os.IBinder
06:
07: class MyService : Service() {
08:
09: override fun onBind(intent: Intent): IBinder {
10: TODO("Return the communication channel to the service.")
11: }
12: }
AndroidManifest.xmlに追記。
01: <service
02: android:name=".MyService"
03: android:enabled="true"
04: android:exported="true"></service>
こちらはIntentServiceを追加した場合。
ファイルの追加
app/src/main/java/com/example/sample0/MyIntentService.kt
01: package com.example.sample0
02:
03: import android.app.IntentService
04: import android.content.Intent
05: import android.content.Context
06:
07: // TODO: Rename actions, choose action names that describe tasks that this
08: // IntentService can perform, e.g. ACTION_FETCH_NEW_ITEMS
09: private const val ACTION_FOO = "com.example.sample0.action.FOO"
10: private const val ACTION_BAZ = "com.example.sample0.action.BAZ"
11:
12: // TODO: Rename parameters
13: private const val EXTRA_PARAM1 = "com.example.sample0.extra.PARAM1"
14: private const val EXTRA_PARAM2 = "com.example.sample0.extra.PARAM2"
15:
16: /**
17: * An [IntentService] subclass for handling asynchronous task requests in
18: * a service on a separate handler thread.
19:
20: * TODO: Customize class - update intent actions, extra parameters and static
21: * helper methods.
22:
23: */
24: class MyIntentService : IntentService("MyIntentService") {
25:
26: override fun onHandleIntent(intent: Intent?) {
27: when (intent?.action) {
28: ACTION_FOO -> {
29: val param1 = intent.getStringExtra(EXTRA_PARAM1)
30: val param2 = intent.getStringExtra(EXTRA_PARAM2)
31: handleActionFoo(param1, param2)
32: }
33: ACTION_BAZ -> {
34: val param1 = intent.getStringExtra(EXTRA_PARAM1)
35: val param2 = intent.getStringExtra(EXTRA_PARAM2)
36: handleActionBaz(param1, param2)
37: }
38: }
39: }
40:
41: /**
42: * Handle action Foo in the provided background thread with the provided
43: * parameters.
44: */
45: private fun handleActionFoo(param1: String?, param2: String?) {
46: TODO("Handle action Foo")
47: }
48:
49: /**
50: * Handle action Baz in the provided background thread with the provided
51: * parameters.
52: */
53: private fun handleActionBaz(param1: String?, param2: String?) {
54: TODO("Handle action Baz")
55: }
56:
57: companion object {
58: /**
59: * Starts this service to perform action Foo with the given parameters. If
60: * the service is already performing a task this action will be queued.
61: *
62: * @see IntentService
63: */
64: // TODO: Customize helper method
65: @JvmStatic
66: fun startActionFoo(context: Context, param1: String, param2: String) {
67: val intent = Intent(context, MyIntentService::class.java).apply {
68: action = ACTION_FOO
69: putExtra(EXTRA_PARAM1, param1)
70: putExtra(EXTRA_PARAM2, param2)
71: }
72: context.startService(intent)
73: }
74:
75: /**
76: * Starts this service to perform action Baz with the given parameters. If
77: * the service is already performing a task this action will be queued.
78: *
79: * @see IntentService
80: */
81: // TODO: Customize helper method
82: @JvmStatic
83: fun startActionBaz(context: Context, param1: String, param2: String) {
84: val intent = Intent(context, MyIntentService::class.java).apply {
85: action = ACTION_BAZ
86: putExtra(EXTRA_PARAM1, param1)
87: putExtra(EXTRA_PARAM2, param2)
88: }
89: context.startService(intent)
90: }
91: }
92: }
AndroidManifest.xmlに追記。
01: <service
02: android:name=".MyIntentService"
03: android:exported="false"></service>
なぜか知らんが、AndroidManifest.xmlはさっき追記した <service ...></service> が <service ... /> に置き換えられた。
名前に同じ「Service」が付いているものの、全然似たところがない。
だがIntentServiceはServiceの派生クラスだ。
と思ったら! IntentServiceはAPI 30からdeprecatedとのことだ。代わりに androidx.work.WorkManager とか androidx.core.app.JobIntentService を使うことをおすすめされている。
WorkManager はバックグラウンドタスクのところに出ていた。 JobIntentService は「作業ステータスを報告する」に出てきていた。
一つ分かったのは、初学者にとってはclassから調べていくのは効率が悪そうだ、ということだ。「人間とは何か」を調べる命題があったとして、細胞とか動植物から調べ始めるようなもので、間違っているわけではないけど後で調べた方が効率がよさそう、というやつだ。
そして・・・私はIntentServiceは忘れることにした。
私のバッファはそんなに大きくないのだ。