[Android] Activity

dEpayse
dEpayse_publication
15 min readFeb 4, 2021
  • 본 포스트는 Kotlin 언어로 Android studio 에서 작업할 수 있는 내용을 담고 있습니다.
  • 본 포스트는 Kotlin 언어에 관한 설명은 없습니다. Kotlin에 관한 내용은 저의 다른 포스트를 참고해주시면 감사하겠습니다.

Activity 란?

App(Application) 구성요소

Android Application의 필수 빌딩 블럭인 구성요소는 시스템이나 사용자가 App에 들어올 수 있는 진입점이다. App의 구성요소에는 다음 네 가지가 있다.

  • Activity
  • Service
  • Content Provider
  • Broadcast Receiver

이번 포스트에선 Activity를 다룰 것이다.

Activity

Activity는 사용자와 App이 상호작용하기 위한 진입점이다. App이 사용자와 상호작용할 수 있도록 하는 것을 UI(User Interface)라고도 하는데, 잘 와닿지 않는다면 일단 Activity는 ‘(UI가 있는) 화면’을 떠올리자. 실제로, Android Studio에서 Activity를 생성하면

  1. 시각적 화면을 구성하는 layout 파일 하나(.xml)와,
  2. layout을 보여주고 다양한 동작을 제어하는 kotlin 파일(.kt) 혹은 java 파일(.java)

두 가지가 생성된다. Fig1은 Android Studio에서 Activity 하나를 생성하여 두 가지 파일이 생성되는 것을 보여준다. 코드 상에서 Activity는 ‘Activity 타입의 클래스’로 볼 수 있다.

Fig1–1. Empty Activity 생성하기1
Fig1–2. Empty Activity 생성하기2
Fig1–3. Empty Activity 생성하기3

처음 프로젝트를 생성할 때도, Empty Activity를 선택하여 생성한다면 MainActivity.kt 파일(Source Language : Kotlin)과 activity_main.xml 파일 두 개가 생성되는 것을 볼 수 있다.

Activity가 추가되는 과정

Fig1에서 봤듯이 Activity를 쉽게 추가할 수 있지만, 사실 프로젝트에서 Activity를 추가할 때 내부적으로 더 세분화된 과정이 있다. Fig1에서 봤듯이 Activity를 생성하면 layout파일과 kotlin 파일이 생성된다. 하지만 Activity를 프로젝트에 추가할 때 관련된 파일이 하나 더 있는데, AndroidManifest.xml 파일이다.

즉 Activity를 프로젝트에 추가할 때 관련된 파일은 다음 세 가지이다.

  • Activity class를 상속받는 kotlin 클래스 파일(.kt) 혹은 java 클래스 파일(.java)
  • manifest 파일(AndroidManifest.xml)
  • layout xml 파일(.xml)

manifest는 본 포스트에서 자세히 다루지는 않지만, 모든 프로젝트가 갖고 있어야 하는 파일이고, App의 여러 가지 필수 정보를 포함한다. 포스트 상단에서 다룬 App의 구성 요소도 manifest가 포함하기 때문에, activity를 추가할 때 manifest에 추가해주어야 한다.

이제 Fig1 같은 방법이 아닌 좀 더 세분화된 방법으로 activity를 추가해보자. 이 방법은 학습이 목적일 뿐이며, 실제로 프로젝트를 진행할 때는 더 효율적인 방법을 택하자.

Activity 직접 추가하기1. Activity class를 상속받는 class 파일 생성하기

Fig2–1. Activity를 상속받는 class 파일 생성하기

포스트 상단에서 코드 상의 Activity는 Activity 타입의 클래스라고 하였다. Activity를 추가하기 위해, 먼저 Activity타입의 클래스를 만들어보자. 방법은 java나 kotlin의 클래스를 만들고, Activity를 상속받으면 된다. Fig1에서 만든 Activity는 AppCompatActivity 클래스를 상속 받는데, 이 클래스 역시 Activity의 하위 클래스이므로 Activity 타입이다.

Activity 직접 추가하기2. AndroidManifest.xml에 activity 추가하기

