본문 바로가기
안드로이드

[안드로이드] Activity와 Fragment

by krapoi 2022. 6. 7.
반응형

Activity

개요

안드로이드 앱이 실행이 되면 화면이 등장하고 UI가 화면 위에 나타난다. 버튼을 터치하거나 스크롤 등 여러 가지 활동이 가능하다.

이러한 전반적인 활동을 담당하는 구성요소이다. 또한 안드로이드의 4대 구성요소 중 하나이기도 하다.

main() 메서드를 사용하여 앱을 실행하는 일반적인 프로그래밍 패러다임과는 달리 수명 주기의 특정 단계에 해당하는 특정 콜백 메서드(ex : onCreate)를 호출하여 Activity의 인스턴스 코드를 시작한다.

개념

모바일 앱 환경은 사용자와 앱의 상호작용이 항상 동일한 위치에서 시작되는 것이아니다 (데스크톱 앱 환경과의 차이점).

 

사용자는 흔히 비결정론적으로 시작시킨다.

이게 무슨소리인지 모르겠다면, 인스타그램으로 예를 들어보자.

 

우리가 홈화면에서 인스타그램을 켜면 그냥 인스타그램 메인 화면이 뜰 것이다.

하지만 유튜브영상 같은 것을 공유하기를 눌러 인스타그램을 켠다면 글쓰기 화면으로 가질 것이다.

이렇게 앱은 켜지면 무조건 동일한 위치인 메인에서 시작하는 것이 아니라 상황에 따라 맞는 Activity에서 켜지게 된다.

 

그래서 안드로이드의 Activity 클래스는 이 패러다임을 촉진하도록 설계되어있다.

한 앱이 다른 앱을 호출할 때, 호출 앱은 다른 앱 전체를 호출하는 것이 아니라 다른 앱의 Activity를 호출한다.

이러한 방식으로 Activity은 앱과 사용자의 상호작용을 위한 진입점 역할을 한다.

Activity는 Activity 클래스의 서브클래스로 구현된다.

 

또한 Activity는 앱이 UI를 그리는 창을 제공한다. 이 창은 일반적으로는 화면을 다 채우지만 작을 수 도있고, 다른 창 위에 떠 있을 수 도 있다. 일반적으로는 한 Activity는 앱에서 하나의 화면을 구현한다.

 

대부분의 앱에는 여러 화면이 포함되어 있다. 즉, 대부분의 앱은 여러 Activity로 구성이 된다.

일반적으로 앱에서 하나의 Activity가 기본 Activity로 지정되며 이 기본 Activity는 사용자가 앱을 실핼할 때 표시되는 첫 번쨰 화면을 뜻한다. 그리고 각 Activity는 다양한 Activity들을 실행하기 위해 또 다른 Activity를 시작할 수 있다.

 

예를 들어주자면, 우리가 사용하는 대부분의 앱들은 기본 Activity로 로그인화면을 제공할 것이다. 그리고 로그인 화면에서는 아이디/비밀번호 찾기, 회원가입 같은 작업을 위한 화면을 제공하는 다른 Activity들을 실행할 수 있을 것이다.

 

이러한 Activity는 앱에 일관된 사용자 환경을 형성하기 위해 함께 작동하지만, 각 Activity들은 다른 Activity에 최소한의 종속성만 가진다. 쉽게 설명하자면 한 Activity는 다른 Activity내에 있는 메소드를 직접 호출할 수 없고 데이터도 직접 액세스 할 수 없다는 뜻이다.

그래도 intent나 Content Provider를 사용하면 액티비티를 공유할 수는 있으니 걱정하지 말자.

 

앱의 Activity를 사용하려면 앱의 manifest에 Activity 관련 정보를 등록하고 수명주기를 적절히 관리해야 한다.

Activity 수명 주기

Activity는 수명 주기 전체 기간에 걸쳐 여러 상태를 거친다. 상태 간 전환을 처리하는데 일련의 콜백을 사용할 수 있다. 그러한 콜백 함수를 알아보자.

onCreate()

시스템이 Activity를 생성할 때 실행되는 이 콜백은 반드시 구현해야 한다.

그 이유가 이 콜백에서 setContentView()를 호출해 Activity의 UI를 위한 레이아웃을 정의해야 하기 때문이다. (안 하면 화면 안 나옴)

또한 Activity의 전체 수명 주기 동안 한 번만 발생해야 하는 기본 애플리케이션 시작 로직을 실행하며 구현 시 Activity에 필수 구성요소를 초기화한다.

