[Android] Service ์ •๋ฆฌ

Minjun Kimยท2023๋…„ 9์›” 12์ผ
0

Android

๋ชฉ๋ก ๋ณด๊ธฐ
38/47
post-thumbnail

๐Ÿ“ SeSAC์˜ 'JetPack๊ณผ Kotlin์„ ํ™œ์šฉํ•œ Android App ๊ฐœ๋ฐœ' ๊ฐ•์ขŒ๋ฅผ ์ •๋ฆฌํ•œ ๊ธ€ ์ž…๋‹ˆ๋‹ค.


๐Ÿ“ก ์„œ๋น„์Šค ๊ฐœ์š”

์•ˆ๋“œ๋กœ์ด๋“œ 4๊ฐœ ์ปดํฌ๋„ŒํŠธ ์ค‘ ํ•˜๋‚˜๋กœ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์—…๋ฌด ๋ฅผ ๋‹ด๋‹นํ•˜๊ธฐ ์œ„ํ•œ ์ปดํฌ๋„ŒํŠธ.

  • ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์˜ค๋žœ ์‹œ๊ฐ„ ๋™์•ˆ ์ˆ˜ํ–‰๋˜๋Š” ์—…๋ฌด๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ์ปดํฌ๋„ŒํŠธ

  • ํ™”๋ฉด ์ถœ๋ ฅ ๋Šฅ๋ ฅ์€ ๊ฐ€์ง€์ง€ ์•Š๋Š” ์ปดํฌ๋„ŒํŠธ

Thread ํ˜น์€ Coroutine ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•กํ‹ฐ๋น„ํ‹ฐ์—์„œ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์—…๋ฌด๋ฅผ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿผ only ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ž‘์—…์ธ ์„œ๋น„์Šค์™€ ๋ฌด์—‡์ด ๋‹ค๋ฅผ๊นŒ?

ํ™”๋ฉด์—์„œ ๋ฐ˜์‘์„ ๋ฐ›๊ฑฐ๋‚˜ ์ฒ˜๋ฆฌ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ํ™”๋ฉด์— ์ถœ๋ ฅํ•ด์•ผ ๋˜๋Š” ๊ฒฝ์šฐ ๊ฐ™์€ ํ™”๋ฉด๊ณผ ๊ด€๋ จ๋œ ์—…๋ฌด๋ผ๋ฉด ์•กํ‹ฐ๋น„ํ‹ฐ์—์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ๋งž๋‹ค. ๋•Œ๋ฌธ์— ๋ชจ๋“  ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์—…๋ฌด๋ฅผ ์„œ๋น„์Šค๋กœ ๋นผ๋Š” ๊ฒƒ์€ ์ข‹์ง€ ์•Š๋‹ค. ๋ฌผ๋ก  ํ™”๋ฉด ๊ด€๋ จ ์ž‘์—…๋„ ๊ฐ•์ œ์ ์œผ๋กœ ์„œ๋น„์Šค๋กœ ๋บ„ ์ˆ˜ ์žˆ๊ธด ํ•˜๋‹ค๊ณ  ํ•œ๋‹ค.

๊ทธ๋ž˜์„œ ์„œ๋น„์Šค๋Š” ํ™”๋ฉด ๋ฐ˜์‘์„ฑ์ด ์•„์˜ˆ ์—†๊ฑฐ๋‚˜ ๋“œ๋ฌผ๊ฒŒ ๋ฐœ์ƒํ•˜๋Š” ์—…๋ฌด๋ฅผ ๋‹ด๋‹นํ•œ๋‹ค. ํŠนํžˆ ์œ ์ € ํ•ธํŠธํฐ ํ™”๋ฉด์— ๋‹ค๋ฅธ ์•ฑ์ด ๋„์›Œ์ ธ ์žˆ์–ด๋„ ์šฐ๋ฆฌ ์•ฑ์ด ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ƒํ™ฉ์„ ๋Œ€ํ‘œ์ ์œผ๋กœ ๋“ค ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ“š Service ํด๋ž˜์Šค

class MyService : Service() {
	override fun onBind(intent: Intent): IBinder? {
    	return null
    }
}
  • Service ๋ฅผ ์ƒ์† ๋ฐ›์•„ ์ž‘์„ฑ

  • onBind() ํ•จ์ˆ˜๋Š” ๋‚ด๋ถ€๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๋”๋ผ๋„ ๋ฐ˜๋“œ์‹œ ์˜ค๋ฒ„๋ผ์ด๋“œ ๋ฐ›์•„์•ผ ํ•œ๋‹ค.