Fig2–2. AndroidManifest.xml에 activity 추가하기

Activity타입의 클래스를 생성해도, manifest에 등록해주지 않으면 시스템이 이 Activity가 있는지 알 수 없다. Activity를 manifest에 추가해주는 방법은 Fig2–2와 같다. “.TestActivity”의 ‘.’은 프로젝트 패키지명을 뜻한다. 만약 Activity타입 클래스의 디렉토리가 “프로젝트 패키지명.common”에 있으면 name 속성 값을 “.common.액티비티명”으로 해주면 된다.

name 속성 값을 입력할 때 ctrl+space를 누르면 자동 완성으로 불러올 수 있는 Activity 목록을 볼 수 있는데, Fig2–1과 같이 Activity를 상속받지 않는다면 이 목록에서도 볼 수 없다.

Activity 직접 추가하기3. layout xml 파일 생성하기

Fig2–3. layout xml 파일 생성하기

Activity는 UI가 있는 화면이라고 하였다. 구상된 화면을 보여주기 위해서는 화면을 구상하는 layout 파일을 생성해야 한다. layout 파일은 res(Resource) 의 layout 디렉토리에 추가하면 된다.

Activity 직접 추가하기4. Activity class를 상속받는 class 파일로 layout(화면) 보여주기

Fig2–4. Activity를 상속받는 class 파일로 layout(화면) 보여주기

이제 Activity 타입의 클래스 파일에 화면을 보여주는 코드를 작성하면 된다. onCreate()라는 함수는 Activity의 생명주기에 포함되는 함수인데, 본 포스트 하단부에서 다루므로 자세한 내용은 포스트 하단부를 참고하자. 여기서 화면에 보여질 내용을 정하는 것이 setContentView(R.layout.activity_test)이다. 정확히는 setContentView함수가 argument를 ‘inflate’하는 역할을 한다. inflate란 xml파일인 layout을 ‘parsing’하여 메모리에 객체화시키는 것을 말한다. parsing은 사전적으로 분석이라는 뜻인데, xml파일을 parsing하는 것은 안드로이드 시스템에서 각종 태그들로 이루어진 텍스트를 시스템이 이해할 수 있도록 만드는 것을 뜻한다. argument로 들어간 R.layout.activity_test가 Fig2–3에서 생성한 레이아웃 파일(activity_test.xml)을 가리킨다.

(R.layout.activity_test의 뜻은 본 포스트에서 다루지 않는다. 안드로이드의 리소스 관리가 관련된다.)

위의 과정을 요약하면 Fig3과 같다.

Fig3. Activity 직접 추가 요약

Activity Life cycle

하나의 어플리케이션에는 여러 개의 activity가 존재할 수 있다. 어플리케이션에는 여러 개의 화면이 존재하고 이 화면들은 보통 각각의 activity로 존재한다. android는 여러 개의 activity를 어떻게 관리할까?

Android Activity 관리

Android는 Activity를 Stack이라는 자료 구조를 이용하여 관리하는데, Stack은 나중에 저장된 것이 먼저 나가는 구조(Last In First Out, LIFO)로 되어 있다. Stack은 어떤 박스 안에 박스 크기에 맞는 책을 하나씩 쌓는다는 상황을 떠올리면 이해가 좀 더 쉬울 수도 있다. 가장 먼저 들어간 책을 제일 나중에 꺼내야하고, 가장 나중에 들어간 책을 제일 먼저 꺼내야 한다. 안드로이드 휴대폰에서 우리가 보는 화면은 이 박스의 가장 위에 있는 책인 것이다. Fig4에서 우리가 보는 화면은 Activity A가 된다.

Fig4. Stack으로 관리하는 Android Activity

Activity 상태

우리가 휴대폰에서 보는 화면은 Stack의 가장 위에 있는 Activity이다. 그러나 Stack의 아래 쪽에 있다고 해서 Activity가 종료된 것은 아니다. 종료된 상태는 따로 존재한다. 이렇게 Android의 Activity는 Lifetime에 관련된 상태를 나눈다. Activity의 상태는 크게 네 가지로 나뉜다.

