<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>
<service
android:name=".MyMediaPlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="false">
</service>
</manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>
//29이상일 때
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
// 34 이상일 때
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA"/>
<application ...>
...
</application>
</manifest>
서비스는 백그라운에서 실행된다는데 포그라운드?
status notification을 통해서 사용자에게 서비스가 작동하고 있다는 걸 알린기 때문에 foreground이다.
ex. 뮤직 재생 중인 상태바 플레이어, 사용자 위치나 건강상태 측정 중.. 같은 것
어떤 foreground service를 사용하는지 알려줘야 한다.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" ...>
<service
android:name=".MyMediaPlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="false">
</service>
</manifest>
START_NOT_STIKCY
START_STICKY
START_REDELIVER_INTENT

service로 오디오를 재생하는데 액티비티에서 button으로 호출할 수 있는 기능을 만들어본다면
class AudioService : Service() {
// Binder given to clients.
private val audioBinder by lazy { AudioBinder() }
// Random number generator.
private var mediaPlayer: MediaPlayer? = null
/** Method for clients. */
var isPlaying: Boolean = false
fun play() {
if (isPlaying) return
mediaPlayer?.start()
isPlaying = true
}
fun pause() {
if (isPlaying.not()) return
mediaPlayer?.pause()
isPlaying = false
}
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
iinner class AudioBinder : Binder() {
// Return this instance of LocalService so clients can call public methods.
fun getService(): AudioService = this@AudioService
}
override fun onBind(intent: Intent): IBinder {
return audioBinder
}
override fun onDestroy() {
super.onDestroy()
mediaPlayer?.stop()
mediaPlayer?.release()
mediaPlayer = null
}
}
class BindingActivity : Activity() {
private lateinit var audioService: AudioService
private var isBound: Boolean = false
/** Defines callbacks for service binding, passed to bindService(). */
private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) {
// We've bound to AudioService, cast the IBinder and get LocalService instance.
val binder = service as AudioService.AudioBinder
audioService = binder.getService()
isBound = true
}
override fun onServiceDisconnected(arg0: ComponentName) {
isBound = false
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main)
}
override fun onStart() {
super.onStart()
Intent(this, AudioService::class.java).also { intent ->
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
}
override fun onStop() {
super.onStop()
unbindService(connection)
isBound.value = false
}
/** Called when a button is clicked (the button in the layout file attaches to
* this method with the android:onClick attribute). */
private fun onButtonClick() {
if (isBound.value) {
if (audioService.isPlaying) audioService.pause()
else {
audioService.play()
}
} else {
audioService.play()
}
}
}
started service
bound service
https://developer.android.com/develop/background-work/background-tasks
https://developer.android.com/develop/background-work/services/foreground-services
https://developer.android.com/develop/background-work/services/bound-services