제임스딘딘의
Tech & Life

개발자의 기록 노트/Android

[안드로이드] 안드로이드 Activity

제임스-딘딘 2017. 5. 11. 15:39

안드로이드 액티비티란?

Activity는 일종의 애플리케이션 구성 요소로서, 사용자가 전화 걸기, 사진 찍기, 이메일 보내기 또는 지도 보기 등의 일을 하기 위해 상호작용할 수 있는 화면을 제공한다.
액티비티마다 창이 하나씩 주어지며, 안드로이드 앱 개발자는 이곳에 UI(사용자 인터페이스)를 구현하게된다. 이 창은 일반적으로 화면을 가득 채우지만, 작은 창으로 만들어 다른 창 위에 띄울 수도 있다.

하나의 애플리케이션은 보통 여러 개의 액티비티가 느슨하게 서로 묶여 있는 형태로 구성된다. 통상 한 애플리케이션 내에서 하나의 액티비티가 "Main" 액티비티로 지정되며, 사용자가 이 애플리케이션을 처음 실행할 때 이 "Main"으로 지정된 액티비티가 사용자에게 최초로 보여지게 된다. 

 각각의 액티비티는 여러 가지 작업을 수행하기 위해 또 다른 액티비티를 시작할 수 있다. 새로운 액티비티가 시작될 때마다 이전 액티비티는 중단되지만 시스템은 해당 액티비티를 스택("백 스택")에 보존하게된다. 새로운 액티비티가 시작되면, 이전 액티비티는 백 스택으로 Push되며, 새로운 액티비티가 사용자 포커스를 갖게된다. 백 스택은 기본적인 "후입선출" 방식을 준수하므로, 사용자가 현재 액티비티를 끝내고 'Back'키를 누르면 해당 액티비티가 스택에서 Pop되고, 스택상에서는 지워지며, 이전 액티비티가 재개(resume)된다.

 하나의 액티비티가 다른 하나의 새로운 액티비티의 시작으로 인해 중단된 경우, 액티비티에 "상태 변경이 발생했다" 라고 말할 수 있다. 이러한 액티비티의 상태 변경은 액티비티의 수명 주기 콜백 메서드를 통해 통지된다. 액티비티가 시스템 액티비티를 생성, 중단, 재시작, 제거하는 등의 상태 변화로 인해 받을 수 있는 콜백 메서드는 여러 가지가 있다. 각 콜백은 상태 변화에 알맞은 특정 작업을 수행할 기회를 개발자에게 제공한다. 예를 들어 액티비티가 중단(stop)되면 네트워크 또는 데이터베이스 연결과 같은 자원들을 해제(release)해야 한다. 액티비티가 재개(resume)되면, 필요한 리소스를 다시 획득(acquire)하여 중단된 작업을 다시 시작할 수 있다. 이러한 상태 전환은 모두 액티비티 수명 주기의 일부이다.

이 포스팅에서 다양한 액티비티 상태 사이의 전환을 적절히 관리할 수 있도록 액티비티 수명 주기가 작동하는 방식을 자세히 논하는 등, 액티비티를 구축하고 사용하는 기본적 방법을 설명해보겠다.

액티비티 생성

액티비티를 생성하려면 Activity의 서브클래스(또는 이의 기존 서브클래스)를 생성해야 한다. 

그리고, 서브클래스에서는 액티비티 생성, 중단, 재개, 소멸 시기 등과 같은 수명 주기의 다양한 상태 사이를 액티비티가 전환 할 때마다 시스템이 호출해주는 콜백 메서드를 구현해야 한다. 

가장 중요한 콜백 메서드는 아래 두가지다. 일단 이것만 기억하고 시작해보자.

onCreate()
이 콜백메서드는 반드시 구현해야 한다. 액티비티를 생성할 때 안드로이드 시스템이 이것을 호출한다. 또한 구현부 최상단에서는 액티비티의 필수 구성 요소를 초기화해야 한다. 무엇보다도 중요한 점은, 바로 이 콜백에서 setContentView()를 호출해야 액티비티의 사용자 인터페이스 레이아웃을 화면에 뜨게 할 수 있다는 점이다. 즉, 이걸 구현하지 않으면 화면에 아무것도 보이지않는다.