예를 들어, data를 list에 바인딩하고, Activity를 ViewModel과 연결하고, 일부 클래스 범위 변수를 인스턴스 화할 수도 있다.

이 메서드는 savedInstanceState매개변수를 수신하는데, 이는 활동의 이전 저장 상태가 포함된 Bundle 객체이다. 이번에 처음 생성된 활동인 경우 Bundle 객체의 값은 null이다.

onCreate()가 완료되면 다음 콜백은 항상 onStart()이다.

onStart()

onCreate()가 종료되면 Activity는 ‘onStart’ 상태로 전환되고 Activity가 사용자에게 표시된다. 이 콜백에는 Activity가 백그라운드가 아닌 포그라운드로 나와 사용자와 상호작용을 준비하는 작업이 포함된다.

이 콜백이 완료되면 Activity가 onResume() 상태에 들어가고, 시스템이 onResume() 메서드를 호출한다.

onResume()

Activity가 사용자와 상호작용을 시작하기 직전에 시스템은 이 콜백을 호출한다. 이 시점에서 Activity는 Activity stack 맨 위에 있으며 모든 사용자의 입력을 캡처한다. 앱의 핵심 기능은 대부분 onResume() 메서드로 구현된다.

onPause() 콜백은 항상 onResume() 뒤에 온다.

onPause()

Activity가 포커스를 잃고 ‘onPause’ 상태로 전환될 때 시스템은 onPause()를 호출한다. 이 상태는 대표적으로 뒤로가기 버튼을 탭할 때 발생한다.

 

시스템이 활동에서 onPause() 를 호출할 때 이는 자세히 말하면 Activity가 여전히 부분적으로 표시되지만 대체로 사용자가 Activity를 떠나고 있으며 활동이 조만간 ‘onStop’ 또는 ‘onResume’ 상태로 전환됨을 나타낸다.

즉, 활동이 포그라운드에 있지 않게 되었다는 것을 나타낸다.

 

사용자가 UI 업데이트를 기다리고 있다면 ‘onPause’ 상태의 활동은 계속 UI를 업데이트할 수 있다. 예를 들면 내비게이션에서 내 위치가 지속적으로 옮겨지는 것.

 

애플리케이션 또는 사용자의 데이터를 저장하거나, 네트워크를 호출하거나, 데이터베이스 트랜잭션을 실행할 때 onPause()를 사용하면 절대 안 된다.

 

이유는 이러한 작업은 메서드 실행이 끝나기 전에 완료되지 못할 수도 있기 때문이다.

그 대신, 부하가 큰 종료 작업은 onStop()일 때 실행하는 것이 좋다.

 

onPause()가 실행을 완료하면 다음 콜백은 활동이 ‘onPause’ 상태로 전환된 후 발생하는 상황에 따라 onStop() 또는 onResume()이 된다.

onStop()

Activity가 사용자에게 더 이상 표시되지 않는다면 onPause 상태에 들어가고, 시스템은 onStop() 콜백을 호출한다.

예를 들어 새로 시작된 Activity가 화면 전체를 차지하는 경우에 적용된다. 또는 시스템이 Activity의 실행이 완료되어 종료될 시점에 호출할 수도 있다.

 

이 메서드에서는 앱이 사용자에게 보이지 않은 동안 필요하지 않는 리소스를 해제하거나 조정한다. 예를 들면 애니메이션을 일시 중지하는 것이 있다.

 

onPause() 대신 onStop()을 사용하면 사용자가 멀티 윈도 모드에서 활동을 보고 있더라도 UI 관련 작업이 계속 진행된다.

또한 onStop()을 사용하여 CPU를 비교적 많이 소모하는 종료 작업을 실행해야 한다.

예를 들어 정보를 데이터베이스에 저장할 적절한 시기를 찾지 못했다면 onStop() 상태일 때 저장할 수 있다.

onDestroy()

이 메서드는 Activity가 소멸되기 전에 호출된다. 시스템은 다음 중 하나에 해당할 때 이 콜백을 호출한다.

  • 사용자가 Activity를 완전히 닫거나 Activity에서 finish()가 호출되어 활동이 종료되는 경우
  • 구성 변경(예 : 기기 회전, 멀티 윈도 모드)으로 인해 시스템이 일시적으로 Activity를 소멸시키는 경우

활동이 종료되는 경우 onDestroy()는 활동이 수신하는 마지막 수명 주기 콜백이 된다.

