[Android] Activity란? Activity LifeCycle 이해

WonseokOh·2022년 4월 30일
0

Android

목록 보기
2/16
post-thumbnail

  안드로이드 개발을 한 번이라도 해봤다면 Activity는 무조건 사용하는 컴포넌트입니다. 저도 Activity를 자주 사용하지만 구체적으로 Activity의 역할이 무엇이고, LifeCycle을 생각해서 개발을 한 적이 없을 정도로 올바르게 사용하고 있지 않았습니다. 이번 글을 통해 Activity에 대해 제대로 공부해보고 LifeCycle에 맞춰서 사용해보려고 합니다.


Activity란?

  Activtiy는 안드로이드 4대 컴포넌트 중 하나로 사용자와 상호작용을 하는 UI를 제공하는 역할을 합니다. 안드로이드 폰에서 특정 애플리케이션을 실행하면 보여지는 화면이 대부분 Activity로 만들어졌습니다. Activity는 안드로이드 시스템에서 Entry Point 역할을 하면서 사용자에게 보여지는 부분을 담당한다고 볼 수 있습니다.

Entry Point

  • 소프트웨어에서 Entry Point는 진입점을 뜻하며, C/C++, Java 개발 시 main 함수가 Entry Point입니다.
  • 보통 Entry Point는 main과 유사하게 오직 하나만 존재하여 단일 진입점이라고도 부릅니다.
  • 하지만 안드로이드 시스템에서는 단일 진입점이 아닌 4대 컴포넌트(Activity, BroadCastReceiver, Service, ContentProvider) 를 통해서 진입이 가능합니다.
  • Activity도 Entry Point중 하나로 사용자와 상호작용하는 UI 제공과 동시에 진입점 역할도 하게 됩니다.
  • 안드로이드 시스템에서 Entry Point를 통해 해당 애플리케이션의 컴포넌트로 제어권을 넘기기 위해서 Manifest.xml에 명시해야 합니다.

Activity LifeCycle

  Activity의 역할에 대해 알았으니 해당 컴포넌트 LifeCycle에 대해 숙지할 필요가 있습니다. LifeCycle에 대해 이해가 되지 않은 상태로 개발을 하게 되면 반납해야 될 리소스들이 반납되지 않고, DB 데이터를 읽어올 수 없다던가, 필요한 데이터를 가져오지 못하게 될 수 있습니다. Activity에는 6개의 콜백(onCreate, onStart, onResume, onPause, onStop, onDestory)이 제공되며 Activity가 어떤 상태일 때 해당 콜백이 호출되는지 알아야 합니다.

onCreate

  안드로이드 시스템이 Activity를 생성할 때 실행되는 콜백메소드로 전체 LifeCycle동안 한번 호출하게 됩니다. 주로 ViewBinding, DataBinding을 사용하여 UI를 구성하는 레이아웃과 연결하고 ViewModel 생성과 같은 Activity 시작 로직들이 포함되어 있습니다. 이 콜백 메소드에는 key와 value의 형태로 저장하는 Bundle 타입인 savedInstanceState 매개변수 전달받게 됩니다. 이전 Activity의 상태를 저장하여 재생성 시에 설정하기 위한 변수로 처음 Activity를 실행했다면 해당 매개변수는 null 값으로 전달받게 됩니다.

onStart

  onCreate 이후 시작상태가 되었고, 시스템은 연달아 onStart, onResume 콜백을 호출하게 됩니다. onStart가 호출되는 경우는 2가지로 나뉘는데 처음 생성 이후 호출될 때와 onRestart 콜백을 수신 후 재시작될 때 호출됩니다. onStart에서는 Activity가 사용자에게 표시되고, 포그라운드로 이동할 준비를 하게 됩니다. 해당 콜백은 빠르게 완료가 되고 onResume 콜백을 호출하게 됩니다.

onResume

  onResume이 호출된 이후에는 Activity가 포그라운드 상태가 되고 사용자와 상호작용을 할 수 있습니다. 실제로 setContentView 결과가 보여지는 부분으로 재시작 이후 백그라운드에 있던 Activity가 포그라운드 상태가 되고 모든 화면에 해당 Activity가 가득 찬 모습인 상태입니다. 전화가 오거나, 홈버튼을 눌러 해당 Activity의 화면이 꺼지는 이벤트가 발생하기 전까지는 onResume 상태에 계속 머무르게 됩니다.

  화면이 꺼지는 이벤트가 발생하면 onPause가 호출되고 다시 재개가 되면 onResume 콜백이 호출하게 됩니다. 아래에서도 설명하겠지만 onResume은 onPause에서 해제했던 리소스들을 다시 초기화 하는 코드가 있어야 합니다. 즉, onResume과 onPause는 대칭적으로 리소스 및 데이터를 초기화하고 해제하여야 합니다.

onPause

  Activity가 포그라운드에서 백그라운드로 바뀌는 시점으로 화면의 일부가 가려진 상태일 때 onPause 콜백이 호출됩니다. 이벤트가 발생하여 새로운 Activity가 포그라운드로 나오기전까지는 onPause 상태에 있다가 포그라운드로 나오는 순간 모든 화면이 가려지면 onStop 콜백을 호출하게 됩니다. 또는 Dialog Activity나 투명 Activity가 위에 나타날 경우에도 onPause상태에 머물게 됩니다. 실제 면접에서도 onPause와 onStop의 차이를 자주 질문하기도 합니다. onPause는 포그라운드에서 백그라운드로 전환되는 시점으로 화면의 일부가 가려진 상태에 호출되고, onStop은 완전히 화면이 가려질 때 호출됩니다.

  onPause는 아주 잠깐 실행되므로 현재 화면을 구성하는 데이터를 저장하거나, 네트워크 호출 또는 DB 트랜잭션과 같은 시간 소요가 있는 작업들을 실행해서는 안됩니다. 이처럼 부하가 큰 작업들은 주로 onStop에서 처리해야 합니다.

onStop

  위에서 설명했듯이 Activity가 이벤트로 인해 새로운 화면이 나타나서 전체 화면을 가리게 되면 onStop이 호출됩니다. onStop에서는 Activity에서 사용되지 않을 리소스들을 해제하거나 현재 상태 정보를 저장하기 위한 DB 작업들을 진행해야 합니다. onStop에서 중요한 점은 Activity 객체는 아직 메모리 안에 머무르게 됩니다. 이 객체에서 Window manager와 연결되어 있지 않을 뿐 모든 상태나 멤버 정보는 계속 관리되고 있습니다. Activity가 다시 재개되면 이 정보들을 다시 호출할 수 있습니다. 재개 시 onCreate에서 생성한 구성요소는 다시 초기화 할 필요 없고 레이아웃에 있는 각 View 객체도 현재 상태를 기록하기에 저장 및 복원할 필요 없습니다.

onDestory

  Activity가 완전히 소멸되기 전에 onDestory 콜백이 호출됩니다. 공식문서에는 onDestory가 발생하는 경우는 2가지라고 나와있습니다. finish() 함수를 호출하여 Activity가 종료되는 경우와 기기 회전과 같은 구성 변경으로 인해 일시적으로 소멸되는 경우입니다. 또한 시스템에 의한 액티비티가 제거 될 수도 있는데 이 때도 마찬가지로 onDestory 콜백까지 호출됩니다.

  시스템에 의한 액티비티 제거에 대해서 자세히 설명을 하면, 여러 테스크를 사용하는 애플리케이션에서 메모리를 많이 사용할 때 발생할 수 있습니다. 하나의 태스크를 갖는 애플리케이션에서 메모리 사용량이 많아질 경우에는 OutOfMemoryError가 발생하지만, 여러 태스크를 사용한다면 OutOfMemoryError가 발생하기 전에 메모리를 줄일 수 있는 방법으로 백그라운드 테스크의 액티비티를 종료시키게 됩니다. 이와 같이 시스템에서 Activitiy를 제거할 때에도 onDestroy까지 호출됩니다.


생명주기 메소드 호출 순서

헷갈릴만한 상황에서의 생명주기 호출 순서입니다. 한 번씩 생각해보신 후에 확인해보시면 좋을 것 같습니다.

  • 시작할 때 : onCreate -> onStart -> onResume
  • 화면 회전할 때 : onPause -> onStop -> onDestroy -> onCreate -> onStart -> onResume
  • 홈 버튼 클릭 시 : onPause -> onStop
  • 홈 이동 후 다시 돌아올 때 : onRestart -> onStart -> onResume
  • 백 버튼 클릭하여 액티비티 종료 시 : onPause -> onStop -> onDestory

액티비티 전환 시 생명주기 메소드 호출

  Activity A에서 Activity B를 시작할 때 메소드들이 어떻게 호출되는지도 알 필요가 있습니다. 저 또한 단순하게 생각해서 Activity A가 onStop까지 호출된 이후에 Activity B가 onCreate, onStart, onResume 순서대로 호출된다고 생각했습니다. 하지만 이와 같이 실행되는게 아닙니다.

  1. Activity A는 onPause 메소드를 실행합니다.(Activity A가 백그라운드로 이동)
  2. Activity B는 onCreate, onStart, onResume 메소드를 실행하여 포그라운드 상태가 됩니다.
  3. Activity B가 onResume까지 호출된 이후에는 포그라운드 상태가 되고 전체 화면을 가득 채우기 때문에 Activity A의 onStop 메소드가 호출됩니다.

  크게 중요하지 않다고 생각하실 수도 있지만, 만약 두 액티비티에서 공통적으로 사용되는 클래스나 DB를 사용할 때 문제가 될 수 있습니다. Activity A가 onPause가 아닌 onStop에서 DB 저장할 시 Activity B에서는 저장되지 않은 상태에서 데이터를 가져오게 되고 그 이후에 저장되기 때문에 다른 값들을 사용하게 됩니다. 따라서 액티비티 전화 시에 생명주기에 대해 잘 알고 사용하도록 해야합니다.


생명주기 메소드 사용 시 주의사항

리소스 생성/제거는 대칭으로 실행

onCreate에서 리소스 생성했으면 onDestory에서 해제를 하고 onResume에 생성하면 onPause에 제거를 해서 대칭적으로 코드를 작성해야 합니다. 위에서 많은 예시를 들었듯이 DB를 onCreate에 열었고 onPause에서 닫는다고 가정했을 때 재시작이 되면 닫힌 DB를 열기 때문에 문제가 발생할 수 있습니다. 반드시 onCreate에서 DB를 열었다면 onDestory에 닫도록 해야 합니다.


finish() 메소드 호출 후 return 필수

finish 함수로 액티비티 종료 시에 finish 메소드는 시스템에 액티비티를 종료하라는 메세지를 보낼 뿐 리턴을 하는게 아닙니다. finish 메소드 이후에도 로직이 있다면, 해당 로직이 수행될 수 있으며 정상적인 결과를 얻지 못하거나, 오류가 발생하게 될 수 있습니다. 따라서 finish 메소드를 호출했다면 return을 필수로 추가하여 이후 로직이 실행되지 않도록 해야 합니다.


참고

profile
"Effort never betrays"

0개의 댓글