Fig5. Activity의 상태 정보
  • running/active : 사용자가 App과 상호작용하고 있는 Stack 가장 위쪽(foreground)의 Activity의 상태이다.
  • paused/visible : 사용자에게 Activity가 보이기는 하지만 상호작용은 할 수 없는 상태이다. 이 상태는 Activity보다 크기가 작거나, 투명한 다른 Activity가 올라오는 경우, multi-window에서 다른 Activity를 사용하고 있는 경우, 현재 window에서 상호작용할 수 없는 경우를 포함한다.
  • stopped/hidden : Activity가 다른 Activity에 완전히 가려진 상태이다.
  • destroyed : 시스템이나 사용자에 의해 Activity가 완전히 종료된 상태이다. 다른 세 개의 상태는 Activity의 정보를 갖고 있으나, destroyed 된 Activity는 Activity의 모든 정보를 다시 불러와야 한다.

Activity Lifecycle

어플리케이션이 실행되면 어떤 Activity가 실행되고, Activity가 보여주는 layout을 화면에 띄우게 된다. 그리고 다른 Activity가 실행되면 화면이 전환되며 원래의 Activity는 보이지 않게 되고, 어플리케이션을 종료하면 앱의 모든 Activity가 종료된다.

이렇듯 각각의 Activity는 바로 위 파트에서 본 Activity의 상태가 존재하고, 이상태를 변화하기 위해 몇 개의 함수를 갖는다. Activity가 시작될 때부터 끝날 때까지 상태들을 Activity의 Life cycle(수명 주기)로 표현하고, Fig6과 같이 나타낼 수 있다.

Fig6. 핵심적인 Activity 생명주기
  • onCreate() : activity가 생성될 때 가장 먼저 호출된다. 반드시 부모 클래스의 onCreate() 함수를 호출해야 한다. Bundle 객체를 인자로 받는다. 본 포스트에서 Bundle에 대해 다루진 않는다.
  • onRestart() : activity가 stopped 상태일 때, 사용자가 activity를 다시 실행하면 호출된다. 반드시 부모 클래스의 onRestart() 함수를 호출해야 한다.
  • onStart() : activity가 visible한 상태로 들어가기 시작할 때 호출된다. 그러나 제일 처음 액티비티를 시작할 때 이 함수를 지난 직후에 안 보이는데, 이는 Activity 마다 갖고 있는 Window가 앱의 Window들을 관리하는 WindowManager에 추가되지 않았기 때문이다. 본 포스트에서 Window에 대해 다루진 않는다. 반드시 부모 클래스의 onStart() 함수를 호출해야 한다.
  • onResume() : 사용자와 상호작용하기 위해 호출되는 함수다. onStart() 함수에서와의 같은 이유로 onResume() 함수가 지나도 디자인한 레이아웃이 보이지 않을 수 있다. View의 디자인에 관한 변동사항을 적용하려면 onWindowFocusChanged() 함수에 해주는 것이 확실한 방법이다. 실질적으로 상호작용이 가능한 것도 Window가 Focus를 얻고난 후이다. 반드시 부모 클래스의 onResume() 함수를 호출해야 한다.
  • onPause() : activity가 foreground 상태에서 벗어나거나, focus를 잃었을 때 호출된다. 사용자에게 보이는 상태이기 때문에 UI를 신경써주는 것이 좋다. 반드시 부모 클래스의 onPause() 함수를 호출해야 한다.
  • onStop() : activity가 사용자에게 더이상 보이지 않을 때 호출된다. 새로운 activity가 실행되어 running 상태가 되거나, 존재하던 activity가 running 상태가 되거나, 본 activity가 destroyed 되기 전에 이런 경우가 발생한다. animation을 멈출 때, UI를 새롭게 할 때 등의 경우에 사용되기도 한다. 반드시 부모클래스의 onStop() 함수를 호출해야 한다.
  • onDestroy() : activity가 destroy되기 전 호출되는 마지막 함수이다. activity를 종료하거나, 시스템이 메모리가 부족할 때 강제로 종료하면 호출된다. 반드시 부모 클래스의 onDestroy() 함수를 호출해야 한다.

