[Android & Kotlin] Service でバックグラウンド処理

Servce はバックグラウンドで作業をさせたい場合に使います。システムは直ぐにスリープに入れてしまいます。それでも裏で色々やりたい場合に有効です。例えば音楽の再生など

Android Studio
2024.1.1




Service

 

Serviceがバックグラウンドで動作するので、非同期と勘違いしそうですがそうではなく、Activityから表示UIを無くしたようなコンポーネントです。

サービスは、そのホスティング プロセスのメインスレッドで実行され、サービスが自身のスレッドを作成することはなく、別のプロセスで実行されることもありません
CPU を集中的に使う作業、Audioの再生やネットワーク作業など、を行う場合は、サービス内に新しいスレッドを作成してその作業を行う必要があります
 

 

Serviceの開始

 

Serviceを開始するには、

  1. startService()
    • 開始後は、開始したActivityが破棄されても基本的には実行し続けられる、Activityとは別の独自のContextを持っている
    • 呼び出し側からの制御は開始か停止させるのみで、タスクの終了をコールバックしないので自身で終了するなどの手当が必要
  2. bindService()
    • 要求を送信したり、結果を取得したりとServiceを制御できますが、呼び出し元のActivityが終了すると一緒に終了してしまう

これにAndroid 8.0からの追加として、

startForegroundService()

を使ってバックグラウンド実行制限をある程度回避できます。
また、API 28からAndroidMnifestにpermission登録が必要になりました
さらにAPI34からはフォアグラウンド サービスタイプの設定が必要です

 

startService()

 

Activity からServiceを呼び出すのはIntent をセットして、startService(intent) で行い
アプリの安全性のため明示的インテントを使用
 

 
Activity から Activity に遷移させる場合は
startActivity(intent)でしたので、startService(intent)に変わっただけとわかりやすです
 
一方、サービス側は

 
Service を継承して

  1. onCreate()
    • これはActivity同様、最初だけ呼ばれて終わりなので初期化だけです。
  2. onStartCommand()
    • サービスで実行させたいコードはここに記述
    • 戻り値は:
      • START_NOT_STICY:強制終了しても再起動しない
      • START_STICKY:強制終了されても自動的にサービスが再起動、最後のインテントは再配信しない
      • START_REDELIVER_INTENT:強制終了されても自動的にサービスが再起動、サービスに最後に配信されたインテントで onStartCommand() を呼び出す
  3. onDestroy()
  4. onBind()
    • bindService() で呼び出した場合
      onStartCommand() ではなく
      onBind() がcallbackされます

 

Manifest にサービスクラスの定義を忘れないように

パーミッション
サービスタイプの指定

AndroidManifest.xml

 

 

Serviceの終了

 

startService()で始めたServiceは勝手には止まりません。
 
MainActivityからstopService(intent)で止める
 

 
サービスが自身で止められるようにするには、stopSelf()を使います
 

 
Oreoからバックグラウンドに対する制限ができて

アプリがバックグラウンドに移行すると数分間のウィンドウが提供され、アプリはそのウィンドウ内でサービスを作成して使用できます。
 
そのウィンドウの終了時に、アプリは?アイドル状態?であると見なされます。 システムはこの時点で、アプリがサービスの?Service.stopSelf()?メソッドを呼び出したかのように、アプリのバックグラウンド サービスを停止します。

バックグラウンド実行制限 | Android Developers 

またマルチタスクメニューからアプリをユーザーが終了させることもあります。

 

startForegroundService()

 

バックグラウンドでアプリが実行できないと、一番困るのはmusic系のアプリでしょうか、それについては
バックグラウンド実行制限 | Android Developersにはこのような一文があります。

システムは、バックグラウンド アプリによるバッグラウンド サービスの作成を許可しません。
そのため、Android 8.0 では、フォアグラウンドで新しいサービスを作成する Context.startForegroundService() メソッドが新たに導入されています。

システムによってサービスが作成されると、アプリは、サービスの startForeground() メソッドを 5 秒以内に呼び出して、
その新しいサービスの通知をユーザーに表示します。
アプリが startForeground() を制限時間内に呼び出さない場合、サービスが停止し、アプリが ANR になります。

ということでこれを使ってMediaPlayerでをServiceで音楽再生してみます。

 

サンプルコード

 

ActivityからServiceを開始し、Service内で5秒以内にstartForegroundを呼び出します。

これでステータスバーにはアイコンが表示されてForgroundにいるかのようになります

1x1.trans - [Android & Kotlin] Service でバックグラウンド処理

Screenshot

 

MainActivityではServiceの開始とストップのためのボタンを設置

MainActivity.kt

 
サービス側では、MediaPlayerを使ってmp3を再生させてみます。
MediaPlayerについてはこちらで解説しています。

mediaplyer a01 100x100 - [Android & Kotlin] Service でバックグラウンド処理
MediaPlayer()を使って簡単な音楽再生アプリが作れます。Audioを扱うものとしては他にはSoundPoolやAudioTrack...

Rawフォルダーを作成して適当なmp3の音楽ファイルを入れておきます。

1x1.trans - [Android & Kotlin] Service でバックグラウンド処理


以下のKotlinクラスを作成しコーディング

TestService.kt

 

マニュフェストに追加するものは、

  • FOREGROUND_SERVICEのpermission設定
  • <service … />の追加とサービスタイプの指定
    • android:foregroundServiceType=”mediaPlayback”
  • バックグラウンドに入った後で、通知からActivityを起動させるための<activity>設定
    • android:taskAffinity=””
    • android:excludeFromRecents=”true”

AndroidManifest.xml

 

以下にレイアウトやリソースがあります

レイアウトです。簡単にするためLinearLayoutを使いました。
activity_main.xml

 
strings.xml

 
これでアプリを終了、マルチタスクメニューから削除してもmp3が再生されています。
 
フォアグラウンドサービスはAPIによって変更が多々あるので確認が必要です

 
ただし、あまり調子に乗っていると、Systemから「○○が電池をしようしています」とユーザーにチクられます。

 
関連ページ:

 

References:
サービス | Android Developers
バックグラウンド実行制限 | Android Developers
Service | Android Developers

シェアする

  • このエントリーをはてなブックマークに追加

フォローする