본문 바로가기
카테고리 없음

Lifecycle-Aware Component

by 찐세 2021. 11. 7.

 

Lifecycle은 안드로이드 개발에서 가장 중요하고 핵심이 되는 개념이라고 할 수 있다. 애플리케이션은 항상 lifecycle을 고려해야 하며, 그렇지 않으면 메모리 누수 또는 애플리케이션의 비정상 종료가 발생할 수 있다.

 

Lifecycle-Aware Component 는 직역하면 생명주기 인식 컴포넌트를 의미하는데, 이는 말 그대로 lifecycle을 관찰하고 그에 따라서 동작하는 컴포넌트로 이해할 수 있다. 우리가 항상 당연하게 사용해왔던 lifecycle callback 도 이와 관련이 깊다.

우리는 당연하게 사용했던 개념을 가능하게 하는 원리는 무엇인지 한번 알아볼 필요가 있을 것이다. 모르고 쓰는 것과 알고 쓰는 것은 엄청난 차이니까 말이다. (내가 궁금하기도 했고)

 

 

Lifecycle

가장 기본이 되는 것은 당연히 Lifecycle 클래스이다. 공식문서에서는 Lifecycle 클래스를 다음과 같이 정의하고 있다.

Lifecycle은 액티비티나 프래그먼트와 같은 구성요소의 생명주기 상태 관련 정보를 포함하며 다른 객체가 이 상태를 관찰할 수 있게 하는 클래스입니다.

 

즉, 액티비티 나 프래그먼트의 생명주기 정보를 가지고 있는 클래스라고 생각하면 된다. Lifecycle 클래스 내부에는 생명주기에 따른 상태(State) 와 상태 전환시 발생할 수 있는 이벤트(Event)를 정의하고 있다

 

정말 많이 봤을 그림이다...

 

이 정보는 Lifecycle 클래스 코드에서도 확인할 수 있다.

 

Lifecycle 의 이벤트와 상태는 우리가 잘 아는 lifecycle callback 과도 깊은 연관이 있다. (당연히 그렇겠지?)

공식문서에도 이 내용을 확인할 수 있다.

ON_CREATE, ON_START, ON_RESUME 이벤트는 관련 lifecycle callback 메소드가 리턴되고 나면 발생하고,

ON_PAUSE, ON_STOP, ON_DESTROY 이벤트는 관련 lifecycle callback 메소드가 호출되기 전에 발생한다.

이를 통해 우리는 액티비티 / 프래그먼트의 상황에 따라서 lifecycle callback 메서드가 호출이되면 이에 따라 적절한 이벤트가 발생하고, 상태가 변경되는 것을 알 수 있다. 그리고 이 모든 정보를 Lifecycle 객체가 담당하고 있다는 것도 알 수 있다.

 

 

LifecycleOwner

앞에서 액티비티 / 프래그먼트의 이벤트와 상태 정보를 Lifecycle 객체가 담당하고 있다는 것을 알아보았다. 그럼 당연히 액티비티 / 프래그먼트는 Lifecycle 객체에 대해서 접근이 가능해야할 것이고, 액티비티 / 프래그먼트의 lifecycle에 의해 동작하는 여러 컴포넌트들이 이를 확인할 수 있어야할 것이다.

이는 LifecycleOwner를 통해 확인할 수 있다. 직역하면 말 그대로 lifecycle을 가지고 있다는 의미로 해석된다. 

LifecycleOwner는 getLifecycle() 라는 단일 메서드를 가지고 있는 인터페이스이다.

문서에서도 알 수 있듯이 이 인터페이스를 구현한 클래스는 독자적인 생명주기를 가지게 되고, 생명주기의 변화에 따라서 동작할 수 있는 컴포넌트가 될 수 있다고 한다.

 

액티비티 / 프래그먼트가 LifecycleOwner를 구현하고 있기 때문에 독자적인 lifecycle을 가지고 동작하는 컴포넌트가 될 수 있는 것이다.

 

앞에서 LifecycleOwner는 getLifecycle() 메서드만 가지는 단일 메서드 인터페이스라고 했다. 이 인터페이스의 구현체는 이 메서드를 통해서 lifecyle에 대한 정보를 리턴하게 되고, lifecycle aware component 들은 이 lifecycle 정보를 가지고 동작하는 것으로 유추해볼 수 있을 것 같다.

 

이러다보니 Lifecycle 객체가 내부적으로 어떤 동작을 하는지 더 세세하게 알고싶어졌다. lifecycle 을 리턴하는  getLifecycle() 메서드로 부터 거꾸로 한번 파고 들어가보자.

 

