안드로이드에서 생명 주기는 매우 중요합니다. 앱의 활성 상태를 알아야 UI나 동작 등의 작업을 할 수 있기 때문입니다.
액티비티나 프래그먼트의 경우, onCreate 메서드나 onStop 메서드와 같이 해당 상태에 따라 호출되는 메서드가 있습니다. 하지만 수명 주기의 현재 상태에 따라 UI와 다른 구성 요소를 관리하는 호출이 너무 많이 발생하면 여러 컴포넌트를 수명 주기 메서드에 상당한 양의 코드를 배치하게 되어 유지하기 어려워집니다. 또한, 장기 실행 작업을 진행해야 하는 경우 onStop() 메서드가 onStart() 전에 종료되어 구성 요소가 필요 이상으로 오래 유지되는 경합 상태가 발생할 수 있습니다. 이를 해결하기 위해 안드로이드에서는 androidx.lifecycle을 지원하고 있습니다.
Lifecycle 클래스는 액티비티나 프래그먼트 같은 구성 요소의 수명 주기 상태 관련 정보를 포함하며, 다른 객체가 이 상태를 관찰할 수 있게 하는 클래스입니다. Lifecycle은 Event와 State를 사용하여 연결된 구성 요소의 수명 주기 상태를 추적합니다. 그럼 이것이 어떻게 이전에 설명한 문제들을 해결할 수 있는지 알아보겠습니다.
Lifecycle은 직접적으로 사용할 때 옵저버 패턴을 통해 해당 상태에 맞춰 동작을 실행할 수 있습니다. 이 옵저버는 LifecycleObserver 형태를 가지며, 한 개의 옵저버가 아니라 여러 개의 옵저버를 등록할 수 있습니다. 이를 통해 액티비티나 프래그먼트의 코드를 분리하고 유지 보수를 향상시킬 수 있습니다. 또한 LifecycleObserver를 사용하면 생명 주기 상태 변화를 명확하게 추적하고, 필요 시 특정 이벤트에서 작업을 취소하거나 정지시켜 경합 상태를 해결할 수 있습니다. 간접적으로는 Lifecycle을 가지고 있는 LifecycleOwner를 LiveData의 옵저버에 등록하여 장기 실행 작업을 관리할 수 있습니다.
이제 코드에서 그 사용법을 알아봅시다.
Lifecycle 클래스를 접근하기 위해서는 LifecycleOwner가 필요합니다.
public interface LifecycleOwner {
/**
* Returns the Lifecycle of the provider.
*
* @return The lifecycle of the provider.
*/
public val lifecycle: Lifecycle
}
위의 코드는 LifecycleOwner의 인터페이스입니다. 액티비티나 프래그먼트는 이를 상속받아 lifecycle을 접근하도록 구현하고 있습니다. 그렇기에 액티비티나 프래그먼트에서는 Lifecycle에 바로 접근할 수 있는 것입니다. LiveData나 DataBinding 같은 다른 곳에서 Lifecycle이 필요하다면 이 LifecycleOwner를 넘겨줘 해당 액티비티나 프래그먼트의 상태를 확인할 수 있습니다.
액티비티나 프래그먼트에서는 이를 이용하여 옵저버 패턴으로 각 옵저버를 Lifecycle에 등록할 수 있습니다. 이 경우 옵저버는 DefaultLifecycleObserver를 이용하여 구현할 수 있습니다.
internal class MyLocationListener(
private val context: Context,
private val lifecycle: Lifecycle,
private val callback: (Location) -> Unit
): DefaultLifecycleObserver {
private var enabled = false
override fun onStart(owner: LifecycleOwner) {
if (enabled) {
// connect
}
}
fun enable() {
enabled = true
if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
// connect if not connected
}
}
override fun onStop(owner: LifecycleOwner) {
// disconnect if connected
}
}
class MyActivity : AppCompatActivity() {
private lateinit var myLocationListener: MyLocationListener
override fun onCreate(...) {
myLocationListener = MyLocationListener(this, lifecycle) { location ->
// update UI
}
Util.checkUserStatus { result ->
if (result) {
myLocationListener.enable()
}
}
llifecycle1.addObserver(myLocationListener)
}
}
안드로이드 공식 문서에서는 Lifecycle의 권장 사항과 사용 사례 등을 알려주고 있습니다.
- UI는 가능한 가볍게 유지하고 데이터를 확보해야 한다면 ViewModel에서 LiveData로 가져와 해당 사항을 관찰하는 방식으로 사용하도록 합니다.
- DataBinding을 사용하면 뷰와 UI 컨트롤러 사이의 인터페이스를 깔끔하게 유지할 수 있습니다.
- UI가 복잡하다면 UI 수정을 처리할 수 있는 presenter 클래스를 만드는 것이 좋습니다.
참고
https://velog.io/@jjddww/AAC-Lifecycles
'안드로이드 > AAC(Android Architecture Components)' 카테고리의 다른 글
[AAC] Navigation 기능 구현 - 딥 링크 (0) | 2024.06.12 |
---|---|
[AAC] Navigation의 정의와 적용 (0) | 2024.06.10 |
[AAC] LiveData의 정의와 사용 (0) | 2024.06.06 |
[AAC] DataBinding 고급 기능 (1) | 2024.06.05 |
[AAC] DataBinding의 정의와 적용 (0) | 2024.06.04 |