티스토리 뷰

/* 본 게시물은 '핵심만 골라 배우는 안드로이드 스튜디오 & 프로그래밍(Android Studio 2 Development Essentials) | 닐 스미스 지음' 의 내용을 토대로 작성되었습니다. */


# Activity 클래스


 거의 예외 없이 애플리케이션의 액티비티들은 안드로이드 Activity 클래스 또는 Activity 클래스의 서브 클래스인 다른 클래스(예를 들어, 하위 버전과의 호환성을 고려하여 만든 AppCompatActivity 또는 FragmentActivity) 중 하나의 서브 클래스로 생성된다.


 안드로이드 앱은 액티비티가 근간이 되며, 액티비티는 리눅스 커널의 프로세스로 실행된다. 그리고 하나의 UI (=단위 기능의 화면)를 갖고 처리한다. 필요하다면 하나의 앱에서 여러 개의 액티비티를 갖고 한 액티비티가 다른 액티비티를 연계하여 실행하도록 할 수도 있다. 이때 인텐트(Intent)를 사용한다. 이것과는 다른 방법으로 하나의 액티비티에서 여러 개의 프래그먼트(Fragment)를 갖고 실행할 수도 있다.


 안드로이드 앱을 개발할 때 주로 사용하는 액티비티 클래스에는 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 클래스와 그것의 서브 클래스들은 안드로이드 런타임이 자동으로 호출하는 메서드를 많이 갖고 있다. 액티비티의 상태가 변경된다는 것을 그 액티비티에게 알려주기 위해서다. 그런 메서드들을 액티비티 생명주기 메서드(activity lifecycle method)라고 한다. 

 보통 액티비티 클래스에서는 그런 메서드들을 오버라이드(override)하여 필요한 기능들을 구현만 하면 된다. // 액티비티의 상태가 변경될 때 우리가 원하는, 필요로 하는 처리를 하기 위해 오버라이드 한다. onCreate( ) 메서드는 반드시 구현해야 한다.


# 동적상태 / 영속적 상태

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


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


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


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


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


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


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


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



