Activity란 무엇인가

5 minute read

Android developers 홈페이지를 참고하여 작성했습니다.

Activity란

Activity 클래스는 안드로이드 애플리케이션 모델의 기본 요소이다. main() 메소드를 사용해 앱을 실행하는 프로그래밍 패러다임과 달리 Android 시스템은 수명 주기의 특정 단계에 해당하는 콜백 메소드를 호출하여 Activity 인스턴스의 코드를 시작한다.

따라서 Activity는 앱과 사용자의 상호작용을 위한 진입점 역할을 한다고 볼 수 있고 Activity 클래스의 서브 클래스로 구현된다.

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

Manifest 구성

해당 파일에 Activity 및 관련 특정 속성을 선언해야 앱에서 Activity를 사용할 수 있다.

다음과 같이 manifest 파일을 열고 요소를 요소의 하위 요소로 추가해야 한다.

<manifest ...>
	<application ...>
		<activity android:name=".OOOActivity" />
		...
	</application ...>
	...
</manifest>

다음으로 intent-filter가 있다. manifest 파일에서 다음과 같이 사용한다

<activity android.name=".OOOActivity">
	<intent-filter>
		<action android:name="android.intent.action.SEND" />
		<category android:name="android.intent.category.DEFAULT" />
		<data android:mimeType="text/plain" />
	</intent-filter>
</activity>

인텐트 필터는 다음의 activity를 실행하는 기능을 제공한다 .

  • “OOO 이메일 앱을 통해 이메일 activity를 시작” 하도록 시스템에 지시한다.
  • “이메일 작업을 할 수 있는 activity로 이메일 보내기 화면을 시작” 하도록 시스템에 지시한다.

시스템 UI에서 사용자에게 작업을 실행할 때 어떤 앱을 사용할지 묻는 메시지가 나왔다면 인텐트 필터가 작동한 것이다.

Activity 활동 주기

앱을 사용하다보면 다음과 같이 여러 가지 상황이 있을 수 있다.

앱을 사용하던 중 전화가 걸려온 경우.

사용자가 앱에서 나갔다가 다시 돌아왔을 때, 사용자의 진행 상태를 저장해야 하는 경우.

화면이 가로 또는 세로로 회전하면서 비정상 종료되거나, 진행상태가 저장되지 않는 경우.

위와 같이 사용자가 앱을 사용하는 중이나, 앱을 나가거나, 앱으로 다시 돌아갈 경우 앱의 Activity 인스턴스는 수명 주기 안에서 여러 다른 상태를 통해 전환된다.

Activity의 수명 주기를 표현하면 위와 같다. 그리고 상태 간 전환을 처리하는데 다음의 콜백을 사용한다.

  • onCreate()
  • onStart()
  • onResume()
  • onPause()
  • onStop()
  • onRestart()
  • onDestroy()

사용자가 activity를 벗어나면 시스템은 activity를 해체할 메소드를 호출한다. 예를 들면 사용자가 다른 앱으로 전환하는 경우가 그렇다.

activity는 계속 메모리 안에 남아 있고 foreground로 다시 돌아올 수 있기도 하다.

시스템은 그 시점의 activity state에 따라 특정 프로세스와 그 안의 activity를 같이 종료할지를 결정한다.

activity의 복잡도에 따라 모든 수명 주기 메소드를 구현할 필요가 없는 경우도 있다. 하지만 각 수명 주기 메소드를 이해해서 사용자가 예상한 대로 앱이 실행되게끔 구현하는 것이 중요하다.

수명 주기 Callback

onCreate()

override fun onCreate(savedInstanceState: Bundle?) {
	super.onCreate(savedInstanceState)
	setContentView(R.layout.activity_main)	
}

onCreate() 콜백은 시스템이 activity를 생성할 때 실행되는 것으로 필수 구현해야 한다. onCreate() 메소드에서 activity의 전체 수명 주기 동안 한 번만 발생해야 하는 기본 애플리케이션 시작 로직을 실행한다.

onCreate() 메소드를 구현하면 데이터를 목록에 바인딩하고, activity를 ViewModel과 연결하고, 일부 클래스 범위 변수를 인스턴스화 할 수 있다.