๐Ÿ“š Manifest ๋“ฑ๋ก

์„œ๋น„์Šค๋„ ์ปดํฌ๋„ŒํŠธ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋“ฑ๋กํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

<service
	android:name=".MyService"
    android:enabled="true"
    android:exported="true"></service>
  • AndroidManifest.xml ์— ๋“ฑ๋ก

  • <service> ํƒœ๊ทธ๋กœ ๋“ฑ๋กํ•˜๋ฉฐ <name> ์†์„ฑ์€ ์ƒ๋žต ๋ถˆ๊ฐ€

๐Ÿ“š startService()

val intent = Intent(this, MyService::class.java)
startService(intent)
  • startService() ์— ์˜ํ•œ ์‹คํ–‰

  • ์™ธ๋ถ€ ์•ฑ์˜ ์„œ๋น„์Šค๋ผ๋ฉด setPackage() ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ์‹คํ–‰ํ•˜๊ณ ์ž ํ•˜๋Š” ์•ฑ์˜ ํŒจํ‚ค์ง€๋ช…(์‹๋ณ„์ž) ์„ ๋ช…์‹œ

๐Ÿ“š stopService()

4๊ฐœ์˜ ์ปดํฌ๋„ŒํŠธ ์ค‘์— ์œ ์ผํ•˜๊ฒŒ ์„œ๋น„์Šค๋งŒ ์ข…๋ฃŒํ•˜๊ธฐ ์œ„ํ•œ ์ธํ…ํŠธ ํ•จ์ˆ˜๋„ ์กด์žฌํ•œ๋‹ค.

โ“ ์ œ๊ณตํ•˜๋Š” ์ด์œ ๋Š”

์„œ๋น„์Šค๋Š” ํ•œ ๋ฒˆ ๊ตฌ๋™๋˜๋ฉด ๋Œ€๋ถ€๋ถ„ ์ž‘์—… ์‹œ๊ฐ„์ด ๊ธธ๊ณ , ํ™”๋ฉด ๋ฐ˜์‘์„ฑ์ด ์—†์–ด ์œ ์ €์— ์˜ํ•ด ์ข…๋ฃŒ๋  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

val intent = Intent(this, MyService::class.java)
stopService(intent)
  • ์„œ๋น„์Šค๋ฅผ ์ข…๋ฃŒ ์‹œํ‚ค๊ณ  ์‹ถ๋‹ค๋ฉด stopService() ํ•จ์ˆ˜๋กœ ์ธํ…ํŠธ ๋ฐœ์ƒ

๐Ÿ“ก Service Lifecycle

์•ˆ๋“œ๋กœ์ด๋“œ ์ปดํฌ๋„ŒํŠธ ์ค‘์—์„œ ์•กํ‹ฐ๋น„ํ‹ฐ์™€ ์„œ๋น„์Šค์˜ ๋ผ์ดํ”„์‚ฌ์ดํด์€ ์ •๋ฆฌํ•ด ๋†“์•„์•ผ ํ•œ๋‹ค.

  • ์„œ๋น„์Šค๋ฅผ ์‹คํ–‰์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•์ด startService() ํ•จ์ˆ˜์™€ bindService() ํ•จ์ˆ˜ ๋‘ ๊ฐœ๊ฐ€ ์žˆ๋‹ค.

  • ์–ด๋Š ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ์„œ๋น„์Šค๊ฐ€ ์‹คํ–‰ ๋˜๋Š”์ง€์— ๋”ฐ๋ผ ์„œ๋น„์Šค์˜ ๋ผ์ดํ”„ ์‚ฌ์ดํด์ด ๋‹ฌ๋ผ์ง„๋‹ค.

  • ์„œ๋น„์Šค ํด๋ž˜์Šค๋Š” ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

๐Ÿ“š startService ์˜ Lifecycle

์ตœ์ดˆ์˜ ์„œ๋น„์Šค ์ธํ…ํŠธ ๋ฐœ์ƒ ์‹œ onCreate() ๊ฐ€ ํ˜ธ์ถœ ๋˜๋ฉด์„œ ์„œ๋น„์Šค ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  stopService() ํ˜ธ์ถœ ์‹œ onDestroy() ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด์„œ ์„œ๋น„์Šค๋Š” ๋ฉˆ์ถ˜๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋งŒ์•ฝ ์„œ๋น„์Šค ๊ตฌ๋™ ์ค‘์—
๋‘ ๋ฒˆ์งธ ์ธํ…ํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