# 안드로이드 액티비티 생명주기 메서드


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


  • onCreate(Bundle savedInstanceState) - 이 메서드는 액티비티 인스턴스가 최초로 생성될 때 호출되며, 대부분의 초기화 작업을 진행한다. 메서드의 매개변수(인자)는 동적 상태 정보를 포함할 수 있는 Bundle 객체가 전달된다. 그리고 동적 상태 정보는 직전에 생성되었다가 소멸된 동일한 액티비티의 인스턴스로부터 받으며, 일반적으로 사용자 인터페이스의 상태와 관련되는 데이터다.

  • onRestart( ) - 액티비티가 런타임 시스템에 의해 이전에 중단되었다가 막 다시 시작될 때 호출된다.

  • onStart( ) - 예외없이 onCreate( )나 onRestart( ) 메서드가 호출된 후 바로 호출된다. 그리고 액티비티의 사용자 인터페이스가 곧 사용자에게 보이게 될 것이라고 액티비티에게 알려준다. 만약 액티비티 스택의 맨 위로 이동하면 이 메서드가 호출된 다음에는 onResume( )가 호출될 것이다.

  • onResume( ) - 액티비티가 액티비티 스택의 맨 위에 있으며, 사용자가 현재 상호 동작하는 (실행 중인)액티비티임을 알려준다. // 액티비티 스택의 맨 위에 있는 액티비티가 현재 화면에 보이는 액티비티다.

  • onPause( ) - 이 메서드 호출 다음에는 onResume( ) 또는 onStop( ) 메서드 중 하나가 호출된다. 액티비티가 포그라운드로 돌아가는 경우 계속 실행하기 위해 onResume( )가 호출되며, 액티비티의 사용자 인터페이스를 사용자가 볼 수 없게 되면 중단되면서 onStop( )가 호출된다.
     이 메서드 내부에서는 액티비티에서 필요한 영속적 데이터(콘텐트 제공자, 데이터베이스, 파일에 저장되는 데이터)를 저장하는 일을 해야 한다. 이 메서드는 또한 애니메이션과 같이 CPU를 지나치게 사용하는 작업들을 중단해야 한다.

  • onStop( ) - 이 메서드가 호출될 때는 액티비티가 더 이상 사용자에게 보이지 않는다. 이 메서드 호출 다음에는 onRestart( ) 또는 onDestroy( )가 호출된다. 액티비티가 다시 포그라운드로 들어가면 onRestart( )가 호출되며, 액티비티가 종료될 때는 onDestroy( )가 호출된다.

  • onDestroy( ) - 이 메서드는 액티비티가 막 소멸되려고 하거나 혹은 자발적으로 소멸될 때 호출된다. 액티비티가 자신의 작업을 완료하고 finish( ) 메서드를 호출했거나 또는 메모리를 해제하거나 구성 변경(예를 들면 가로/세로 화면 변경)이 생겨 런타임이 액티비티를 종결하기 때문이다. 그러나 액티비티가 종료될 때 항상 onDestroy( ) 메서드가 호출되는 것은 아니라는 점에 유의하자.

 위와 같은 생명주기 메서드와 더불어 액티비티의 동적 상태를 저장하고 복원하기 위해 특별히 만들어진 두 개의 메서드가 있다. 아래의 두 메서드를 살펴보자.
  • onRestoreInstanceState(Bundle savedInstanceState) - 상태 정보가 저장되었던 이전 액티비티 인스턴스로부터 액티비티가 다시 시작하는 경우에 이 메서드는 onStart( ) 메서드가 호출된 후 곧바로 호출된다. onCreate( ) 메서드처럼 이 메서드도 이전 상태 데이터를 포함하는 Bundle 객체를 매개변수로 받는다.
     그리고 onCreate( )와 onStart( )에서 액티비티의 초기화가 수행된 후에 이전 상태 데이터를 복원하는 것이 더 좋을 때 이 메서드가 사용된다.

  • onSaveInstanceState(Bundle outState) - 현재의 동적 상태 데이터가 저장될 수 있게끔 액티비티가 소멸되기 전에 호출된다. 여기서 동적 상태 데이터는 대개 사용자 인터페이스와 관련된 것들이다. 이 메서드도 Bundle 객체를 매개변수로 받으며, 저장되어야 하는 상태 데이터를 Bundle 객체에 넣는다. 
     그리고 이 Bundle 객체는 액티비티가 다시 시작될 때 onCreate( )와 onRestoreInstanceState( ) 메서드에 전달된다. 동적 상태 데이터가 저장될 필요가 있다는 것을 런타임이 알 경우에만 이 메서드가 호출된다는 점에 유의하자.
 액티비티에서 위의 여러 메서드를 오버라이딩 할 때 꼭 기억할 것이 있다. onRestoreInstanceState( )와 onSaveInstanceState( ) 두 메서드를 제외한 나머지 메서드에서는 자신의 구현 코드에서 반드시 Activity 슈퍼 클래스의 오버라이딩되는 메서드를 호출해줘야 한다.

 예를 들어 아래의 메서드는 onRestart( ) 메서드를 오버라이딩 한다. 그리고 메서드 구현 코드에서 슈퍼 클래스 인스턴스의 오버라이딩되는 메서드를 호출한다.
protected void onRestart() {
super.onRestart();
Log.i(TAG, "onRestart");
}

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



# 액티비티 생애


 끝으로 액티비티가 실행하는 동안 전환하는 생애를 아래 정리해보았다. 액티비티는 전체(entire), 가시적(visible), 포그라운드(foreground)의 세 가지 생애를 오간다.

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

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

  • 포그라운드 생애(Foreground Lifetime) - onResume( ) 메서드 호출과 onPause( ) 호출 사이의 액티비티 실행 시기를 의미한다.
 액티비티는 자신의 전체 생애 동안 포그라운드와 가시적 생애를 여러 번 거칠 수 있다. 아래의 그림은 액티비티의 생애와 생명주기 메서드들의 개념을 보여준다.




# 요약

 모든 액티비티들은 안드로이드 Activity 클래스로부터 상속된다. 그리고 액티비티의 상태가 변경될 때 런타임 시스템에 의해 호출되도록 설계된 이벤트 메서드들을 갖는다. 이 메서드들을 오버라이딩함으로써 액티비티는 상태 변화에 응답할 수 있다. 또한 액티비티와 애플리케이션 모두의 현재 상태 데이터를 저장 및 복원도 할 수 있다.


 액티비티 상태는 두 가지 형태로 생각할 수 있다. 영속적 상태는 애플리케이션이 실행되는 동안 파일 또는 데이터베이스 등에 저장해야 하는 데이터를 말한다. 동적 상태는 현재 화면에 보이는 사용자 인터페이스와 관련되는 데이터 및 액티비티 내부에서만 보존해야 하는 변수들의 데이터를 말한다.


댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday