728x90
반응형
참고 교재 : Joyce의 안드로이드 앱 프로그래밍 - 홍정아
전체 코드가 궁금하다면 아래 링크를 참고하시길 바랍니다.
원본 코드 : Joyce의 안드로이드 앱 프로그래밍 - 홍정아
5. 서비스 클래스 구현하기

[com.example.simplemusicplayer] 을 우클릭하여 [New] → [Kotlin Class/File] 클릭
Class를 선택한채로 MusicPlayerService라는 이름의 클래스 파일 생성
우선 서비스 클래스의 뼈대를 만들겠습니다.

[MusicPlayerService.kt] 의 뼈대 코드
package com.example.simplemusicplayer
import android.app.Service
import android.content.Intent
import android.os.IBinder
class MusicPlayerService : Service() {
override fun onCreate() { // 서비스가 생성될 때 딱 한 번만 실행
super.onCreate()
startForegroundService() // 포그라운드 서비스 : 상태 표시줄에 알림을 생성
}
// 구성요소에서 bindService() 함수를 호출할 때 실행, 서비스와 구성요소를 이어주는 매개체 IBinder 반환
// 시작되고 바인드된 서비스이므로 반드시 구현, 바인드가 필요 없는 서비스는 null 반환
override fun onBind(intent: Intent?): IBinder? {
TODO("NOT yet implemented")
}
// startService()나 startForegroundService() 호출할 때 실행, 시작된 상태 및 백그라운드에 존재
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return super.onStartCommand(intent, flags, startId)
}
// 서비스 생명 주기의 마지막 단계, onCreate()에서 상태표시줄에 보여주었던 알림 해제
override fun onDestroy() {
super.onDestroy()
}
fun startForegroundService() {} // 알림 채널 생성, API 26부터는 서비스 실행됨을 알림
fun isPlaying() {} // 재생 중인지 확인
fun play() {} // 재생
fun pause() {} // 일시정지
fun stop() {} // 완전 정지
}

class MusicPlayerService : Service() {
var mMediaPlayer: MediaPlayer? = null // 미디어 플레이어 객체 초기화
var mBinder: MusicPlayerBinder = MusicPlayerBinder() // mBinder 객체 생성
// 내부 클래스 MusicPlayerBinder 생성, Binder 상속
inner class MusicPlayerBinder : Binder() {
fun getService(): MusicPlayerService { // getService 함수를 가지고 있음
return this@MusicPlayerService // 현재 서비스 반환 → 연결된 구성요소가 서비스의 함수 사용 가능
}
}

override fun onCreate() { // 서비스가 생성될 때 딱 한 번만 실행
super.onCreate()
startForegroundService() // 포그라운드 서비스 : 상태 표시줄에 알림을 생성
}
// 구성요소에서 bindService() 함수를 호출할 때 실행, 서비스와 구성요소를 이어주는 매개체 IBinder 반환
// 시작되고 바인드된 서비스이므로 반드시 구현, 바인드가 필요 없는 서비스는 null 반환
override fun onBind(intent: Intent?): IBinder? {
return mBinder // 위에서 생성한 mBinder 객체를 반환값으로 전달
}
// startService()나 startForegroundService() 호출할 때 실행, 시작된 상태 및 백그라운드에 존재
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
// 반드시 정숫값 반환, 시스템이 서비스를 중단하면 서비스 다시 실행, onStartCommand() 함수 호출
return START_STICKY
}
// 서비스 생명 주기의 마지막 단계, onCreate()에서 상태표시줄에 보여주었던 알림 해제
override fun onDestroy() {
super.onDestroy()
}
fun startForegroundService() {} // 알림 채널 생성, API 26부터는 서비스 실행됨을 알림
fun isPlaying() {} // 재생 중인지 확인
fun play() {} // 재생
fun pause() {} // 일시정지
fun stop() {} // 완전 정지
}

