Android

안드로이드 4대 컴포넌트란 무엇인가? - Activity

park_juyoung 2019. 1. 9. 16:12

 개발자가 되기위한 첫 걸음 

Activity(액티비티)란?

액티비티는 UI 화면을 담당하는 컴포넌트이다. 안드로이드 액티비티가 화면에 UI를 표시하는 역할을 수행한다고 해서 자체적인 그리기 기능이 실행되어 화면을 그리는 것이 아니다. VIew 또는 ViewGroup의 다양한 조합을 화면에 배치함으로써, UI를 표시하는 것입니다. 이러한 관점에서 보면 액티비티는 화면에 UI를 표시하기 위한 틀이라는 개념이 될 수 있습니다. 따라서 하나의 UI는 하나의 Activity라는 말이 됩니다.


하나의 애플리케이션은 하나 이상의 액티비티가 느슨하게 서로 묶여 있는 형태로 구성됩니다. 각각의 액티비티는 여러 가지 작업을 수행하기 위해 또 다른 액티비티를 시작할 수 있습니다. 새로운 액티비티가 시작될 때마다 이전 액티비티는 중단되지만 시스템은 해당 액티비티를 스택(백 스택)에 보존하게 됩니다. 새로운 액티비티가 시작되면 이전 액티비티는 백 스택으로 Push되며 새로운 액티비티가 사용자 포커스를 가지게 됩니다. 백 스택은 기본적으로 LIFO 방식이므로 사용자가 현재 액티비티를 끝낸다면 해당 액티비티가 스택에서 pop 되고 스택상에서 지워지며 이전 액티비티가 재개됩니다.

Activity 클래스

주로 사용하는 액티비티 클래스에는 Activity, FragmentActivity, AppCompatActivity가 있습니다.

  • Activty 클래스(android.app.Activity) - 해당 안드로이드 버전의 기본 라이브러리 액티비티 클래스이며, 모든 다른 액티비티 클래스는 이 클래스의 서브 클래스가 된다.

  • FragmentActivty 클래스 (android.support.v4.app.FragmentActivity) - 과거 버전과의 호환성을 유지하면서 프래그먼트를 사용할 때 필요한 액티비티 클래스다.

  • AppCompatActivity 클래스 (android.app.support.v7.app.AppCompatActivity) - 과거 안드로이드 버전과의 호환성을 유지하면서 새로운 버전의 기능도 사용할 수 있도록 만든 액티비티 클래스다.이 클래스는 안드로이드 6.0(마시멜로)의 새로운 기능(Material Design 관련)도 많은 부분 구현하고 있다. 이런 이유로 안드로이드 스튜디오 1.5 버전부터는 프로젝트 생성 시에 액티비티를 AppCompatActivity 클래스의 서브 클래스로 생성해준다.


Activity 생명주기

액티비티 생명주기를 관리하는 주된 목적은 적시에 액티비티 상태를 저장하거나 복원하기 위함이다. 상태(state)는 액티비티가 현재 보존하고 있는 데이터와 현재 보이는 사용자 인터페이스 데이터(일반적으로 폰이나 태블릿 등의 화면에 나타난 뷰 객체의 데이터)를 의미한다.

 예를 들어 액티비티는 데이터베이스, 콘텐트 제공자, 파일 등에 저장될 필요가 있는 메모리의 데이터를 유지할 수 있다. 이러한 상태 정보를 영속적 상태(persistent state)라고 한다.

화면에 보이는 사용자 인터페이스는 동적 상태(dynamic state)라 한다(사용자 인터페이스 상태 또는 인스턴스 상태라고도 한다). 애플리케이션이 실행되는 동안만 보존되기 때문이다. 예를 들어 화면의 텍스트 필드에 입력된 텍스트는 아직 애플리케이션의 영속적 상태 데이터로 확정되지 않은 것이다. 이외에도 파일이나 데이터베이스 등에는 저장하지 않지만 액티비티 내부에서 보존해야 하는 변수들이 필요할 수 있다. 이런 변수 데이터까지를 포함하는 것이 동적 상태다.

 영속적 상태를 저장하는 목적은 데이터 유실을 막기 위함이다. 즉, 액티비티가 백그라운드 상태로 있을 때는 런타임 시스템이 그 액티비티를 종료시키면서 액티비티의 데이터가 없어질 수 있다. // 액티비티의 사용자 인터페이스가 현재 화면에 보이면서 사용자와 데이터를 입출력할 수 있을 때는 포그라운드 상태라고 한다.

 이것과 달리 동적 상태는 약간 복잡한 이유 때문에 데이터가 저장되고 복원된다. 예를 들어 하나의 텍스트 필드와 몇 개의 라디오 버튼(radio button)을 갖는 액티비티 A가 있다. 애플리케이션을 사용하는 동안 사용자는 텍스트 필드에 텍스트를 입력하고 라디오 버튼을 선택한다. // radio button은 여러 개의 선택지 중 하나만 선택하게끔 구성되어 있는 버튼이다. 온라인으로 객관식 문제 풀 때 등장하는 선택지들 중 하나를 선택할 수 있게끔 되어 있는 것이 radio button이다.

