반응형
Forgound Service 생명주기
Forgound Service 통신
Forgound Service 최적화

Foreground Service 생명주기

Managing the lifecycle of a service

서비스의 수명 주기는 액티비티의 수명 주기보다 훨씬 간단합니다. 하지만 서비스를 생성하고 소멸하는 방법에 특히 주의를 기울여야 한다는 면에서 중요도는 이쪽이 더 높습니다. 서비스는 사용자가 모르는 채로 백그라운드에서 실행될 수 있기 때문입니다.

서비스 수명 주기(생성된 시점부터 소멸되는 시점까지)는 두 가지 서로 다른 경로를 따를 수 있습니다.

  • 시작된 서비스
  • 다른 구성 요소가 [startService()]를 호출하면 서비스가 생성됩니다. 그러면 서비스가 무기한으로 실행될 수 있으며, [stopSelf()]를 호출하여 자체적으로 중단해야 합니다. 다른 구성 요소도 [stopService()]를 호출하면 서비스를 중단시킬 수 있습니다. 서비스가 중단되면 시스템이 이를 소멸시킵니다.
  • 바인딩된 서비스
  • 다른 구성 요소(클라이언트)가 [bindService()]를 호출하면 서비스가 생성됩니다. 그러면 클라이언트가 [IBinder] 인터페이스를 통해 서비스와 통신을 주고받을 수 있습니다. 클라이언트가 연결을 종료하려면 [unbindService()]를 호출하면 됩니다. 여러 클라이언트가 같은 서비스에 바인딩될 수 있으며, 모든 클라이언트가 바인딩을 해제하면 시스템이 해당 서비스를 소멸시킵니다 서비스가 스스로 중단하지 않아도 됩니다.

이 두 가지 경로는 완전히 별개는 아닙니다. 이미 [startService()]로 시작된 서비스에 바인딩할 수도 있습니다. 예를 들어 재생할 음악을 식별하는 [Intent]를 포함해 [startService()]를 호출하면 백그라운드 음악 서비스를 시작할 수 있습니다. 나중에 아마도 사용자가 플레이어에 좀 더 많은 통제력을 발휘하려고 하거나 현재 노래에 대한 정보를 얻고자 할 때, 액티비티가 [bindService()]를 호출하여 서비스에 바인딩할 수 있습니다. 이와 같은 경우에는 모든 클라이언트가 바인딩을 해제할 때까지 [stopService()] 또는 [stopSelf()]가 서비스를 중단하지 않습니다.

Service Lifecycle

class ExampleService : Service() {
    private var startMode: Int = 0             // indicates how to behave if the service is killed
    private var binder: IBinder? = null        // interface for clients that bind
    private var allowRebind: Boolean = false   // indicates whether onRebind should be used

    override fun onCreate() {
        // The service is being created
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // The service is starting, due to a call to startService()
        return mStartMode
    }

    override fun onBind(intent: Intent): IBinder? {
        // A client is binding to the service with bindService()
        return mBinder
    }

    override fun onUnbind(intent: Intent): Boolean {
        // All clients have unbound with unbindService()
        return mAllowRebind
    }

    override fun onRebind(intent: Intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }

    override fun onDestroy() {
        // The service is no longer used and is being destroyed
    }
}

Foreground Service 통신

  • ChatGPT 답변
    1. BroadcastReceiver 사용 BroadcastReceiver를 등록하고 Intent를 전달하여 Foreground Service에 명령을 보낼 수 있습니다. Foreground Service에서는 BroadcastReceiver를 수신하여 해당 작업을 수행하도록 할 수 있습니다.
    2. LocalBroadcastManager 사용 LocalBroadcastManager를 사용하여 Foreground Service에서 브로드캐스트 이벤트를 보내고 수신할 수 있습니다. 이 방법은 BroadcastReceiver와 유사하지만 로컬 브로드캐스트를 사용하기 때문에 안전하고 효율적입니다.
    3. Messenger 사용 Messenger를 사용하여 Foreground Service와 메시지를 주고받을 수 있습니다. 메시지는 Android.os.Message 클래스를 사용하여 전송하고 수신합니다. 이 방법은 Intent와 BroadcastReceiver를 사용하는 것보다 조금 더 복잡하지만, Foreground Service와 안전하게 통신할 수 있습니다.
    4. AIDL 사용 AIDL (Android Interface Definition Language)를 사용하여 서비스와 통신할 수 있습니다. 이 방법은 Service와 다른 애플리케이션 간의 통신에 사용되며, 인터페이스를 정의하고 메서드를 호출하여 Foreground Service와 상호작용 할 수 있습니다.

Intent(BroadcastReceiver)

Extend the Binder class

  • 로컬 애플리케이션만 서비스를 사용하고 프로세스 간에 작업할 필요가 없는 경우 [Binder]서비스의 공용 메서드에 대한 클라이언트 직접 액세스를 제공하는 자체 클래스를 구현할 수 있습니다.
**참고:** 이는 클라이언트와 서비스가 동일한 애플리케이션 및 프로세스에 있는 경우에만 작동하며 가장 일반적입니다. 
예를 들어 백그라운드에서 음악을 재생하는 자체 서비스에 활동을 바인딩해야 하는 음악 애플리케이션에 적합합니다.