// 알림 채널 생성, API 26부터는 서비스 실행됨을 알림
fun startForegroundService() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
val notificationManager = getSystemService(NOTIFICATION_SERVICE)
as NotificationManager
val mChannel = NotificationChannel( // 알림 채널 생성
"CHANNEL_ID",
"CHANNEL_NAME",
NotificationManager.IMPORTANCE_DEFAULT
)
notificationManager.createNotificationChannel(mChannel)
}
// 알림 생성
val notification: Notification = Notification.Builder(this, "CHANNEL_ID")
.setSmallIcon(R.drawable.ic_play)
.setContentTitle("뮤직 플레이어 앱")
.setContentText("앱이 실행 중입니다.")
.build()
// 서비스를 포그라운드 서비스로 만듬, startForeground(알림의 식별자, 보여줄 알림)
startForeground(1, notification)
}

// 서비스 생명 주기의 마지막 단계, onCreate()에서 상태표시줄에 보여주었던 알림 해제
// 서비스 중단 처리
override fun onDestroy() {
super.onDestroy()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
stopForeground(true); // 포그라운드 서비스를 멈춤
}
}
// 재생 중인지 확인
fun isPlaying() : Boolean{
return (mMediaPlayer != null && mMediaPlayer?.isPlaying ?: false)
}

// 재생
fun play() {
if (mMediaPlayer == null) {
// 음악 파일 리소스를 가져와 미디어 플레이어 개체 할당
mMediaPlayer = MediaPlayer.create(this, R.raw.chocolate)
mMediaPlayer?.setVolume(1.0f, 1.0f); // 볼륨 지정
mMediaPlayer?.isLooping = true // 반복재생 여부를 정함
mMediaPlayer?.start() // 음악 재생
} else { //mMediaPlayer가 이미 있고
if (mMediaPlayer!!.isPlaying) { // 음악 재생 중인 경우
Toast.makeText(this, "이미 음악이 실행 중입니다.",
Toast.LENGTH_SHORT).show()
} else { // 일시정지 상태이면
mMediaPlayer?.start() // 음악을 재생
}
}
}