onPause()
시스템이 이 메서드를 호출하는 것은 사용자가 액티비티를 떠난다는 첫 번째 신호다.(다만 이것이 항상 액티비티가 소멸 중이라는 뜻은 아님)
현재 사용자 세션을 넘어서 지속되어야 하는 변경 사항을 커밋하려면 보통 이곳에서 해야 한다.(사용자가 다시 이 액티비티 화면으로 돌아오지 않을 수 있기 때문이다. 안드로이드 폰 사용할 때, 어떤 앱을 한참 쓰다가 홈버튼 누르고, 그날 그 앱을 실행 하지 않는 경우를 상상하자. 사용자는 하룻밤을 자고나서 그앱을 실행할 수 있고, 심지어 한 일주일 뒤에 그앱을 실행할 수도 있다.)

아직 다루진 않았지만 여러 액티비티 사이에서 원활한 사용자 환경을 제공하고, 액티비티 중단이나 심지어 소멸을 초래할 수도 있는 예상치 못한 간섭을 처리하기 위해 사용해야 하는 다른 수명 주기 콜백 메서드도 여러 가지 있다.


사용자 인터페이스 구현

한 액티비티에 대한 사용자 인터페이스는 뷰 계층—즉, View 클래스에서 파생된 객체가 제공한다. 

각각의 뷰는 액티비티 창 안의 특정한 직사각형 공간을 제어하며 사용자 상호작용에 대응할 수 있다. 
예를 들면, 어떤 뷰는 사용자가 터치하면 작업을 시작하는 버튼일 수 있다.

Android는 레이아웃을 디자인하고 정리하는 데 사용할 수 있도록 여러 가지 뷰를 미리 만들어 제공한다. 

"위젯"이란 화면에 시각적(및 대화형) 요소를 제공하는 뷰이다. 예를 들어 버튼, 텍스트 필드, 체크박스나 그저 하나의 이미지일 수도 있다.

"레이아웃"은 선형 레이아웃, 격자형 레이아웃, 상대적 레이아웃과 같이 하위 레이아웃에 대해 독특한 레이아웃 모델을 제공하는 ViewGroup에서 파생된 뷰이다. 또한, View와 ViewGroup 클래스(또는 기존 서브클래스)의 아래로 내려가서 위젯과 레이아웃을 생성하고 이를 액티비티 레이아웃에 적용할 수 있다.

뷰를 사용하여 레이아웃을 정의하는 가장 보편적인 방식은 애플리케이션 리소스에 저장된 XML 레이아웃 파일을 사용하는 것이다. 이렇게 하면 액티비티의 동작을 정의하는 소스 코드와 별개로 사용자 인터페이스 디자인을 유지할 수 있다. setContentView()로 액티비티의 UI로서 레이아웃을 설정하고, 해당 레이아웃의 리소스 ID를 전달할 수 있다. 그러나 액티비티 코드에 새로운 View를 생성하고 새로운 View를 ViewGroup에 삽입하여 뷰 계층을 구축한 뒤 루트 ViewGroup을 setContentView()에 전달해도 해당 레이아웃을 사용할 수 있다.



액티비티 수명 주기 관리

콜백 메서드를 구현하여 액티비티의 수명 주기를 관리하는 것은 강력하고 유연한 애플리케이션 개발에 대단히 중요한 역할을 한다. 액티비티의 수명 주기는 다른 액티비티와의 관계, 액티비티의 작업과 백 스택 등에 직접적으로 영향을 받는다.

액티비티는 기본적으로 세 가지 상태로 존재할 수 있다.

재개됨(Resumed)
액티비티가 화면 포그라운드에 있고 사용자 포커스를 갖고 있다. (이 상태를 때로는 "실행 중"이라고 일컫기도 한다).

일시정지됨(Paused)
다른 액티비티가 포그라운드에 나와 있고 사용자의 시선을 집중시키고 있지만, 이 액티비티도 여전히 표시되어 있다. 다시 말해, 다른 액티비티가 이 액티비티 위에 표시되어 있으며 해당 액티비티는 부분적으로 투명하거나 전체 화면을 덮지 않는 상태라는 뜻이다. 일시정지된 액티비티는 완전히 살아있지만(Activity 객체가 메모리에 보관되어 있고, 모든 상태 및 멤버 정보를 유지하며, 창 관리자에 붙어 있는 상태로 유지됨), 메모리가 극히 부족한 경우에는 예외적으로 안드로이드 시스템 판단에 따라, 중단시킬 수 있다.

정지됨(Stopped)
이 액티비티가 다른 액티비티에 완전히 가려진 상태다. (액티비티가 이제 "백그라운드"에 위치함). 
중단된 액티비티도 여전히 살아 있기는 마찬가지이다. (Activity 객체가 메모리에 보관되어 있고, 모든 상태와 멤버 정보를 유지하시만 창 관리자에 붙어 있지 않음 ). 
그러나, 이는 더 이상 사용자에게 표시되지 않으며 다른 곳에 메모리가 필요한 상황이 되면 언제든지 안드로이드 시스템이 임의대로 종료시킬 수 있다.


