Android

[Android/Kotlin] 서비스(Service) 컴포넌트 정리

haehyun 2022. 1. 22. 01:10
728x90

안드로이드 4대 컴포넌트

  • 액티비티(Activity)
  • 브로드캐스트 리시버(Broadcast Receiver)
  • 서비스(Service)
  • 콘텐츠 프로바이더(Content Provider)

 

서비스(Service)

  • 오래 걸리는 작업을 백그라운드에서 처리할 수 있게 해주는 컴포넌트.
  • 서비스에 화면을 구현하지 않는다.
  • 시스템에서 생명주기를 관리한다.
  • 안드로이드 8버전 부터 백그라운드 작업에 제약이 생김.

 

서비스 생성, 실행 순서

1. [MyService.kt] Service 클래스를 상속받아서 서비스 컴포넌트 작성

package com.example.프로젝트명

import android.app.Service
import android.content.Intent
import android.os.IBinder

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

 

2. [MyService.kt] onBind() 함수 오버라이딩, IBinder 인터페이스를 구현한 객체를 반환하도록 작성
*IBinder 인터페이스를 구현한 클래스가 Binder이기 때문에, Binder 클래스를 상속하는 것으로 가능. Binder 클래스를 상속받는 MyBinder 클래스를 선언해서 액티비티-서비스 간에 전달할 필드, 메서드 등을 선언해 둔다. 어쨌든 액티비티-서비스 간에 오가는 건 IBinder 인터페이스를 구현한 객체 하나 뿐. 그 안에 필요한 여러 기능을 담아야 한다.

package com.example.androidlab

import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder

class MyService : Service() {
    class MyBinder : Binder() {
        fun funA(arg: Int) {

        }
        fun funB(arg: Int): Int {
            return arg * arg
        }
    }
    
    override fun onBind(intent: Intent): IBinder {
        return Binder()
    }
}

 

3. [AndroidManifest.xml] 서비스 컴포넌트 등록

<service
    android:name=".MyService"
    android:enabled="true"
    android:exported="true"></service>

 

4. [MainActivity.kt] ServiceConnection인터페이스를 구현한 객체 생성

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        // ServiceConnection 객체 생성
        val connection: ServiceConnection = object : ServiceConnection {
            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                TODO("Not yet implemented")
            }

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

    }
}

 

5. [MainActivity.kt] onServiceConnected(), onServiceDisconnected() 함수 오버라이딩

  • onServiceConnected() : bindService() 함수로 서비스를 구동할 때 자동으로 호출된다.
  • onServiceDisconnected() : unbindService() 함수로 서비스를 종료할 때 자동으로 호출된다.
var serviceBinder: MyService.MyBinder

// ServiceConnection 객체 생성
val connection: ServiceConnection = object : ServiceConnection {
	override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
		serviceBinder = service as MyService.MyBinder
	}

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

 

6. [MainActivity.kt] 서비스를 인텐트에 담아서 실행

// 서비스 실행
val intent = Intent(this, MyService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)

 

7. [MainActivity.kt / MyService.kt] bindService() 함수로 서비스를 실행하면 서비스의 onBind() 함수가 실행된다.
onBind() 함수는 Service에서 구현한 대로 IBinder인터페이스를 구현한 객체를 반환한다.

8. [MainActivity.kt] onBind()에서 반환된 Binder객체는 ServiceConnection인터페이스를 구현한 객체의 onServiceConnected() 함수의 매개변수로 받을 수 있다.

var serviceBinder: MyService.MyBinder

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

    override fun onServiceDisconnected(name: ComponentName?) {
        TODO("Not yet implemented")
    }
}
  • onServiceConnected(name: ComponentName?, service: IBinder?) 에서 service 매개변수가 서비스에서 반환된 Binder 객체이다.
  • onBind() 함수의 반환 값을 service 매개변수로 받은 뒤, IBinder 인터페이스를 구현했던 타입으로 형변환해서 사용한다. => 매개변수 타입이 IBinder 인터페이스인 경우, 이 인테페이스를 구현한 타입들을 매개변수로 받아들일 수 있지만, 인스턴스에 딱 맞는 타입으로 형변환 해주지 않으면 해당 타입의 멤버를 사용할 수 없다. service 참조 변수는 IBinder 타입인데, 실제 인스턴스는 MyBinder 타입임.

 

9. 필요할 때 Binder 객체의 함수를 호출해서 매개변수나 반환값으로 데이터를 주고 받는다.

class MainActivity : AppCompatActivity() {
    lateinit var serviceBinder: MyService.MyBinder
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        // ServiceConnection 객체 생성
        val connection: ServiceConnection = object : ServiceConnection {
            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                serviceBinder = service as MyService.MyBinder
            }

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

        // 서비스 실행
        val intent = Intent(this, MyService::class.java)
        bindService(intent, connection, Context.BIND_AUTO_CREATE)

        serviceBinder.funA(10)
    }
}
728x90