[Android] Service の使い方

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

Android Studio
2021.2.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登録が必要になりました。

 

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

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

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

 

サンプルコード

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

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

1x1.trans - [Android] Service の使い方


 

マニュフェストには、

  • FOREGROUND_SERVICEのpermission設定
  • <service … />の追加
  • バックグラウンドに入った後で、通知からActivityを起動させるための<activity>設定

 


 

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

MainActivity.java


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

https://akira-watson.com/android/audio-player.html

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

1x1.trans - [Android] Service の使い方


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

TestService.java


 

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


 
strings.xml

 
これでアプリを終了、マルチタスクメニューから削除してもmp3が再生されています。
 
1x1.trans - [Android] Service の使い方


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

 1x1.trans - [Android] Service の使い方


 
注意点:簡単なAudio再生をServiceとForegroundでやった例で、実際には検討すべき点があります
  • あくまでメインスレッドでのAudio再生なので、別スレッド作成の必要性があるか検討
  • システムにより強制終了させられた場合に、START_STICKYあるいはSTART_REDELIVER_INTENTを使用して再起動させるか検討
  • 今更ですがAndroid12から、フォアグラウンド サービスの起動に関する制限があります。非推奨ではないのですが…

    注: あるアプリが、別のアプリが所有しているフォアグラウンド サービスを起動するために Context.startForegroundService() を呼び出すとき、両方のアプリが Android 12 をターゲットとしている場合にのみ、このページで説明する制限が適用されます。

    フォアグラウンド サービスの起動に関する制限

 
関連ページ:

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

シェアする

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

フォローする