Android AAC LifeCycle

홍승범·2023년 4월 23일
0

Android

목록 보기
8/9

androidx.lifecycle패키지는 액티비티나 프래그먼트의 현재 수명 주기 상태를 기반으로 동작을 자동으로 조절할 수 있는 구성요소를 빌드할 수 있는 클래스 및 인터페이스를 제공한다.

LifeCycle 패키지를 이용하기 위해서는 아래와같이 선언한다

    dependencies {
        def lifecycle_version = "2.5.1"
        def arch_version = "2.1.0"

        // ViewModel
        implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
        // ViewModel utilities for Compose
        implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"
        // LiveData
        implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
        // Lifecycles only (without ViewModel or LiveData)
        implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"

        // Saved state module for ViewModel
        implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"

        // Annotation processor
        kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
        // alternately - if using Java8, use the following instead of lifecycle-compiler
        implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"

        // optional - helpers for implementing LifecycleOwner in a Service
        implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"

        // optional - ProcessLifecycleOwner provides a lifecycle for the whole application process
        implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"

        // optional - ReactiveStreams support for LiveData
        implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version"

        // optional - Test helpers for LiveData
        testImplementation "androidx.arch.core:core-testing:$arch_version"

        // optional - Test helpers for Lifecycle runtime
        testImplementation "androidx.lifecycle:lifecycle-runtime-testing:$lifecycle_version"
    }

지금까지의 수명주기 사용방법

일반적으로 액티비티의 수명주기 메서드(onStart, onResume, onPause, onStop.....)에서 필요한 작업을 정의했었다.

아래 코드는 ExoPlayer를 다루는 액티비티 코드중 일부이다

override fun onStart() {
        super.onStart()
        player.playWhenReady = !leaveByUser
        leaveByUser = false
    }

    override fun onUserLeaveHint() {
        super.onUserLeaveHint()
        leaveByUser = true
    }

    override fun onStop() {
        super.onStop()
        player.pause()
    }

일반적으로는 이래도 문제가 없는데, 다른 구성요소들을 다루는 코드가 많아질수록, onStart, onStop과 같은 수명주기 메서드는 점점 방대해지고, 때에 따라서는 수명주기 상태에 맞지 않는 호출이 일어날 수도 있다.

public override fun onStart() {
        super.onStart()
        Util.checkUserStatus { result ->
            // what if this callback is invoked AFTER activity is stopped?
            if (result) {
                myLocationListener.start()
            }
        }
    }

    public override fun onStop() {
        super.onStop()
        myLocationListener.stop()
    }

checkUserStatus 메서드가 onStop 호출 이후에 불리는 경우가 있다면????? 아 물론 조건을 따져서 예외처리를 하면 되긴 한다. 하지만 이런 문제들에 대한 구글의 도움이 바로 androidx.lifecycle패키지인 것이다.

LifeCycle

LifeCycle은 액티비티 / 프래그먼트에서 수명주기 상태정보 및 다른 객체가 이 상태를 관찰할 수 있게 하는 클래스이다.

LifeCycle은 두가지 Enumeration을 사용해 연결된 구성요소의 수명 주기 상태를 관리한다.
1. 이벤트 : 프레임워크 및 LifeCycle클래스에서 전달되는 수명 주기 이벤트. 액티비티와 프래그먼트의 콜백 이벤트에 매핑됨. 즉 onResume, onStop등에 매핑된다는것
2. 상태 : LifeCycle객체가 추적한 구성요소의 현재 상태를 의미

다음 이미지는 상태와 이벤트간의 관계를 나타내는 이미지이다.
이미지

상태와 이벤트를 모니터링하고 싶은 클래스는 DefaultLifecycleObserver를 구현하고, 각 상태에 대한 메서드를 재정의하여 수명주기 상태를 모니터링 할 수 있다

class MyObserver : DefaultLifecycleObserver {
    override fun onResume(owner: LifecycleOwner) {
        connect()
    }

    override fun onPause(owner: LifecycleOwner) {
        disconnect()
    }
}

myLifecycleOwner.getLifecycle().addObserver(MyObserver())

이거 어디서 많이보지 않았는가??? AutoClearedValue!!!

LifeCycleOwner

LifeCycleOwner는 클래스에 LifeCycle이 있음을 나타내는 단일 메서드 인터페이스이다.

이 인터페이스에는 클래스에서 구현해야 하는 getLifecycle()메서드가 있다. 인터페이스를 통해 수명주기가 있는 객체와 함께 동작하는 구성요소들을 만들어 낼 수 있다.

즉 예를 들면 아래와 같다

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()
            }
        }
    }
}

MyLocationListener는 액티비티의 라이프사이클을 제공받아 DefaultLifecycleObserver를 구현해 라이프사이클에따른 동작을 캡슐화 해서 구현할 수 있다.

LifeCycleOwner는 그것이 무엇이든 LifeCycle을 관찰자에게 제공할 수 있으므로, 관찰자가 LifeCycleOwner의 형태와는 무관하게 동작할 수 있는 방법을 제공해 준다.

또한 LifeCycle은 현재 상태를 쿼리할 수 있도록 해준다.

fun enable() {
    enabled = true
    if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
        // connect if not connected
    }
}

권장사항

  1. UI 컨트롤러는 가능한 가볍게. 데이터의 변경에 따른 UI의 변경에만 신경쓰도록 해야함
  2. 데이터 로직은 ViewModel 배치하고, ViewModel의 책임은 UI 컨트롤러와 나머지 부분의 커넥터 역할로 할것.
  3. 데이터 바인딩 / 뷰 바인딩등을 이용해 UI컨트롤러와 ViewModel의 사이의 인터페이스를 깔끔하게 유지할 것
  4. ViewModel에서 뷰 또는 액티비티의 컨텍스트를 참조하지 말것, 뷰모델이 액티비티보다 오래 지속되는경우 메모리 누수의 원인이 됨
  5. 코루틴등을 사용해 장기실행 및 비동기 작업을 관리할 것

AutoClearedValue????
아까도 말했지만 구글이 프래그먼트에서 뷰바인딩의 참조 문제를 해결하기 위한 방법중 하나로 제시한게 AutoClearedValue 프로퍼티이다.
AutoClearedValue
구현 내용중 init 부분을 보면 알겠지만, 프래그먼트의 lifecycle에 옵저버를 구현하여, onCreate시 해당 프래그먼트의 viewLifeCycleOwner의 lifecycle이 onDestroy를 받을 때 값을 null로 자동으로 치환해 주는 코드를 가지고 있다.
즉 요놈이 LifeCycle및 LifeCycleOwner의 훌륭한 예제가 된다!!!


https://developer.android.com/topic/libraries/architecture/lifecycle?hl=ko

https://thdev.tech/android/2021/11/04/Android-ViewModel-Lifecycle/

profile
그냥 사람

0개의 댓글