이때 변경 사항을 저장하기 전 사용자가 다른 액티비티로 전환한다면, 액티비티 A는 액티비티 스택으로 들어가고 백그라운드 상태가 된다. 이후 장치의 메모리가 부족해져 런타임 시스템이 부족한 리소스를 보충하기 위해 액티비티 A를 종결시킨다(kill). 그러나 사용자는 액티비티 A가 그냥 백그라운드에 있다가 언제든지 포그라운드로 올 준비가 되어 있다고 생각한다. 즉, 액티비티 A가 포그라운드로 돌아오면 자신이 입력했던 텍스트와 선택한 라디오 버튼들이 그대로 남아 있으리라 생각한다.


 그러나 위의 경우 액티비티 A의 새로운 인스턴스가 생성되므로, 만약 동적 상태 데이터가 저장되어 복원되지 않았다면 사용자가 이전에 입력한 데이터는 유실된다. 또한 안드로이드 장치의 구성이 변경되는 경우에도 항상 그 액티비티의 인스턴스를 새로 생성한다는 것에 유의하자. 이는 변경된 상황에 맞게 액티비티를 다시 구성해야하기 때문이다.


 예를 들어, 장치를 세웠다 눕혔다 하면 그때마다 장치의 구성이 변경되므로 (가로 세로 전환 설정시) 현재 화면에 있는 액티비티의 인스턴스를 소멸시키고 새로운 인스턴스를 생성한다. 그러므로 동적 상태를 저장하는 것의 주 목적은 포그라운드와 백그라운드 액티비티들 간의 매끄러운 전환을 제공하기 위함이다.



액티비티가 실행하는 동안 전환하는 생애를 아래 정리해보았습니다. 액티비티는 전체(entire), 가시적(visible), 포그라운드(foreground)의 세 가지 생애를 번갈아가며 반복합니다.


    • 전체 생애(Entire Lifetime) - 액티비티가 생성될 때 최초 호출되는 onCreate( ) 메서드 호출과 종결되기 전에 호출되는 onDestroy( ) 호출 사이에 액티비티에서 발생하는 모든 것을 나타내는 데 '전체 생애'라는 용어가 사용됩니다.

    • 가시적 생애(Visible Lifetime) onStart( )와 onStop( ) 호출 사이의 액티비티 실행 시기다. 이 시기 동안 액티비티는 자신을 사용자에게 화면으로 보여줄 수 있습니다.

    • 포그라운드 생애(Foreground Lifetime) onResume( ) 메서드 호출과 onPause( ) 호출 사이의 액티비티 실행 시기를 의미합니다.

 
액티비티는 자신의 전체 생애 동안 포그라운드와 가시적 생애를 여러 번 거칠 수 있습니다. 아래의 그림은 액티비티의 생애와 생명주기 메서드들의 개념을 보여줍니다.