onStartCommand() ๋งŒ ๋‹ค์‹œ ํ˜ธ์ถœ๋œ๋‹ค. ์„œ๋น„์Šค๋Š” ์‹ฑ๊ธ€ํ†ค์ด๊ธฐ ๋•Œ๋ฌธ์— onCreate() ํ•จ์ˆ˜๋Š” ์„œ๋น„์Šค ๊ฐ์ฒด ์ƒ์„ฑ ์‹œ ์ตœ์ดˆ์˜ ๋‹จ ํ•œ๋ฒˆ๋งŒ ํ˜ธ์ถœ๋œ๋‹ค. ๊ทธ๋ž˜์„œ ์„œ๋น„์Šค ์š”์ฒญ์„ ๊ตฌ๋ถ„ํ•ด์„œ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด onStartCommand() ์—์„œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค. ๋‚ด๋ถ€์— ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์„ ๊ตฌํ˜„ํ•˜๋Š” ์‹์œผ๋กœ ๋ง์ด๋‹ค.

โ“ ์–ด๋–ป๊ฒŒ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์„๊นŒ?

์„œ๋น„์Šค ์ž์‹ ์„ ์‹คํ–‰์‹œํ‚จ ์ธํ…ํŠธ ์ •๋ณด๋Š” onStartCommand() ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌ๋œ๋‹ค.

๐Ÿ“š bindService ์˜ Lifecycle

startService ์™€์˜ ์ฐจ์ด์ ์€ onCreate() ํ˜ธ์ถœ ์ดํ›„ onBind() ์™€ onUnbind() ๊ฐ€ ํ˜ธ์ถœ ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์‹ฑ๊ธ€ํ†ค์ด๊ธฐ ๋•Œ๋ฌธ์— ๋™์ผํ•˜๊ฒŒ ์ธํ…ํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด onBind() ๋งŒ ๋‹ค์‹œ ํ˜ธ์ถœ๋œ ํ›„, ์ข…๋ฃŒ๋  ๋•Œ ๋‹ค์‹œ onUnbind() ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ ๋œ๋‹ค.


๐Ÿ“ก startService

  • startService() ํ•จ์ˆ˜์— ์˜ํ•ด Service ๊ฐ€ ์‹คํ–‰๋˜๋ฉด ํŠน์ • ๊ฐ์ฒด๊ฐ€ ๋ฆฌํ„ด๋˜์ง€ ์•Š๋Š”๋‹ค.

  • ์ƒํ˜ธ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ์ง์ ‘์ ์ธ ๋ฐฉ๋ฒ•์ด ์—†๋‹ค.

  • BroadcastReceiver ๋ฅผ ์ •์˜ํ•˜๊ณ  ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์ด ํ•„์š”ํ•  ๋•Œ ์ด BroadcastReceiver ๋ฅผ ์‹คํ–‰ ์‹œํ‚ค๋ฉด์„œ Broadcast Intent ์— Extra ๋ฐ์ดํ„ฐ๋กœ ์ „๋‹ฌ์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•์„ ์ด์šฉ

๊ตฌ๋™๋˜๊ณ  ์žˆ๋Š” ์„œ๋น„์Šค์— ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ฑฐ๋‚˜ ๋ฐ›์•„์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ์ด ๋•Œ putExtra ๋กœ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ด๊ฒƒ์€ ์ธํ…ํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ ์ˆœ๊ฐ„ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. ๋”ฐ๋ผ์„œ ์ž์œ ๋กญ๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ  ๋ฐ›๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ•˜๋‹ค.

์œ„์˜ ๋‚ด์šฉ์ฒ˜๋Ÿผ ์„œ๋น„์Šค๋Š” ํŠน์ • ๊ฐ์ฒด๋ฅผ ๋ฆฌํ„ดํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ž์‹ ์„ ์‹คํ–‰์‹œํ‚จ ๊ณณ์— ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ฆฌํ„ดํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค. ๋˜ํ•œ ์„œ๋น„์Šค ์ž์ฒด์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ถ€๋ถ„๋„ ์—†๋‹ค. ๊ทธ๋ž˜์„œ BroadcastReceiver ๋ฅผ ์ด์šฉํ•œ๋‹ค. ์„œ๋น„์Šค ์•ˆ์— ๋ฆฌ์‹œ๋ฒ„๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

