chacha's

[ Android ] Android Lifecycle 본문

Android/Concept

[ Android ] Android Lifecycle

Cha_Cha 2021. 4. 15. 21:29

목차

    Stage of the activity lifecycle, Lifecycles and logging을 참고하였습니다.
    아래에서 사용된 코드는 github에 올려두었습니다.

    Android Lifecycle을 이해한다는 것은 Android 개발자에게 중요한 사항입니다.

    라이프사이클(lifecycle)과 관련된 코드 배치, 객체 초기화 등을 이해하면 앱의 안정성과 성능을 향상시킬 수 있습니다. 애플리케이션을 개발할 때 우리는 "기기의 화면이 회전하거나 앱이 백그라운드로 배치되는 동안 어떤 정보가 유지되어야 하는가?", "어떤 뷰를 초기화 및 참조해야 하는가?", "코드를 구조화할 때 어떤 것을 고려해야 할 다른 사항이 있는가?" 등 라이프사이클과 관련된 여러 사항들을 생각해야 합니다. 

    예를 들어 어떤 앱을 사용한다고 생각했을 때, 해당 앱을 사용하는 동안 전화나 카톡을 받거나 웹 브라우저를 여는 등의 행동을 할 수 있습니다. 즉, 해당 앱에서 알림을 받거나 다른 앱을 사용했다가 다시 앱으로 돌아왔을 때 내용이 유지되고 있는 화면을 보는 등의 다양한 상황을 맞이하게 되고 이런 모든 경우가 라이프사이클(lifecycle)과 연관됩니다.

     

     로그 메시지 작성 Tip

    Android에서 lifecycle 각 단계의 callback 메서드에 Log를 찍어서 확인해 볼 수 있습니다.

    • Verbose (상세) : 모든 로그 메시지를 표시합니다. - default
    • Debug (디버그) : 개발 단계에서만 유용한 디버그 로그 메시지뿐 아니라 그보다 낮은 레벨의 메시지도 이 목록에 표시합니다.
    • Info (정보) : 일반적인 사용을 위해 예상할 수 있는 로그 메시지뿐 아니라 그보다 낮은 레벨의 메시지도 이 목록에 표시합니다.
    • Warn (경고) : 아직 오류는 아니지만 발생할 수 있는 문제뿐 아니라 그보다 낮은 레벨의 메시지도 이 목록에 표시합니다.
    • Error (오류) : 오류를 일으킨 문제뿐 아니라 그보다 낮은 레벨의 메시지도 이 목록에 표시합니다.
    • Assert (강제 종료) : 개발자가 발생해서는 안 된다고 생각하는 문제를 표시합니다.
        /** Lifecycle Methods **/
        override fun onStart() {
            super.onStart()
            Log.i("MainActivity", "onStart Called")
        }
    "Log와 관련한 유용한 라이브러리 : Timber" 보러가기

     

     Activity Lifecycle

    Activity 클래스와 Activity 클래스의 서브 클래스는 동작을 변경하기 위한 메서드들(lifecycle callback)을 구현하거나 lifecycle의 상태가 변경될 때 일부 코드를 실행할 수 있습니다. 이러한 메스드들은 activity 내에서 재정의 하여 커스텀 테스크를 수행할 수 있습니다.

    아래의 다이어그램은 Activity Lifecycle의 상태와 callback 메서드를 보여줍니다.

     🧵 Lifecyels의 상태

    • Initialized : 새로운 Activity를 만들 때마다 시작하는 단계입니다. 일시적인 상태로 바로 onCreate가 실행됩니다.
    • Created : Activity가 방금 생성되었지만 아직 사용자에게 보이지 않고 초점이 맞춰지지 않아서 상호작용할 수 없는 상태입니다.
    • Started : Activity가 보이지만 포커스가 맞춰지지 않은 상태입니다.
    • Resumed : Activity가 실행 중인 상태입니다. 사용자에게 보여지고 포커스가 맞춰져 상호작용할 수 있습니다.
    • Destroyed : Activity가 파괴됩니다. 언제든 메모리에서 꺼낼 수 있으므로 참조하거나 상호 작용을 할 수 없는 상태입니다.

     🧲 Activity Lifecycle Callbacks 

    Method 설명
    onCreate() Activity가 시작할 때 불리는 메서드로 lifecycle 동안 1번만 호출됩니다.
    Activity가 생성되고 초기화되는 시기를 나타냅니다.
    Activity는 아직 화면에 보이지 않고 상호작용도 할 수 없습니다.

    해당 메서드 내에서는 주로 아래와 같은 작업을 해야 합니다.

     1. findViewByID나 databinding을 사용하여 Activity의 UI를 inflate 합니다.
     2. 변수를 초기화합니다.
     3. Activity lifecycle 동안 1번만 발생해야 하는 모든 초기화를 수행합니다.
    onStart() Activity가 보일 때 불리는 Callback 메서드
    사용자가 Activity에서 벗어나거나 돌아올 때마다 호출되는 메서드입니다. 사용자가 홈 화면이나 앱의 새 Activity로 이동하는 경우를 예로 들 수 있습니다. 
    현재 단계에서는 상호작용이 이루어지지 않습니다. 

    해당 메서드 내에서는 아래와 같은 작업을 해야 합니다.

     - Activity가 보일 때 시작해야 하는 센서, 애니메이션, 기타 프로시저를 시작합니다.
    onResume() Activity가 포커스를 얻어 사용자와 상호작용 할 수 있을 때 호출되는 메서드

    해당 메서드 내에서는 아래와 같은 작업을 할 수 있습니다.

     - Activity에 포커스가 맞춰졌을 때 시작해야 하는 센서, 애니메이션, 기타 프로시저(사용자가 현재 상호작용하고 있는 활동)를 시작합니다.
    onPause() Activity가 포커스를 잃을 때 불리는 메서드( ex. Activity가 부분적으로 가리는 다이어로그가 팝업되는 상황 )
    사용자가 Activity와 상호작용을 할 수 없는 즉시 이 메서드를 호출합니다. Activity가 화면에서 완전히 사라지지 않고 포커스를 잃을 수 있습니다. 

    이 메서드가 반환될 때까지 다음 Activity가 재개되지 않기 때문에 무슨 일을 하든 빨리 끝내야합니다.

    해당 메서드 내에서는 아래와 같은 작업을 해야 합니다.

     - Activity에 포커스가 없고 부분적으로 가려져 있을 때 실행되지 않아야하는 모든 센서, 애니메이션, 프로시저를 중지합니다.
     - 데이터 유지를 위한 저장, 스레드 중지, 앱이 종료되기 직전에 실행할 기능 등을 처리합니다.
    onStop() Activity가 화면에 보이지 않게 될 때 불리는 메서드

    항상 호출되는 것은 아니며 메모리가 부족할 경우 호출이 안 될 수도 있습니다. 

    데이터를 영구히 저장할 수 있으며 UI를 업데이트 하면 안 됩니다. 화면을 벗어난 Activity가 실행되는 것은 리소스 낭비입니다.
    onDestroy() Activity가 파괴되기 직전에 호출됩니다. 호출이 안 되는 경우도 있기 때문에 만약 Activity가 종료되는 상황에 반드시 처리해야 하는 작업이 있다면 onPause에서 처리해야 합니다. 
    시스템 비상 시에 메모리를 복구해야 할 경우, onStop과 onDestroy는 호출되지 않을 수 있습니다.

    back button을 누르거나 
    Activity와 관련된 리소스를 정리할 수 있는 마지막 callback 메서드입니다.

    Activity와 관련이 있고 자동으로 해제되지 않는 리소스를 해제합니다. 이 작업을 하지 않으면 메모리 누수가 발생할 수 있습니다.
    Activity가 제거된 후 UI를 업데이트하려는 작업이 있을 경우 앱이 충돌할 수 있습니다.

     

    ▷ 여러 가지 상황에서 Callback 메서드 호출 순서 ( 기본, 홈 버튼 누른 후, 가로 모드 전환 )

    앱 아이콘 클릭 후 바로 back button을 누른 상황에서 Log
    앱 실행 후 홈 버튼 클릭하여 홈 화면으로 갔다가 다시 앱을 실행했을 때 Log

    유저가 홈 화면으로 갔다가 다시 앱으로 돌아오는 과정은 유저가 다른 Activity로 갔다가 돌아오는 과정(ex. 폰 게임을 하다가 전화를 받고 다시 돌아오는 상황)과 같습니다. 

    앱 실행 후 화면 회전했을 때 Log

    🥽 onCreate vs onStart

    변수를 초기화 하는 위치를 onCreate로 잡는가 아니면 onStart로 잡는가에 따라 앱의 동작이 달라질 수 있습니다. 

    만약 dessertsSold를 onCreate에서 초기화하는 경우 홈 버튼을 클릭했다가 다시 화면을 클릭하여 돌아와도 onCreate는 화면을 생성할 때 1번 호출되기 때문에 Id 값에 변화가 없습니다. 하지만 dessertsSold를 onStart에서 초기화하는 경우, 홈 버튼을 클릭했다가 화면으로 다시 돌아오면 Id 값은 0으로 초기화되어 있어서 디저트를 클릭했을 때 1로 값이 나타납니다.

    왼쪽은 onStart에서 dessertsSoId를 초기화해 준 경우 / 오른쪽은 onCreate에서 초기화해 준 경우

     

     Fragment Lifecycle

     

    Fragment Lifecycle callback methods와 flow

     

    ** Fragment 생명 주기 설명 추가 필요

     

    위의 설명은 단일 Activity나 Fragment에 대한 lifecycle을 설명한 것입니다. 더 복잡한 애플리케이션의 경우, Activity와 fragment lifecycle 간의 상호작용과 여러 Activity 간의 상호작용을 이해하는 것이 중요해집니다. 아래의 포스트들은 이러한 상황에 대한 참고자료입니다.

    The Android Lifecycle cheat sheet — part I

    The Android Lifecycle cheat sheet — part II
    : 2개의 Activity 간의 상호작용에 관한 포스트

    The Android Lifecycle cheat sheet — part III
    : Activity와 fragment가 상호작용할 때 lifecycle의 호출 순서를 다루는 포스트

     

     Lifecycle Library

     Architecture Components I/O 2017
     Handling Lifecycles with Lifecycle-Aware Components Documentation 
    📌 먼저, Observer Pattern에 대해 알아봅시다! 

    Lifecycle 라이브러리를 사용하면 onStartonStop과 같은 lifecycle 콜백 메서드에 많고 다양한 기능을 선언하지 않고 메서드에 어떤 Lifecycle 일 때 호출될지 알려줄 수 있습니다. 이를 통해 깜박하고 Lifecycle 메서드에서 필요 메서드를 호출하지 않아 생기는 버그를 찾기 위해 골머리를 앓는 경우를 방지할 수 있습니다.

    📖 설명

    DessertPusher 프로젝트에서 액티비티는 타이머(Timer)의 시작/멈춤 메서드 호출을 담당하고 있습니다. 하지만 옵저버 패턴을 사용할 경우 이 책임 관계를 뒤집을 수 있습니다. 대신 여기서 타이머는 Acitivity의 관찰자(Observer) 되어야 합니다.

    원래 관계 / 옵저버 패턴을 사용한 관계

    원래는 MainActivity에서 DessertTimer를 호출하며 무엇을 해야 할지 명령하지만, 옵저버 패턴을 사용함으로써 이 관계가 뒤집어집니다. 옵저버 패턴을 사용하면 DessertTimerMainActivity 라이프사이클의 변화에 대한 알림만 받고 이에 맞게 동작을 결정합니다.

    💤 사용하기

    1. LifecycleObserver 등록하기

    DessertTimer class에 LifecycleObserver를 등록하여 activity의 lifecycle을 파라미터로 받아와 init 블럭에서 observer를 등록해 줍니다.

    • LifecyclerOwner는 Activity/Fragment와 같이 Lifecycle을 가지는 클래스입니다.
    • LifecycleObserver는 객체들(Objects)이 LifecyclerOwner를 관찰할 수 있게 허용합니다.
    class DessertTimer(lifecycle: Lifecycle) : LifecycleObserver {
        ...
        init {
            // 현재 객체가 넘겨받은 객체(여기서는 Activity)의 Lifecycle을 관찰
            lifecycle.addObserver(this)
        }
        ...
    }

    2. DessertTimer 클래스의 필요 메서드에 @OnLifecycleEvent 어노테이션을 선언

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    fun startTimer() {...}
    
    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun stopTimer() {...}

    3. MainActivity에서 lifecycle을 전달

        override fun onCreate(savedInstanceState: Bundle?) {
            ...
            dessertTimer = DessertTimer(this.lifecycle)
            ...
        }

     

    END

    'Android > Concept' 카테고리의 다른 글

    [ Android ] ADB 사용하기  (0) 2021.04.27
    [ Android ] Navigation  (0) 2021.04.09
    [ Android ] Constraint layout  (0) 2021.04.08
    [ Android ] Data binding  (0) 2021.04.06
    [ Android ] View Binding  (0) 2021.03.24
    Comments