또는 구성 변경으로 인해 onDestroy()가 호출되는 경우 시스템이 즉시 새 Activity를 인스턴스를 생성한 다음, 새로운 구성에서 그 새로운 인스턴스에 관해 onCreate()를 호출한다.

onDestroy() 콜백은 이전의 콜백에서 아직 해제되지 않은 모든 리소스(예: onStop() )를 해제해야 한다.

Fragment

등장 배경

다양한 크기의 화면을 가지는 단말기가 늘어남에 따라 한 화면에 여러 개의 화면 요소를 원하는 수요가 늘어가고 있다.

대표적으로 화면의 크기가 큰 태블릿 PC와 같이 화면의 크기가 큼에 따라 복잡한 레이아웃 구성과 뷰 위젯 배치들로 인해 기존의 Activity를 통한 레이아웃 구성만으로는 구현하기 버거운 면이 있었다. 이를 커버하기 위해 나온 것이다. (안드로이드 3.0 버전에 나옴)

개념

Fragment는 앱 UI의 재사용 가능한 부분을 나타낸다. Fragment는 자체 레이아웃을 정의 및 관리하고 자체 수명주기를 보유하며, 자체 입력 이벤트를 처리할 수 있다.

 

Fragment는 독립적으로 존재할 수 없고 Activity나 다른 Fragment에서 호스팅 되어야 한다. 즉, Fragment는 하나의 Activity나 Fragment에 연결되어야 한다는 뜻. ( 근데 Fragment에 연결해 봤자 그 연결한 Fragment고 Activity에 연결해야 한다. 그래서 그냥 반드시 하나의 Activity에 연결해야 하는 것과 같음)

Fragment의 뷰 계층 구조는 호스트 뷰 계층 구조의 일부가 되거나 여기에 연결된다.

특징

  • 액티비티를 분할하여 화면의 한 부분을 정의한다.
  • 액티비티와 같이 레이아웃, 동작 처리, 생명주기를 가지는 독립적인 모듈이다.
  • 다른 액티비티에서도 사용할 수 있어 재사용성이 뛰어나다.
  • 액티비티 내에서 실행 중에 추가, 제거가 가능하다.

Fragment 수명 주기

onAttach()

Fragment가 처음으로 Activity에 부착될 때 호출됨, 가장 먼저 어떤 액티비티에 부착될지 결정함. 또한 매게 변수로 Activity를 받기 때문에 여러 Activity에서 재사용이 가능함.

onCreate()

이 콜백 함수에서는 Fragment에 필요한 요소들을 먼저 초기화할 수 있다.

Activity와 달리 미리 초기화해둘 요소들이 없다면 무시해도 상관없다.

 

이 콜백 함수에서 주의할 점은 이 수명주기 단계에서 Activity도 onCreate()이기 때문에 Activity에 있는 컨트롤들을 참조하거나 Fragment의 요소를 초기화할 때 불안정하게 된다.

 

매개변수로는 savedInstanceState를 받는데 Fragment가 재생성된 이전에 상태를 저장하고 있는 변수로써, 이 값을 참조해 이전 내용을 복구한다.

onCreateView()

이 콜백 함수에서는 Fragment에 쓰일 view들을 정의하고 초기화하게 된다.

 

이때, 프래그먼트는 자신의 레이아웃을 루트 뷰로 설정하고 이를 inflate 하게 된다. container를 통해 Fragment가 어느 위치에 자리 잡아야 할지 전달받는다. 마지막으로 Fragment상에 생성된 뷰들을 종속된 액티비티 뷰(container)에 리턴해줘 화면에 표시한다.

onActivityCreated()

onCreate 함수의 역할과 같이 프래그먼트의 구성요소들을 초기화하는 시점이다. 차이점이 있다면 Activity가 완전히 생성된 이후의 시점이기 때문에 Activity의 컨트롤들에 접근하거나 Fragment의 구성요소들을 초기화할 때 안정성을 보장받게 된다.

onPause()

Fragment가 정지되는 시점을 정의한다. Activity와 같이 이 부분에서 반드시 Fragment가 소멸하지 않는다. 또한 다시 해당 Fragment로 돌아온다는 보장도 없기 때문에 이 시점에서 남겨두어야 하거나 영구적으로 보존해야 할 데이터들을 저장하게 된다.

onDetach()

말 그대로 Fragment가 Activity와 연결이 끊어질 때 호출되는 함수이다.

 

나머지 콜백 함수들은 Activity와 거의 같기 때문에 따로 설명하지는 않겠다.

반응형