설정 방법은 다음과 같습니다.

  1. 서비스에서 다음 중 하나를 수행하는 Binder인스턴스를 만듭니다.
    • 클라이언트가 호출할 수 있는 공용 메서드를 포함합니다.
    • [Service]클라이언트가 호출할 수 있는 공개 메서드가 있는 현재 인스턴스를 반환합니다 .
    • 클라이언트가 호출할 수 있는 공용 메서드를 사용하여 서비스에서 호스팅하는 다른 클래스의 인스턴스를 반환합니다.
  2. [onBind()]콜백 메서드에서 Binder 인스턴스를 반환합니다.
  3. 클라이언트에서 콜백 메서드 [onServiceConnected()]에서 Binder를 수신하고 제공된 메서드를 사용하여 바인딩된 서비스를 호출합니다.
class LocalService : Service() {
    // Binder given to clients.
    private val binder = LocalBinder()

    // Random number generator.
    private val mGenerator = Random()

    /** Method for clients.  */
    val randomNumber: Int
        get() = mGenerator.nextInt(100)

    /**
     * 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.
     */
    inner class LocalBinder : Binder() {
        // Return this instance of LocalService so clients can call public methods.
        fun getService(): LocalService = this@LocalService
    }

    override fun onBind(intent: Intent): IBinder {
        return binder
    }
}
class BindingActivity : Activity() {
    private lateinit var mService: LocalService
    private var mBound: 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 LocalService, cast the IBinder and get LocalService instance.
            val binder = service as LocalService.LocalBinder
            mService = binder.getService()
            mBound = true
        }

        override fun onServiceDisconnected(arg0: ComponentName) {
            mBound = false
        }
    }

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

    override fun onStart() {
        super.onStart()
        // Bind to LocalService.
        Intent(this, LocalService::class.java).also { intent ->
            bindService(intent, connection, Context.BIND_AUTO_CREATE)
        }
    }

    override fun onStop() {
        super.onStop()
        unbindService(connection)
        mBound = false
    }

    /** Called when a button is clicked (the button in the layout file attaches to
     * this method with the android:onClick attribute).  */
    fun onButtonClick(v: View) {
        if (mBound) {
            // Call a method from the LocalService.
            // However, if this call is something that might hang, then put this request
            // in a separate thread to avoid slowing down the activity performance.
            val num: Int = mService.randomNumber
            Toast.makeText(this, "number: $num", Toast.LENGTH_SHORT).show()
        }
    }
}

참고: 앞의 예에서 [onStop()]메서드는 서비스에서 클라이언트를 바인딩 해제합니다. 
[추가 참고 사항] 섹션 에서 설명한 대로 적절한 시간에 서비스에서 클라이언트 바인딩을 해제합니다 .

IPC(Inter-Process Communication, 프로세스 간 통신)

Foreground Service 최적화

  • ChatGPT 답변
    1. 필요한 작업만 수행하도록 서비스를 설계하십시오. 서비스가 백그라운드에서 실행 중일 때 필요한 작업만 수행하도록 설계하면 리소스 사용량을 줄일 수 있습니다. 예를 들어, 위치 정보를 가져 오는 경우, 위치 정보를 가져 오는 작업을 수행하는 동안에만 서비스를 실행하고 그렇지 않은 경우에는 서비스를 중지하십시오.
    2. Foreground Service에서 사용하는 리소스를 최소화하십시오. Foreground Service에서 사용하는 리소스를 최소화하면 배터리 수명을 연장할 수 있습니다. 예를 들어, 서비스가 작동 중일 때 불필요한 데이터베이스 또는 네트워크 호출을 피하십시오.
    3. 대기 시간을 최소화하십시오. Foreground Service가 사용자에게 계속해서 정보를 표시하도록하면 대기 시간을 최소화할 수 있습니다. 예를 들어, 노티피케이션을 사용하여 Foreground Service가 실행 중인 것을 사용자에게 알리고 작업을 수행하고 있는 동안 진행 상황을 계속해서 업데이트하십시오.
    4. 백그라운드 작업을 최적화하십시오. Foreground Service가 실행 중이지 않은 경우에도 필요한 작업을 수행하기 위해 백그라운드 작업을 사용하십시오. 예를 들어, AlarmManager나 JobScheduler를 사용하여 Foreground Service가 실행 중이지 않은 경우에도 정기적으로 작업을 수행하십시오.
    5. 리소스 누출을 방지하십시오. 리소스 누출을 방지하도록 코드를 작성하십시오. Foreground Service가 실행 중인 동안 리소스 누출이 발생하면 성능에 영향을 미칠 수 있습니다.

Foreground Service CheckList

Background 시작 제한 면제


References

 

서비스 개요  |  Android 개발자  |  Android Developers

서비스 개요 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Service는 백그라운드에서 오래 실행되는 작업을 수행할 수 있는 애플리케이션 구성 요소이며 사

developer.android.com

 

Foreground services  |  Android Developers

Foreground services Stay organized with collections Save and categorize content based on your preferences. Foreground services perform operations that are noticeable to the user. Foreground services show a status bar notification, to make users aware that

developer.android.com

 

바인드된 서비스 개요  |  Android 개발자  |  Android Developers

바인드된 서비스 개요 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 바인드된 서비스란 클라이언트-서버 인터페이스 안의 서버를 말합니다. 이를 사용하

developer.android.com

반응형

'Android' 카테고리의 다른 글

Service  (0) 2023.05.24
해상도  (0) 2023.04.30
DI(Koin)  (0) 2023.02.27
DataStore  (0) 2023.01.23

+ Recent posts