// 일시정지
fun pause() {
mMediaPlayer?.let {
if (it.isPlaying) { // 음악이 실행중이면
it.pause() // 음악을 일시정지
}
}
}
// 재생중지
fun stop() {
mMediaPlayer?.let {
if (it.isPlaying) {
it.stop() // 음악을 멈춤
it.release() // 미디어 플레이어에 할당된 자원을 해제
mMediaPlayer = null
}
}
}
}

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<service
android:name="com.example.simplemusicplayer.MusicPlayerService" />
MusicPlayerService.kt 전체 코드
package com.example.simplemusicplayer
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Intent
import android.media.MediaPlayer
import android.os.Binder
import android.os.Build
import android.os.IBinder
import android.widget.Toast
class MusicPlayerService : Service() {
var mMediaPlayer: MediaPlayer? = null // 미디어 플레이어 객체 초기화
var mBinder: MusicPlayerBinder = MusicPlayerBinder() // mBinder 객체 생성
// 내부 클래스 MusicPlayerBinder 생성, Binder 상속
inner class MusicPlayerBinder : Binder() {
fun getService(): MusicPlayerService { // getService 함수를 가지고 있음
return this@MusicPlayerService // 현재 서비스 반환 → 연결된 구성요소가 서비스의 함수 사용 가능
}
}
override fun onCreate() { // 서비스가 생성될 때 딱 한 번만 실행
super.onCreate()
startForegroundService() // 포그라운드 서비스 : 상태 표시줄에 알림을 생성
}
// 구성요소에서 bindService() 함수를 호출할 때 실행, 서비스와 구성요소를 이어주는 매개체 IBinder 반환
// 시작되고 바인드된 서비스이므로 반드시 구현, 바인드가 필요 없는 서비스는 null 반환
override fun onBind(intent: Intent?): IBinder? {
return mBinder // 위에서 생성한 mBinder 객체를 반환값으로 전달
}
// startService()나 startForegroundService() 호출할 때 실행, 시작된 상태 및 백그라운드에 존재
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
// 반드시 정숫값 반환, 시스템이 서비스를 중단하면 서비스 다시 실행, onStartCommand() 함수 호출
return START_STICKY
}
// 알림 채널 생성, API 26부터는 서비스 실행됨을 알림
fun startForegroundService() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
val notificationManager = getSystemService(NOTIFICATION_SERVICE)
as NotificationManager
val mChannel = NotificationChannel( // 알림 채널 생성
"CHANNEL_ID",
"CHANNEL_NAME",
NotificationManager.IMPORTANCE_DEFAULT
)
notificationManager.createNotificationChannel(mChannel)
}
// 알림 생성
val notification: Notification = Notification.Builder(this, "CHANNEL_ID")
.setSmallIcon(R.drawable.ic_play)
.setContentTitle("뮤직 플레이어 앱")
.setContentText("앱이 실행 중입니다.")
.build()
// 서비스를 포그라운드 서비스로 만듬, startForeground(알림의 식별자, 보여줄 알림)
startForeground(1, notification)
}
// 서비스 생명 주기의 마지막 단계, onCreate()에서 상태표시줄에 보여주었던 알림 해제
// 서비스 중단 처리
override fun onDestroy() {
super.onDestroy()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
stopForeground(true); // 포그라운드 서비스를 멈춤
}
}
// 재생 중인지 확인
fun isPlaying() : Boolean{
return (mMediaPlayer != null && mMediaPlayer?.isPlaying ?: false)
}
// 재생
fun play() {
if (mMediaPlayer == null) {
// 음악 파일 리소스를 가져와 미디어 플레이어 개체 할당
mMediaPlayer = MediaPlayer.create(this, R.raw.chocolate)
mMediaPlayer?.setVolume(1.0f, 1.0f); // 볼륨 지정
mMediaPlayer?.isLooping = true // 반복재생 여부를 정함
mMediaPlayer?.start() // 음악 재생
} else { //mMediaPlayer가 이미 있고
if (mMediaPlayer!!.isPlaying) { // 음악 재생 중인 경우
Toast.makeText(this, "이미 음악이 실행 중입니다.",
Toast.LENGTH_SHORT).show()
} else { // 일시정지 상태이면
mMediaPlayer?.start() // 음악을 재생
}
}
}
// 일시정지
fun pause() {
mMediaPlayer?.let {
if (it.isPlaying) { // 음악이 실행중이면
it.pause() // 음악을 일시정지
}
}
}
// 재생중지
fun stop() {
mMediaPlayer?.let {
if (it.isPlaying) {
it.stop() // 음악을 멈춤
it.release() // 미디어 플레이어에 할당된 자원을 해제
mMediaPlayer = null
}
}
}
}
※ 본 게시글은 'Joyce의 안드로이드 앱 프로그래밍 - 홍정아' 책의 내용과
Android Developers의 공식문서 내용을 참고하여 작성하였습니다.
전체 코드가 궁금하다면 아래 링크를 참고하시길 바랍니다.
728x90
반응형
'안드로이드(Android)' 카테고리의 다른 글
| com.android.support 리팩토링하기(과거 라이브러리 리팩토링) (0) | 2023.04.08 |
|---|---|
| 뮤직 플레이어(MusicPlayer)_6 [Android_Kotlin] (0) | 2023.03.20 |
| 뮤직 플레이어(MusicPlayer)_4 [Android_Kotlin] (0) | 2023.02.21 |
| 뮤직 플레이어(MusicPlayer)_3 [Android_Kotlin] (0) | 2023.02.17 |
| 뮤직 플레이어(MusicPlayer)_2 [Android_Kotlin] (0) | 2023.02.16 |