์„œ๋น„์Šค ๋‚ด๋ถ€์— ๊ตฌํ˜„๋œ ๋ฆฌ์‹œ๋ฒ„๊ฐ€ ์—‘์ŠคํŠธ๋ผ ๋ฐ์ดํ„ฐ๋กœ ๋„˜์–ด์˜จ ๊ฐ’์„ ์ถ”์ถœํ•˜์—ฌ ์„œ๋น„์Šค์— ๋„˜๊ฒจ์ฃผ๊ณ , ์„œ๋น„์Šค๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๊ตฌํ˜„ํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

์„œ๋น„์Šค์—์„œ ์•กํ‹ฐ๋น„ํ‹ฐ๋กœ์˜ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ๋„ ๋™์ผํ•˜๋‹ค. ์•กํ‹ฐ๋น„ํ‹ฐ์— ๋ฆฌ์‹œ๋ฒ„๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์ธํ…ํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ์ˆœ๊ฐ„ ์—‘์ŠคํŠธ๋ผ ๋ฐ์ดํ„ฐ๋กœ ๋ฐ€์–ด ๋„ฃ๋Š”๋‹ค.



๐Ÿงฉ ์‹ค์Šต ์˜ˆ์ œ

  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#303897">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:src="@drawable/background" />

    <ImageView
        android:id="@+id/startButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginLeft="24dp"
        android:layout_marginBottom="36dp"
        android:clickable="true"
        android:src="@drawable/ic_play" />

    <ImageView
        android:id="@+id/stopButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentBottom="true"
        android:layout_marginRight="24dp"
        android:layout_marginBottom="36dp"
        android:clickable="true"
        android:src="@drawable/ic_stop" />
</RelativeLayout>

  • MyService.kt
package com.kotdev99.android.c71

class MyService : Service() {
	lateinit var player: MediaPlayer

	var receiver = object : BroadcastReceiver() {
		override fun onReceive(p0: Context?, p1: Intent?) {
			val mode = p1?.getStringExtra("mode")
			if (mode != null) {
				if (mode == "start") {
					try {
						if (player != null && player.isPlaying) {
							player.stop()
							player.release()
						}
						player = MediaPlayer.create(p0, R.raw.music)
						player.start()
					} catch (e: Exception) {
						e.printStackTrace()
					}
				} else {
					if (player != null && player.isPlaying) {
						player.stop()
					}
				}
			}
		}
	}

	override fun onCreate() {
		super.onCreate()
		player = MediaPlayer()
		registerReceiver(receiver, IntentFilter("PLAY_TO_SERVICE"))
	}

	override fun onDestroy() {
		super.onDestroy()
		unregisterReceiver(receiver)
	}

	override fun onBind(intent: Intent): IBinder {
		TODO("Return the communication channel to the service.")
	}
}

  • MainActivity.kt
package com.kotdev99.android.c71

class MainActivity : AppCompatActivity() {
	override fun onCreate(savedInstanceState: Bundle?) {
		super.onCreate(savedInstanceState)
		setContentView(R.layout.activity_main)

		val startButton = findViewById<ImageView>(R.id.startButton)
		val stopButton = findViewById<ImageView>(R.id.stopButton)

		startButton.setOnClickListener {
			val intent = Intent("PLAY_TO_SERVICE")
			intent.putExtra("mode", "start")
			sendBroadcast(intent)

			startButton.isEnabled = false
			stopButton.isEnabled = true
		}

		stopButton.setOnClickListener {
			val intent = Intent("PLAY_TO_SERVICE")
			intent.putExtra("mode", "stop")
			sendBroadcast(intent)

			startButton.isEnabled = true
			stopButton.isEnabled = false
		}

		val intent = Intent(this, MyService::class.java)
		startService(intent)
	}

	override fun onDestroy() {
		super.onDestroy()
		val intent = Intent(this, MyService::class.java)
		stopService(intent)
	}
}

๐Ÿ“ฒ ๊ฒฐ๊ณผ


๐Ÿ“ก bindService

  • bindService() ๋Š” ์„œ๋น„์Šค๊ฐ€ ์‹คํ–‰๋˜๋ฉด์„œ ์ž์‹ ์„ ์‹คํ–‰์‹œํ‚จ ๊ณณ์— ๊ฐ์ฒด๋ฅผ ๋ฐ”์ธ๋”ฉํ•œ๋‹ค๋Š” ์˜๋ฏธ

์„œ๋น„์Šค ์ž์‹ ์„ ์‹คํ–‰์‹œํ‚จ ๊ณณ์— '๊ฐ์ฒด๋ฅผ ๋„˜๊ฒจ์ค€๋‹ค (๋ฐ”์ธ๋”ฉ ํ•ด์ค€๋‹ค)' ๋ผ๋Š” ์˜๋ฏธ์—์„œ bindService()

โ“ ๊ทธ๋Ÿผ ์™œ ๊ฐ์ฒด๋ฅผ ๋„˜๊ฒจ์ค„๊นŒ?

์„œ๋น„์Šค๋ฅผ ๊ตฌ๋™ํ•œ ๊ณณ์— ์„œ๋น„์Šค์—์„œ ์ค€๋น„ํ•œ ๊ฐ์ฒด๋ฅผ ๋ฐ”์ธ๋”ฉํ•˜๋Š” ๊ฒƒ์œผ๋กœ, ์„œ๋น„์Šค๋ฅผ ๊ตฌ๋™ํ•œ ์ชฝ์—์„œ ๊ฐ์ฒด์— ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ์ฝœ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด์„œ ๋งค๊ฐœ๋ณ€์ˆ˜๋‚˜ ๋ฆฌํ„ด ๊ฐ’์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฆ‰, bindService ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋‘ ์ปดํฌ๋„ŒํŠธ ์‚ฌ์ด์—์„œ ๋ฐ์ดํ„ฐ ์ฃผ๊ณ  ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ“š Binder

class MyBinder: Binder() {
	fun funA(arg: Int) {
    
    }
    fun funB(arg: Int): Int {
    	return arg * arg
	}
}
override fun onBind(intent: Intent): IBinder? {
	return MyBinder()
}
  • ์„œ๋น„์Šค์˜ ๋ผ์ดํ”„์‚ฌ์ดํด ํ•จ์ˆ˜ ์ค‘ onBind() ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰

onBind() ํ•จ์ˆ˜์˜ ๋ฆฌํ„ด ๊ฐ์ฒด๊ฐ€ ์„œ๋น„์Šค ํ˜ธ์ถœ ์ชฝ์— ์ „๋‹ฌ๋œ๋‹ค. ๊ทธ๋ž˜์„œ ์„œ๋น„์Šค ๋‚ด์— ๊ฐ์ฒด๋ฅผ ํ•˜๋‚˜ ์ค€๋น„ํ•ด์„œ ๋ฆฌํ„ด์‹œ์ผœ ์ฃผ์–ด์•ผ ํ•˜๋Š”๋ฐ, IBinder ํƒ€์ž…์ด์–ด์•ผ ํ•œ๋‹ค. IBinder ๋Š” ์ธํ„ฐํŽ˜์ด์Šค์ด๊ณ  ์ด๊ฒƒ์„ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด Binder ์ด๊ธฐ ๋•Œ๋ฌธ์— Binder ๋ฅผ ์ƒ์† ๋ฐ›์€ ํด๋ž˜์Šค๋กœ ์ค€๋น„ํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ ํด๋ž˜์Šค์˜ ๊ฐ์ฒด๋ฅผ ๋ฆฌํ„ด์‹œ์ผœ ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

์ฐธ๊ณ ๋กœ Binder ์—์„œ ์˜ค๋ฒ„๋ผ์ด๋“œ ๋ฐ›์•„์•ผ ํ•˜๋Š” ํ•จ์ˆ˜๋Š” ์—†๋‹ค. ๊ทธ๋ƒฅ ์ƒ์†๋งŒ Binder ๋กœ ๋ฐ›์œผ๋ฉด ๋œ๋‹ค.

๐Ÿ“š ServiceConnection

val connection: ServiceConnection = object : ServiceConnection {
	override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
    	servideBinder = service as MyService.MyBinder
	}

	override fun onServiceDisconnected(name: ComponentName?) {
	}
}
  • ServiceConnection ์„ ๊ตฌํ˜„ํ•œ ๊ฐ์ฒด ์ค€๋น„

  • onServiceConnected() ํ•จ์ˆ˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ Bind ๊ฐ์ฒด ์ „๋‹ฌ