Activity 생명주기 메소드

 Activity 클래스는 생명주기 메서드를 많이 갖고 있으며, 그 메서드들은 액티비티의 상태가 변경될 때 이벤트 처리기(event handler)처럼 동작한다. 안드로이드 Activity 클래스가 지원하는 주요 생명주기 메서드들은 아래와 같다. // 생명주기 메서드란 액티비티의 상태가 변경된다는 것을 그 액티비티에게 알려주기 위해 안드로이드 런타임이 자동으로 호출하는 메서드를 의미한다.


  • onCreate(Bundle savedInstanceState) 이 메서드는 액티비티 인스턴스가 최초로 생성될 때 호출되며, 대부분의 초기화 작업을 진행한다. 메서드의 매개변수(인자)는 동적 상태 정보를 포함할 수 있는 Bundle 객체가 전달된다. 그리고 동적 상태 정보는 직전에 생성되었다가 어떠한 이유로 종료된 후 재시작되면 종료될 때 호출된 OnSaveInstanceState()에서 저장한 내용과 동일한 Bundle을 넘겨준다. 일반적으로 사용자 인터페이스의 상태와 관련되는 데이터다. 
  • onStart( ) - 예외없이 onCreate( )나 onRestart( ) 메서드가 호출된 후 바로 호출된다. 그리고 액티비티의 사용자 인터페이스가 곧 사용자에게 보이게 될 것이라고 액티비티에게 알려준다. 만약 액티비티 스택의 맨 위로 이동하면 이 메서드가 호출된 다음에는 onResume( )가 호출될 것이다.
  • onResume( ) - 액티비티가 액티비티 스택의 맨 위에 있으며, 사용자가 현재 상호 동작하는 (실행 중인)액티비티임을 알려준다. // 액티비티 스택의 맨 위에 있는 액티비티가 현재 화면에 보이는 액티비티다.
  • onPause( ) - 이 메서드는 액티비티위에 다른 액티비티가 올라와서 focus를 잃었을 때 호출된다. 완전 액티비티가 가려지지 않은 상태에서 호출되는 함수이다. 즉 일부분이 보이거나 투명상태일 경우 호출된다. 이 메서드 내부에서는 액티비티에서 필요한 영속적 데이터(콘텐트 제공자, 데이터베이스, 파일에 저장되는 데이터)를 저장하는 일을 해야 한다. 이 메서드는 또한 애니메이션과 같이 CPU를 지나치게 사용하는 작업들을 중단해야 한다.
  • onStop( ) - 이 메서드가 호출될 때는 액티비티가 더 이상 사용자에게 보이지 않는다. 이 메서드 호출 다음에는 onRestart( ) 또는 onDestroy( )가 호출된다. 액티비티가 다시 포그라운드로 들어가면 onRestart( )가 호출되며, 액티비티가 종료될 때는 onDestroy( )가 호출된다.
  • onDestroy( ) - 이 메서드는 액티비티가 막 소멸되려고 하거나 혹은 자발적으로 소멸될 때 호출된다. 액티비티가 자신의 작업을 완료하고 finish( ) 메서드를 호출했거나 또는 메모리를 해제하거나 구성 변경(예를 들면 가로/세로 화면 변경)이 생겨 런타임이 액티비티를 종결하기 때문이다. 그러나 액티비티가 종료될 때 항상 onDestroy( ) 메서드가 호출되는 것은 아니라는 점에 유의하자.

위와 같은 생명주기 메서드와 더불어 액티비티의 동적 상태를 저장하고 복원하기 위해 특별히 만들어진 두 개의 메서드가 있다. 아래의 두 메서드를 살펴보자.

  • onRestoreInstanceState(Bundle savedInstanceState) - onCreate( ) 메서드처럼 이 메서드도 이전 상태 데이터를 포함하는 Bundle 객체를 매개변수로 받는다. 주의할 점은 OnRestoreInstanceState()는 정상적인 상황에서는 호출되지 않는다. 예시로 디바이스회전시, 강제종료 후 재 시작 할 때 발생한다.
  • onSaveInstanceState(Bundle outState) - 현재의 동적 상태 데이터가 저장될 수 있게끔 액티비티가 소멸되기 전에 호출된다. 여기서 동적 상태 데이터는 대개 사용자 인터페이스와 관련된 것들이다. 이 메서드도 Bundle 객체를 매개변수로 받으며, 저장되어야 하는 상태 데이터를 Bundle 객체에 넣는다. 그리고 이 Bundle 객체는 액티비티가 다시 시작될 때 onCreate( )와 onRestoreInstanceState( ) 메서드에 전달된다. 동적 상태 데이터가 저장될 필요가 있다는 것을 런타임이 알 경우에만 이 메서드가 호출된다는 점에 유의하자.

액티비티에서 위의 여러 메서드를 오버라이딩 할 때 꼭 기억할 것이 있다. onRestoreInstanceState( )와 onSaveInstanceState( ) 두 메서드를 제외한 나머지 메서드에서는 자신의 구현 코드에서 반드시 Activity 슈퍼 클래스의 오버라이딩되는 메서드를 호출해줘야 한다.

 예를 들어 아래의 메서드는 onRestart( ) 메서드를 오버라이딩 한다. 그리고 메서드 구현 코드에서 슈퍼 클래스 인스턴스의 오버라이딩되는 메서드를 호출한다.


오버라이딩하는 메서드에서 슈퍼 클래스의 오버라이딩되는 메서드를 호출하지 않으면 액티비티 실행 중에 런타임이 예외를 발생시킨다. 단, onRestoreInstanceState( )와 onSaveInstanceState( ) 메서드의 경우는 슈퍼 클래스 메서드 호출을 하지 않아도 된다. 


마무리

안드로이드 4대 컴포넌트 중 하나인 Activity에 대해 살펴보았는데 생명주기를 잘 생각하면서 코딩하는 습관이 필요하다고 생각된다.


관련글

내용이 도움이 되셨거나 초보 블로거를 응원하고 싶으신 분은 아래 하트♥공감 버튼을 꾹 눌러주세요! 

내용의 수정이 있거나 도움이 필요하신 분은 댓글을 남겨주세요!