액티비티에서 getLifecycle() 메서드의 구현체를 확인할 수 있었다.

여기서 mLifecycleRegistry 라는 프로퍼티를 리턴하는 것을 확인할 수 있었다. 이는 당연히 Lifecycle 또는 이를 상속하는 타입일 것이다.

 

따라가보니 이는 LifecycleRegistry 라는 클래스의 객체였고 이를 확인해보았다.

 

여기서 이벤트를 핸들링하고, 상태를 변경하는 동작을 하는 것을 확인할 수 있었다.

 

 

그리고 추가적으로 LifecycleObserver 를 추가하고 삭제하는 부분도 여기서 처리하는 것을 확인할 수 있다. addObserver 메서드를 통해 observer를 등록할 수 있고, 등록된 observer 는 lifecycle 에 따른 동작을 수행할 수 있게 되는 것이다. 

 

 

LifecycleObserver

LifecycleObserver 는 말그대로 lifecycle 를 관찰하는 관찰자이다.  LifecycleObserver 가 lifecycle을 관찰하고, 이에 따라 동작하는 것은 전형적인 옵저버 패턴의 동작과 동일하다.

 

 

LifecycleObserver는 마커 인터페이스로, 구현해야할 추상 메서드가 존재하지 않는다. 하지만 문서에서도 나와 있듯이 OnLifecycleEvent 어노테이션과 함께 무슨 역할을 한다고 나와 있다.

 

그렇다면 다시 Lifecycle 쪽에서는 LifecycleObserver를 어떻게 다루는지 한번 살펴보자.

 

 

LifecycleRegistry의 addObserver 메서드의 일부이다. 여기서 LifecycleObserver 객체를 map에 등록해서 관리하고 있다. 그리고 removeObserver에서는 반대로 observer객체를 map에서 삭제한다.

map에 등록하는 ObserverWithState 객체는 컴포넌트의 lifecycle 상태와 옵저버를 동시에 가지는 객체이다.

 

 

그렇다면 이렇게 등록한 옵저버를 어디다가 써먹는 것일까??

옵저버 패턴을 통해 이미 알고 있듯이, 특정 이벤트를 관찰하다가 그에 해당하는 동작을 수행할 것이다. 그렇다면 이를 한번 확인해보자.

 

LifecycleRegistry 에서 이벤트를 핸들링 하는 부분부터 따라가보니 대충 알 수 있었다. 문서에서도 나와있듯이 이벤트가 발생하면, 이벤트에 따라 적절하게 컴포넌트의 상태를 변경하고 등록된 모든 옵저버에게 이를 알린다.

 

쭉 따라가다가 forwardPass() 를 보면, 옵저버를 등록 해놓은 map 을 돌면서 알맞은 옵저버를 찾고, dispatchEvent() 에서 이벤트에 맞는 동작을 수행하는 것을 확인할 수 있다.

 

LifecycleObserver 는 이런 매커니즘으로 lifecycle을 관찰하면서 동작하게 된다. 

 

 

다음은 특정 이벤트에 따라 수행할 동작을 어떻게 옵저버에 등록하는지에 대해서 간단히 알아보자.

옵저버가 이벤트에 따라서 적절한 콜백을 정의하는 부분은 공식 문서 를 참고하였다. @OnLifecycleEvent 어노테이션을 부여한 메서드가 해당 이벤트에 대한 콜백이 되는 구조이다.

 

class MyObserver : LifecycleObserver {

    private val TAG = "MyObserver"

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    fun onCreateEventCallback() {
        Log.i(TAG, "onCreateEventCallback")
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun onStartEventCallback() {
        Log.i(TAG, "onStartEventCallback")
    }
		...
}
class MainActivity : AppCompatActivity() {
    private val TAG = "MainActivity"

    override fun onCreate( savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        lifecycle.addObserver(MyObserver())
    }
}

액티비티의 lifecycle에 커스텀 observer를 등록해주면 된다. 이런식으로 커스텀 observer를 구현하게 되면 액티비티의 lifecycle을 따르지만, 콜백은 액티비티에 정의하지 않을 수 있다.

이런 식의 구조를 사용하면 액티비티와 프래그먼트의 생명주기 콜백의 경량화가 가능하고 유지보수가 용이해진다는 장점도 있다.

 

 

REFERENCE


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

 

수명 주기 인식 구성요소로 수명 주기 처리  |  Android 개발자  |  Android Developers

새 Lifecycle 클래스를 사용하여 활동 및 프래그먼트 수명 주기를 관리합니다.

developer.android.com

https://developer.android.com/reference/androidx/lifecycle/Lifecycle

 

Lifecycle  |  Android Developers

 

developer.android.com