이 메소드는 activity의 이전 저장 상태가 포함된 Bundle 객체인 savedInstanceState 매개변수를 수신한다. 만약 처음 생성된 activity는 Bundle객체의 값은 null이 된다.

XML 레이아웃 파일의 리소스 ID인 R.layout.activity_mainsetContentView()에 전달하여 지정한다.

onCreate()메소드가 실행을 완료하면 시스템은 연달아 onStart(), onResume() 메소드를 호출한다.

생명 주기 인식 구성요소가 있다면 그 구성요소는 ON_CREATE 이벤트를 수신한다.

onStart()

onStart()가 호출되면 activity가 사용자에게 표시되고, 앱은 activity를 foreground로 보낼 준비를 한다. 예를 들면 이 메소드에서는 앱이 UI를 관리하는 코드를 초기화한다.

onStart() 메소드는 매우 빠르게 완료되고, 시스템은 onResume() 메소드를 호출한다.

생명 주기 인식 구성요소가 있다면 그 구성 요소는 ON_START 이벤트를 수신한다.

onResume()

onStart() 메소드가 끝난 state에서는 foreground에 activity가 표시되고 시스템이 onResume() 콜백을 호출한다. 이 상태에 들어갔을 때 앱은 사용자와 상호작용한다.

생명 주기 인식 구성요소가 있다면 그 구성 요소는 ON_RESUME 이벤트를 수신한다.

방해되는 이벤트가 발생하면 시스템은 onPause() 콜백을 호출한다. 그리고 activity의 state는 일시중지됨 상태가 된다.

activity가 일시중지됨 state에서 재개됨 state로 돌아오면 시스템이 다시 onResume() 메소드를 다시 호출한다.

따라서 onResume()을 구현해서 onPause() 중에 해제하는 구성요소를 초기화하고, activity가 재개됨 state로 전환될 때마다 필요한 초기화 작업을 수행해야 한다.

onPause()

시스템은 사용자가 activity를 떠날 때 첫 신호로 이 메소드를 호출한다. 이 때 activity가 항상 소멸되는 것은 아니다.

activity가 이 상태에 들어가는 이유들은 여러가지가 있는데 예를 들면 아래와 같다.

  • 일부 이벤트가 앱 실행을 방해하는 경우(가장 일반적인 사례)
  • Android 7.0(API 수준 24) 이상에서는 멀티 윈도우 모드로 실행된다. 그 중 하나의 앱만 포커스를 가지기 때문에 시스템이 나머지 모든 앱을 일시 중지 시킨다.
  • 대화 상자 등의 새로운 반투명 activity가 열리는 경우 activity가 여전히 부분적으로 보이지만 포커스 상태가 아닌 경우 일시중지됨 상태로 유지된다.

activity가 이 state로 전환되면 생명 주기 인식 구성 요소는 ON_PAUSE 이벤트를 수신한다.

onPause() 메소드를 이용하면 시스템 리소스나, GPS와 같은 센서 핸들 등을 사용자가 사용하지 않을 때배터리 수명에 영향을 미칠 수 있는 모든 리소스를 해제할 수도 있다.

하지만 멀티 윈도우 사용상황을 대비해서 UI 관련 리소스와 작업을 완전히 해제하는 것은 onPause() 대신 onStop()을 사용하는 것이 좋다.

onPause()는 아주 잠깐 실행되기 때문에 사용자 데이터를 저장하거나, 네트워크 호출, 데이터 베이스 트랜잭션 등 저장 작업을 실행하면 안 된다

onPause() 메소드의 실행이 완료되어도 state가 일시중지됨 상태로 남아있을 수 있다. activity가 다시 시작되거나 완전히 보이지 않을 때까지 이 상태에 머무른다. activity가 다시 시작되면 시스템은 onResume() 콜백을 호출하고 activity가 완전히 보이지 않게 되면 시스템은 onStop() 을 호출한다.

onStop()

activity가 사용자에게 더 이상 표시되지 않을 경우 중단됨 상태에 들어가고, 시스템은 onStop() 콜백을 호출한다.

즉 새로 시작된 activity가 화면 전체를 차지한 경우이다. 시스템은 activity의 실행이 완료 후 종료될 시점에 onStop()을 호출할 수도 있다.