생성된 Activity 코드 살펴보기

Fig7. Activity를 만든 후 생성된 클래스 파일의 코드(.kt)

Fig7Fig1처럼 android studio에서 Activity를 생성했을 때 생성되는 파일이다. 익숙하지 않은 부분이 몇 개 보인다. 이 부분을 좀 더 다뤄보자. onCreate() 함수는 포스트 상단 Activity lifecycle 파트에서 다뤘기 때문에 이 파트에선 다루지 않는다.

AppCompatActivity

포스트 상단에서 봤듯이, Activity를 만드는 데는 Activity를 상속받는 class파일이 필요하다. 즉 AppCompatActivity는 Activity를 상속받는다는 뜻이다. 그런데 왜 Activity가 아닌 이름도 길고 어려워 보이는 AppCompatActivity를 상속 받은 것일까?

안드로이드는 현재도 지속해서 새로운 기능과 새로운 경험을 제공하기 위해 플랫폼을 업데이트한다. 만약 더 오래된 버전에서 개발을 진행했다면, 더 오래된 플랫폼을 사용하는 사용자는 새로운 버전의 기능을 사용할 수 없을까? 이런 문제를 해결해줄 수 있는 것이 support library(지원 라이브러리)이다. AppCompatActivity 역시 androidx라는 지원 라이브러리에 속하고, 코드로 버전 확인을 하지 않아도 하위 플랫폼과의 호환을 지원해준다.

Bundle

onCreate() 함수는 Activity가 생성될 때 처음 거치는 함수이다. Activity를 종료하지 않았다면, Activity도 다시 생성되지 않기 때문에 onCreate()함수는 호출되지 않는다. 그러나 만약 시스템에 의해 강제 종료되거나, 화면을 회전한 경우 Activity가 종료된다. 이 때 Activity가 갖고 있던 정보를 잃어버릴 수 있는데, Bundle객체가 이 정보들을 Activity가 꺼지기 전에 보관해줄 수 있다. Activity를 맨 처음 시작하면 savedInstanceState는 null 값임을 볼 수 있다.

setContentView()

setContentView() 함수는 함수 이름을 봤을 때 화면의 내용을 정하는 것이라고 유추할 수 있다. 그러나 유의할 점은, 이 함수가 화면을 그리지는 않는다는 것이다. setContentView()는 인자로 받은 Layout을 객체화하여 메모리에 올리는 역할을 하는데, 이를 ‘inflate한다.’ 라고도 표현한다.

Reference

Overall part

1. [Android developers] “Activity” — https://developer.android.com/reference/android/app/Activity?hl=ko

Activity가 추가되는 과정 part

2. [안드로이드 Q&A] “manifest에 activity 추가 관련” — https://www.masterqna.com/android/54932/manifest%EC%97%90-activity-%EC%B6%94%EA%B0%80-%EA%B4%80%EB%A0%A8

Activity Lifecycle part

3. [wisecow] “ <안드로이드 Activity 클래스> 개념 정리” — https://mattlee.tistory.com/73

4. [hmg trunk] “안드로이드 ACTIVITY란 무엇인가” — https://hmgirl.tistory.com/216

5. [akquinet] “ANDROID ACTIVITIES — THE PREDOMINANCE OF THE UI THREAD” — https://blog.akquinet.de/2010/02/17/android-activities-the-predominance-of-the-ui-thread/

6. [Lazysoul] “Android Activity Life Cycle” — https://medium.com/@lazysoul/android-activity-life-cycle-58a02b7ebc4c

생성된 Activity 코드 살펴보기 part

7. [Programming Source] “Bundle(번들)이란?” — https://programmingsource.tistory.com/34

--

--

dEpayse
dEpayse_publication

나뿐만 아니라 다른 사람들도 이해할 수 있도록 작성하는, 친절한 블로그를 목표로.