์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ชฝ์—์„œ ์ค€๋น„ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ธํ…ํŠธ๋ฅผ ์ค€๋น„ํ•˜๋Š” ๊ฒƒ ์™ธ์— ServiceConnection ์ด๋ž€ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฐ์ฒด๋ฅผ ์ค€๋น„ํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค. 2๊ฐœ์˜ ํ•จ์ˆ˜๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œ ๋ฐ›์•„์•ผ ํ•œ๋‹ค.

bindService ๋กœ ์„œ๋น„์Šค ์ชฝ๊ณผ ์—ฐ๋™์ด ๋˜์—ˆ์„ ๋•Œ onServiceConnected() ๊ฐ€ ์ž๋™ ํ˜ธ์ถœ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด์„œ ๋‘ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์„œ๋น„์Šค์—์„œ ๋ฆฌํ„ดํ•œ ๊ฐ์ฒด๊ฐ€ ๋„˜์–ด์˜จ๋‹ค. ๊ทธ๋Ÿฌ๋‹ค ์–ด๋Š ์ˆœ๊ฐ„ ๋ฐ”์ธ๋”ฉ์ด ๋Š์–ด์ง„ ์ˆœ๊ฐ„ onServiceDisconnected() ํ•จ์ˆ˜๊ฐ€ ์ž๋™ ํ˜ธ์ถœ๋œ๋‹ค.

๐Ÿงฉ ์‹ค์Šต ์˜ˆ์ œ

  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#303897">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:src="@drawable/background" />

    <ImageView
        android:id="@+id/startButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginLeft="24dp"
        android:layout_marginBottom="36dp"
        android:clickable="true"
        android:src="@drawable/ic_play" />

    <ImageView
        android:id="@+id/stopButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentBottom="true"
        android:layout_marginRight="24dp"
        android:layout_marginBottom="36dp"
        android:clickable="true"
        android:src="@drawable/ic_stop" />
</RelativeLayout>

  • MyService.kt
package com.kotdev99.android.c72

class MyService : Service() {

	inner class MyBinder : Binder() {
		var player = MediaPlayer()
		fun startMusic() {
			try {
				if (player != null && player.isPlaying) {
					player.stop()
					player.release()
				}
				player = MediaPlayer.create(applicationContext, R.raw.music)
				player.start()
			} catch (e: Exception) {
				e.printStackTrace()
			}
		}

		fun stopMusic() {
			if (player != null && player.isPlaying) {
				player.stop()
			}
		}
	}

	override fun onBind(intent: Intent): IBinder {
		return MyBinder()
	}
}

  • MainActivity.kt
package com.kotdev99.android.c72

class MainActivity : AppCompatActivity() {

	lateinit var binder: MyService.MyBinder

	val connection: ServiceConnection = object : ServiceConnection {
		override fun onServiceConnected(p0: ComponentName?, p1: IBinder?) {
			binder = p1 as MyService.MyBinder
		}

		override fun onServiceDisconnected(p0: ComponentName?) {
			TODO("Not yet implemented")
		}
	}

	override fun onCreate(savedInstanceState: Bundle?) {
		super.onCreate(savedInstanceState)
		setContentView(R.layout.activity_main)

		val startButton = findViewById<ImageView>(R.id.startButton)
		val stopButton = findViewById<ImageView>(R.id.stopButton)

		startButton.setOnClickListener {
			binder.startMusic()
			startButton.isEnabled = false
			stopButton.isEnabled = true
		}
		stopButton.setOnClickListener {
			binder.stopMusic()
			startButton.isEnabled = true
			stopButton.isEnabled = false
		}
		val intent = Intent(this, MyService::class.java)
		bindService(intent, connection, Context.BIND_AUTO_CREATE)
	}

	override fun onDestroy() {
		super.onDestroy()
		unbindService(connection)
	}
}

๐Ÿ“ฒ ๊ฒฐ๊ณผ

๊ฒฐ๊ณผ๋Š” ๋™์ผํ•˜๋‹ค.

profile
์‘์•  ๋‚˜ ์•„๊ธฐ ๋‰ด๋น„

0๊ฐœ์˜ ๋Œ“๊ธ€