activity가 중단됨 상태로 전환되면 수명 주기 인식 구성요소는 ON_STOP 이벤트를 수신한다.

onStop() 메소드는 앱이 사용자에게 보이지 않는 동안 필요하지 않은 리소스를 해제하거나 조정해야 한다.

또한 CPU를 많이 소모하는 종료 작업도 실행해야 한다. 예를 들면 데이터 베이스에 저장할 적절한 시기를 찾지 못한 경우 onStop() 상태일 때 저장할 수 있다.

activity가 정지됨 상태에서 activity가 다시 시작되면 시스템은 onRestart()를 호출하고 실행을 종료하면 시스템은 onDestroy()를 호출한다.

onDestroy()

onDestroy()는 activity가 소멸되기 전에 호출되며 시스템은 다음 중 하나에 해당하는 경우 이 콜백을 호출한다.

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

activity가 소멸됨 상태로 전환되면 수명 주기 인식 구성요소는 ON_DESTROY 이벤트를 수신한다.

activity가 종료되는 경우 onDestroy()는 activity가 수신하는 마지막 수명 주기 콜백이 되고, 구성 변경으로 인해 onDestroy()가 호출되는 경우 시스템이 즉시 새 활동 인스턴스를 생성한 다음, 새로운 구성에서 그 인스턴스에 관해 onCreate()를 호출한다.

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

Activity 간 이동

다른 Activity에서 Activity를 시작하기

activity는 특정 시점에서 다른 activity를 시작해야 하는 경우가 많다.

activity가 새로 시작하려는 activity에서 결과를 받기 원하는지 여부에 따라 startActivity()startActivityForResult() 메소드 중 하나를 사용해 새 activity를 시작한다. 두 가지 모두 Intent 객체를 전달한다.

Intent 객체는 시작하고자 하는 activity를 정확히 나타내거나 실행하고자 하는 작업의 유형을 설명한다. 그리고 시작된 activity에서 사용할 소량의 데이터를 포함할 수도 있다.

startActivity()

새로 시작된 activity가 결과를 반환할 필요가 없을 경우 startActivity() 메소드를 호출한다.

아래는 기본적인 startActivity() 메소드를 사용한 코드이다.

val intent = Intent(this, SignInActivity::class.java)
startActivity(intent)

Intent를 조금 사용하여 다른 몇 가지 작업을 수행하게 할 수 있다. 아래 코드는 이메일 메시지를 보낼 수 있게 인텐트를 생성한 코드이다.

val intent = Intent(Intent.ACTION_SEND).apply {
	putExtra(Intent.EXTRA_MAIL, recipientArray)
}
startActivity(intent)

이 때 EXTRA_EMAIL은 이메일이 전송될 이메일 주소의 문자열 배열이다. 이메일 앱이 이 인텐트에 응답한 경우 애플리케이션은 제공된 문자열 배열을 읽어 이메일 작성 양식의 ‘수신’ 필드에 배치한다.

startActivityForResult()

activity가 종료될 때 결과를 반환받을 때 사용한다.

예를 들어 사용자가 연락처 목록에서 어떤 사람을 선택해서 받아오는 activity를 시작하는 경우 activity가 종료되면 선택한 사람을 반환해야 한다.

이 경우 startActivityForResult(Intent, int) 메소드를 호출해야 한다. 여기서는 정수 매개 변수가 호출을 식별한다. 이 식별자는 동일 activity에서 여러 개의 startActivityForResult(Intent, int) 호출도 명확하게 구분한다. 이는 글로벌 식별자가 아니어서 다른 앱이나 activity와 충돌할 위험이 없고 결과는 onActivityResult(int, int, Intent) 메소드로 반환된다.

하위 activity는 setResult(int)를 호출해서 상위 activity로 데이터를 반환하고 그 결과 코드는 다음과 같다.

  • 비정상 종료 등으로 하위 활동이 실행되지 않은 경우 RESULT_CANCELED
  • 하위 활동이 실행된 경우RESULT_OK
  • 임의의 맞춤 값RESULT_FIRST_USER

즉 정리하면 startActivityForResult()를 실행하면 하위 activity가 실행되고 하위 activity가 종료할 때 setResult()가 실행한다. 그리고 상위 activity로 돌아오면서 onActivityResult()에 결과값을 전달한다.