액티비티가 일시정지 또는 중단된 상태이면, 시스템이 이를 메모리에서 삭제할 수 있음을 기억하자.
이러기 위해서는 종료를 요청하거나(finish() 메서드를 호출) 단순히 이 액티비티의 프로세스를 중단시키면 된다.
또한, 종료 또는 중단된 이후에 액티비티가 다시 열릴 때는 처음부터 다시 생성해야 한다는 점을 상기하자.


수명 주기 콜백 구현

위에서 설명한 바와 같이 액티비티가 여러 가지 상태를 오가며 전환되면, 이와 같은 내용이 여러 가지 콜백 메서드를 통해 통지된다.

콜백 메서드는 모두 hooking 가능한 시점이다.

액티비티 상태가 변경될 때마다 적절한 작업을 수행시킬 필요가 있다면, 개발자는 이를 직접 재정의할 수 있다.

다음의 기본 액티비티에는 기본 수명 주기 메서드가 각각 하나씩 포함되어 있다.

public class ExampleActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // The activity is being created.
    }
    @Override
    protected void onStart() {
        super.onStart();
        // The activity is about to become visible.
    }
    @Override
    protected void onResume() {
        super.onResume();
        // The activity has become visible (it is now "resumed").
    }
    @Override
    protected void onPause() {
        super.onPause();
        // Another activity is taking focus (this activity is about to be "paused").
    }
    @Override
    protected void onStop() {
        super.onStop();
        // The activity is no longer visible (it is now "stopped")
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // The activity is about to be destroyed.
    }
}


 이와 같은 메서드를 모두 합쳐 '하나의 액티비티의 수명 주기 전체' 로 정의한다. 이러한 메서드를 구현함으로써 액티비티 수명 주기 내의 세 가지 중첩된 루프를 모니터할 수 있다.

 한 액티비티의 전체 수명은 onCreate() 호출과 onDestroy() 호출 사이를 말한다. 액티비티는 onCreate()에서 "전체" 상태(레이아웃 정의 등)의 설정을 수행한 다음 나머지 리소스를 모두 onDestroy()에 해제해 주어야 한다. 예를 들어, 액티비티에 네트워크에서 데이터를 다운로드하기 위해 배경에서 실행 중인 스레드가 있는 경우, 이는 해당 스레드를 onCreate()에서 생성한 다음 onDestroy()에서 그 스레드를 중단할 수 있어야 한다.

 한 액티비티의 가시적 수명은 onStart() 호출과 onStop() 호출 사이를 말한다. 이 기간 중에는 사용자가 액티비티를 화면에서 보고 이와 상호작용할 수 있다. 예컨대 onStop()이 호출되어 새 액티비티가 시작되면 이 액티비티는 더 이상 표시되지 않게 된다. 이와 같은 두 가지 메서드 중에서 사용자에게 액티비티를 표시하는 데 필요한 리소스를 유지하면 된다. 예를 들어, onStart()에서 BroadcastReceiver를 등록하고 UI에 영향을 미치는 변화를 모니터링하고 onStop()에서 등록을 해제하면 사용자는 여러분이 무엇을 표시하고 있는지 더 이상 볼 수 없게 된다. 시스템은 액티비티의 전체 수명 내내 onStart() 및 onStop()을 여러 번 호출할 수 있으며, 이때 액티비티는 사용자에게 표시되었다 숨겨지는 상태를 오가게 된다.

액티비티의 Foreground 수명은 onResume( ) 호출과 onPause( ) 호출 사이를 말한다. 이 기간 중에는 이 액티비티가 화면에서 다른 모든 액티비티 앞에 표시되며 사용자 입력도 여기에 집중된다. 액티비티는 포그라운드에 나타났다 숨겨지는 전환을 자주 반복할 수 있다. 예를 들어 , 기기가 절전 모드에 들어가거나 대화상자가 나타나면 onPause()가 호출된다. 이 상태는 자주 전환될 수 있으므로, 이 두 가지 메서드의 코드는 상당히 가벼워야 한다. 그래야 전환이 느려 사용자를 기다리게 하는 일을 피할 수 있다.


아래 그림은 액티비티가 상태 사이에서 취할 수 있는 이와 같은 루프와 경로를 나타낸 것이다. 직사각형은 콜백 메서드를 나타내며, 이 콜백 메서드에서 액티비티가 여러 상태 사이를 전환할 때 작업을 수행하도록 구현할 수 있다.


액티비티 수명 주기