Android

Android | Activity의 개념과 생명주기(Life Cycle)

8iggy 2022. 9. 22. 23:43

읽기 전

  • 불필요한 코드나 잘못 작성된 내용에 대한 지적은 언제나 환영합니다.
  • 개인적으로 사용해보면서 배운 점을 정리한 글입니다.

안드로이드에 대해 공부해본 적 없는 안드로이드 개발자가 해당 포스팅을 작성합니다. 구글 안드로이드 개발자 문서와 몇몇 블로그, 도서를 참고하여 작성하였습니다. 이번 포스팅에서는 안드로이드의 액티비티가 무엇이고 생명주기는 어떻게 구성되는지 정리합니다.

Activity란?

Android의 주요 컴포넌트로 main 메소드를 사용하여 프로그램을 실행하던 방식과 달리 Android는 수명 주기 단계에 따라 특정 콜백 함수를 호출하여 Activity를 실행한다.

Activity의 개념

Activity는 앱과 사용자의 상호작용을 위한 진입점으로 앱이 UI를 그리는 창을 제공한다. 따라서, 기능 단위로 Activity가 나뉘는 경향을 볼 수 있는데 최근엔 Single Activity로 구현하되 화면은 Fragment로 구현하는 방식을 권장한다. Fragment는 차후 다루기로 하자.

Activity에서 다른 Activity를 실행할 수 있는데 같은 앱뿐만 아니라 다른 앱의 Activity도 실행할 수 있다. 필요에 따라 다른 앱 전체를 시작하지 않고 특정 Activity 실행이 가능하다.

Activity의 등록

앱이 Activity를 사용하려면 AndroidManifest.xml에 몇몇 속성을 선언해야 한다.

Activity 선언

    <manifest ... >
      <application ... >
          <activity android:name=".ExampleActivity" />
          ...
      </application ... >
      ...
    </manifest >

필수 항목은 Activity의 이름을 정의하는 name 속성이다. 그외 별도 테마, 런쳐 Activity 여부 등 다른 속성들도 지정할 수 있다.

Intent Filter 선언

    <activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
        <intent-filter>
            <action android:name="android.intent.action.SEND" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" />
        </intent-filter>
    </activity>

외부 앱으로부터 신호를 받아 특정 액션을 취할 수 있게끔 만들어주는 Intent Filter도 정의할 수 있다.

Permission 선언

    <manifest>
    <activity android:name="...."
       android:permission=”com.google.socialapp.permission.SHARE_POST”
    />

Activity의 동작이 특정 권한을 요구하는 경우 위와 같이 정의할 수 있다. 특정 Activity가 다른 앱으로부터 실행되어야 하는 경우 이렇게 권한을 설정했다면 다른 앱 또한 호출하고자 하는 Activity와 동일한 권한을 선언한 상태여야 한다.

    <manifest>
       <uses-permission android:name="com.google.socialapp.permission.SHARE_POST" />
    </manifest>

Activity Life Cycle

  • 액티비티 생명주기(life cycle) : 액티비티가 생성되어 소멸하기까지의 과정을 말하며, Activity 클래스는 액티비티의 상태를 관측, 조회할 수 있도록 여러 콜백 함수를 제공한다. 콜백 함수에 액티비티의 상태가 바뀔 때 앱이 어떻게 동작해야 하는지 구현한다.
    액티비티의 상태는 동작을 기준으로 크게 3가지로 구분한다.
  1. 활성 : 액티비티 화면이 출력되고 있으며 사용자가 이벤트를 발생시킬 수 있음
  2. 일시 정지 : 액티비티의 화면이 출력되고 있으나 사용자가 이벤트를 발생시킬 수 없음
  3. 비활성 : 액티비티의 화면이 출력되고 있지 않은 상태

액티비티의 시작, 중지, 종료까지의 일련의 과정을 도식화한 그림이다.

Android_Activity_LifeCycle_001.png

entire lifetime

액티비티가 처음 생성될 때 첫 번째로 호출되는 onCreate()부터 마지막에 파기되면서 한 번 호출되는 onDestroy()까지를 의미한다. onCreate()호출 시 액티비티는 global하게 상태를 설정하며 onDestroy() 호출 시 보유한 자원을 모두 release한다. 예를 들어, 액티비티가 네트워크로부터 데이터를 다운로드 받는 백그라운드 스레드를 갖고있다면 해당 스레드는 onCreate() 호출 시 생성되고 onDestroy() 호출 시 소멸한다.

visible lifetime

onStart()가 호출되고나서 onStop()이 호출될 때까지를 의미한다. 해당 기간 동안 사용자는 상호작용 가능 여부와는 상관없이 화면에서 액티비티를 볼 수 있다. 두 메소드 사이에서 개발자는 액티비티에 보여줄 리소스를 유지할 수 있으므로 onStart()호출 시 BroadcastReceiver를 등록해 UI를 변경하면서 onStop()이 호출되면 더 이상 화면에 보여지지 않기 때문에 UI를 갱신하기 위한 BroadcastReceiver를 해제할 수 있다. 이처럼 액티비티가 보여지거나 보여지지 않는 등 상황에 따라 여러 번 호출될 수 있으므로 개발자가 적절하게 사용할 수 있다.

foreground lifetime

onResume() 호출부터 onPause() 호출까지를 의미한다. 이 기간 동안 사용자는 액티비티를 볼 수 있고 액티비티가 동작하며 서로 상호작용 할 수 있다. 액티비티는 단말기가 수면상태로 진입하거나, 새로운 인텐트를 받는 등 자주 paused와 resumed 상태로 전환되므로 onPause(), onResume() 메소드에는 가급적 무거운 작업을 넣지 말아야 한다.

액티비티 콜백 메소드

onCreate()

액티비티 생성 시 최초로 호출되는 콜백 메소드이며 반드시 구현해야 하므로 UI를 표시하는 setContentView()를 여기서 호출한다. onCreate()가 완료되면 다음 콜백은 항상 onStart()이며 처음 실행된 액티비티는 onCreate() -> onStart() -> onResume()메소드까지 호출된다.

onStart()

onCreate()가 종료되고 액티비티는 ‘시작’ 상태로 전환되며 사용자에게 표시된다. 해당 콜백은 액티비티가 foreground로 나오고 상호작용하기 위해 준비하는 작업을 수행한다.

onResume()

액티비티가 사용자와 상호작용하기 직전 호출된다. onResume() 콜백이 호출된 시점에선 액티비티는 액티비티 스택 맨 위에 위치하며 모든 사용자 입력을 받는다. 따라서, 대부분 앱의 기능은 onResume() 메소드로 구현한다.

onPause()

액티비티가 포커스를 잃어 사용자와 상호작용을 할 수 없는 ‘일시중지’ 상태로 전환될 때 시스템이 호출한다. 예를 들어, backward 혹은 recent tray 버튼을 클릭한다던지 아니면 dialog가 발생해서 반투명하게 변할 때 발생한다. 만약 유저에게 UI 업데이트를 제공한다면 포커스를 잃는 ‘일시중지’ 상태에서도 계속 업데이트할 수 있다. 다만, 앱 혹은 사용자 데이터를 저장하거나 네트워크를 호출하거나 데이터베이스 트랜잭션 실행 시 onPause() 메소드에서 처리하면 안된다.

  • onPause()에서 상태 저장 및 복원을 하면 안되는 이유
    onPause()의 실행 시간은 굉장히 짧기에 저장 및 요청 작업을 처리하기엔 시간이 부족할 수 있다. 따라서, 메소드 실행이 끝나기 전에 완료되지 못할 수 있다. 네트워크 요청이나 DB 트랜잭션 실행, 데이터 저장은 실행 시간이 보장되어야 하는 경우가 있는데 이처럼 부하가 큰 종료 작업은 액티비티가 비활성 상태로 전환된 이후 실행되는 onStop() 메소드에서 처리해야 한다.
    onPause() 작업이 끝나고서 호출되는 다음 콜백은 ‘일시중지’ 상태로 전환된 뒤 발생하는 상황에 따라 onStop() 혹은 onResume()이다.

onStop()

액티비티가 더 이상 유저에게 표시되지 않으면 시스템은 onStop()을 호출한다. 현재 액티비티를 제거하거나, 새로운 액티비티를 시작하거나, 기존 Stopped 액티비티가 Resume되어 재진입하게 되는 상황에서 중지 작업을 수행한다.
액티비티가 사용자에게 보여지지 않는 상태이므로 필요없는 리소스를 해제하거나 조정해야 한다. 애니메이션을 일시적으로 중단하거나 위치 정보 업데이트 룰을 세밀함에서 대략적으로 변경한다는 방법을 취할 수 있다.
이후 호출되는 콜백은 액티비티가 다시 사용자와 상호작용을 위해 시작되면 onRestart()이며 액티비티가 완전히 종료되면 onDestroy()이다.

  • 멀티 윈도우 환경에서 액티비티의 UI 활동 보장
    멀티 윈도우에서는 두 개의 앱이 한 화면에 동시에 위치한다. 그리고 하나의 앱과 상호작용 하는 동안 다른 앱은 아직 전면에 노출된 상태이므로 onPause 상태가 된다. 만약 onPause()에서 자원을 release하면 앱이 화면에 있음에도 정상적으로 동작할 수 없다. 따라서, 멀티 윈도우 환경을 고려한다면 자원 release를 onStop()에서 정의하라고 가이드를 제시하고 있다. 다만, 대부분의 경우엔 onStop이나 onDestroy에서 자원을 release하고 있기에 크게 주요한 지식은 아니나 참고사항으로 알아두면 좋겠다. 추후 폴더블 기기등 멀티태스킹 환경에서의 수명 주기도 다뤄볼 예정이다.

onRestart()

‘중지’ 상태의 액티비티를 다시 시작할 때 호출되는 콜백 메소드이다. 액티비티가 중지된 시점부터의 상태를 복원하는 역할을 수행한다. 해당 콜백 뒤에는 항상 onStart() 메소드가 호출된다.

onDestroy()

액티비티가 제거되기 전에 호출되는 콜백이다. 호출되는 시나리오는 크게 두 가지로 요약할 수 있다.

  1. 사용자가 액티비티를 완전히 제거하거나 finish()가 호출되어 종료되는 경우
  2. 구성 변경(기기 회전, 멀티 윈도우 모드로 인한 창 크기 변경)으로 인해 시스템이 일시적으로 액티비티를 소멸시키는 경우
    onDestroy() 메소드는 액티비티가 마지막으로 수신하는 콜백으로 일반적인 경우, 액티비티와 액티비티가 포함된 프로세스가 제거될 때 액티비티의 모든 리소스를 release하도록 구현된다.
    다만, 구성 변경으로 인해 액티비티를 종료하는 경우 즉시 새로운 액티비티 인스턴스를 생성하므로 새로운 구성을 가지고 새로운 인스턴스에 관해 onCreate()를 호출한다.

참고자료

  1. Android Developers - The Activity Lifecycle
  2. Android Developers - Introduction to Activities