본문 바로가기

Java dev/android

안드로이드 Activity란 무엇인가

원문 : https://developer.android.com/guide/components/activities.html


1. Activity란?

사용자에게 UI가 있는 화면을 제공하는 앱 컴포넌트입니다. 

다시 말해서, 폰 다이얼러 화면, 카메라 촬영 화면, 이메일 쓰기 화면, 지도 보기 화면 등과 같이 사용자들이 뭔가 하기 위해 상호작용을 할 수 있는 화면을 제공한다는 것입니다. 각 액티비티는 하나의 윈도우에 UI를 그리며, 그 윈도우가 보통은 화면을 꽉 채우지만, 화면보다 작을수도 있고, 다른 윈도우의 위에 떠 있을 수도 있습니다.

앱은 보통 여러개의 액티비티로 이루어져 있고, 각 액티비티는 서로 느슨한 관계를 갖습니다. 일반적으로, 앱은 하나의 메인(main) 액티비티를 갖고, 그것은 사용자가 앱을 처음 실행했을때 보여지는 액티비티입니다. 각 액티비티는 다른 액티비티를 실행할 수 있습니다. 다른 액티비티가 실행되면 이전의 액티비티는 정지되지만(stopped), 시스템이 "백스택"이라 불리는 스택에 저장해뒀기 때문에 없어지지는 않습니다. 다시 말해서, 시스템은 새로운 액티비티를 시작하면 백스택에 담고 나서 사용자에게 보여줍니다. 백스택은 "후입선출"의 스택 메커니즘을 따르며, 사용자가 뒤로버튼을 누를 경우, 스택의 최상위(top)에 있는 현재 액티비티를 제거(pop and destroy)하고 이전의 액티비티를 시작합니다. 백스택에 대한 더 자세한 내용은 태스크와 백스택에서 학습하실 수 있습니다.

새로운 액티비티가 실행되면서 현재 액티비티가 정지하게 되면, 시스템은 생명주기의 콜백 메소드를 호출함으로써 액티비티의 상태가 변경되었음을 알려줍니다. 이러한 콜백 메소드들은 시스템이 액티비티를 생성하고, 보여주고, 멈추고, 제거하는 등의 상황에 호출되며, 적절히 오버라이드(override)함으로써 각각의 상황에 맞는 동작을 구현할 수 있습니다. 예를 들어, 액티비티는 정지되었을 때 네트웍이나 데이터베이스 관련 객체와 같이 덩치가 큰 객채들을 해제하는 것이 좋고, 액티비티가 다시 화면에 보여질 때 필요한 리소스들을 다시 가져와서 중지되었던 작업들을 다시 실행할 수 있습니다. 이렇게 액티비티가 생성되고 보여지고 멈추고 제거되고 하는 등의 상태변화는 모두 액티비티 생명주기의 일부입니다. 


2. Activity생성

액티비티를 생성하려면 Activity의 하위 클래스(또는 이의 기존 하위 클래스)를 생성해야 합니다. 하위 클래스에서는 액티비티 생성, 중단, 재개, 소멸 시기 등과 같은 수명 주기의 다양한 상태 간 액티비티가 전환될 때 시스템이 호출하는 콜백 메서드를 구현해야 합니다. 가장 중요한 두 가지 콜백 메서드는 다음과 같습니다.


onCreate()

이 메서드는 반드시 구현해야 합니다. 시스템은 액티비티를 생성할 때 이것을 호출합니다. 구현하는 중에 액티비티의 필수 구성 요소를 초기화해야 합니다. 무엇보다도 중요한 점은, 바로 여기서 setContentView()를 호출해야 액티비티의 사용자 인터페이스 레이아웃을 정의할 수 있다는 점입니다.


onPause()

시스템이 이 메서드를 호출하는 것은 사용자가 액티비티를 떠난다는 첫 번째 신호입니다(다만 이것이 항상 액티비티가 소멸 중이라는 뜻은 아닙니다). 현재 사용자 세션을 넘어서 지속되어야 하는 변경 사항을 커밋하려면 보통 이곳에서 해아 합니다(사용자가 돌아오지 않을 수 있기 때문입니다).

여러 액티비티 사이에서 원활한 사용자 경험을 제공하고, 액티비티 중단이나 심지어 소멸을 초래할 수도 있는 예상치 못한 간섭을 처리하기 위해 사용해야 하는 다른 수명 주기 콜백 메서드도 여러 가지 있습니다. 모든 수명 주기 콜백 메서드는 나중에 액티비티 수명 주기 관리 섹션에서 자세히 논의할 것입니다.


인텐트 필터 사용하기

요소 또한 여러 가지 인텐트 필터를 지정할 수 있습니다. 다른 애플리케이션 구성 요소가 이를 활성화하는 방법을 선언하기 위해 intent-filter를 사용하는 것입니다.

Android SDK 도구를 사용하여 새 애플리케이션을 생성하는 경우, 개발자를 위해 생성되어 있는 스텁 액티비티에 자동으로 인텐트 필터가 포함되어 있어 "주요" 동작에 응답하는 액티비티를 선언하며, 이는 "시작 관리자" 범주에 배치해야 합니다. 인텐트 필터는 다음과 같은 형태를 띱니다.


<activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">

    <intent-filter>

        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />

    </intent-filter>

</activity>


action 요소는 이것이 애플리케이션으로 가는 "주요" 진입 지점이라는 것을 나타냅니다. category 요소는 이 액티비티가 시스템의 애플리케이션 시작 관리자에 목록으로 나열되어야 한다는 것을 나타냅니다(사용자가 이 액티비티를 시작할 수 있도록 해줌).

애플리케이션이 자체 포함 방식이기를 원하고 다른 애플리케이션이 이 애플리케이션의 액티비티를 활성화하도록 허용하지 않고자 하면, 달리 인텐트 필터가 더 필요하지 않습니다. "주요" 동작과 "시작 관리자" 범주가 있는 액티비티는 하나뿐이어야 합니다(이전 예시 참조). 다른 애플리케이션에서 사용할 수 없게 하고자 하는 액티비티에는 인텐트 필터가 있으면 안 됩니다. 이러한 액티비티는 명시적인 인텐트를 사용해 직접 시작할 수 있습니다(이 내용은 다음 섹션에서 논의).

그러나, 액티비티가 다른 애플리케이션(및 본인의 애플리케이션)에서 전달된 암시적 인텐트에 응답하도록 하려면 액티비티에 추가로 인텐트 필터를 정의해야만 합니다. 응답하게 하고자 하는 각 인텐트 유형별로 action 요소를 포함하는 intent-filter를 하나씩 포함시켜야 하며, 선택 사항으로 category 요소 및/또는 data 요소를 포함시킬 수 있습니다. 이와 같은 요소는 액티비티가 응답할 수 있는 인텐트의 유형을 나타냅니다.

액티비티가 인텐트에 응답하는 방식에 관한 자세한 정보는 인텐트 및 인텐트 필터 문서를 참조하십시오.


3. 액티비티 시작하기

다른 액티비티를 시작하려면 startActivity()를 호출한 다음 이에 시작하고자 하는 액티비티를 설명하는 Intent를 전달하면 됩니다. 인텐트는 시작하고자 하는 액티비티를 정확히 나타내거나, 수행하고자 하는 작업의 유형을 설명하는 것입니다(시스템이 적절한 액티비티를 선택하며, 이는 다른 애플리케이션에서 가져온 것일 수도 있습니다). 인텐트는 소량의 데이터를 운반하여 시작된 액티비티에서 사용할 수 있습니다.

본인의 애플리케이션 안에서 작업하는 경우에는, 알려진 액티비티를 시작하기만 하면 되는 경우가 잦습니다. 이렇게 하려면 시작하고자 하는 액티비티를 명시적으로 정의하는 인텐트를 클래스 이름을 사용하여 생성하면 됩니다. 예를 들어, 다음은 한 액티비티가 SignInActivity라는 이름의 다른 액티비티를 시작하는 방법입니다.


Intent intent = new Intent(this, SignInActivity.class);
startActivity
(intent);


그러나, 애플리케이션이 다른 몇 가지 동작을 수행하고자 할 수도 있습니다. 예를 들어 이메일 보내기, 문자 메시지 보내기 또는 상태 업데이트 등을 액티비티의 데이터를 사용하여 수행하는 것입니다. 이 경우, 본인의 애플리케이션에 그러한 동작을 수행할 자체 액티비티가 없을 수도 있습니다. 따라서 기기에 있는 다른 애플리케이션이 제공하는 액티비티를 대신 활용하여 동작을 수행하도록 할 수 있습니다. 바로 이 부분에서 인텐트의 진가가 발휘됩니다. 수행하고자 하는 동작을 설명하는 인텐트를 생성하면 시스템이 적절한 액티비티를 다른 애플리케이션에서 시작하는 것입니다. 해당 인텐트를 처리할 수 있는 액티비티가 여러 개 있는 경우, 사용자가 어느 것을 사용할지 선택합니다. 예를 들어 사용자가 이메일 메시지를 보낼 수 있게 하려면, 다음과 같은 인텐트를 생성하면 됩니다.


Intent intent = new Intent(Intent.ACTION_SEND);
intent
.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity
(intent);


인텐트에 추가된 EXTRA_EMAIL 추가 사항은 이메일이 전송되어야 할 이메일 주소의 문자열 배열입니다. 이메일 애플리케이션이 이 인텐트에 응답하면, 애플리케이션은 추가 사항이 제공한 문자열 배열을 읽어낸 다음 이를 이메일 작성 양식의 "수신" 필드에 배치합니다. 이 상황에서 이메일 애플리케이션의 액티비티가 시작되고 사용자가 작업을 끝내면 본인의 액티비티가 재개되는 것입니다.



4. 결과에 대한 액티비티 시작하기

때로는 시작한 액티비티에서 결과를 받고 싶을 수도 있습니다. 그런 경우, (startActivity() 대신) startActivityForResult()를 호출해서 액티비티를 시작합니다. 그런 다음 후속 액티비티에서 결과를 받으려면, onActivityResult() 콜백 메서드를 구현합니다. 해당 후속 액티비티가 완료되면, 이것이 Intent 형식으로 결과를 onActivityResult() 메서드에 반환합니다.

예를 들어 사용자가 연락처 중에서 하나를 고를 수 있도록 하고 싶을 수 있습니다. 즉 여러분의 액티비티가 해당 연락처의 정보로 무언가 할 수 있도록 하는 것입니다. 그와 같은 인텐트를 생성하고 결과를 처리하려면 다음과 같이 하면 됩니다.


private void pickContact() {
   
// Create an intent to "pick" a contact, as defined by the content provider URI
   
Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
    startActivityForResult
(intent, PICK_CONTACT_REQUEST);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    // If the request went well (OK) and the request was PICK_CONTACT_REQUEST
   
if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) {
       
// Perform a query to the contact's content provider for the contact's name
       
Cursor cursor = getContentResolver().query(data.getData(),
       
new String[] {Contacts.DISPLAY_NAME}, null, null, null);


       
if (cursor.moveToFirst()) { // True if the cursor is not empty
           
int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
           
String name = cursor.getString(columnIndex);
           
// Do something with the selected contact's name...
       
}
   
}
}

이 예시는 액티비티 결과를 처리하기 위해 onActivityResult() 메서드에서 사용해야 할 기본 논리를 나타낸 것입니다.

첫 번째 조건은 요청이 성공적인지 확인합니다. 요청에 성공했다면 resultCode가 RESULT_OK가 됩니다. 또한, 이 결과가 응답하는 요청이 알려져 있는지도 확인합니다. 이 경우에는 requestCode가 startActivityForResult()와 함께 전송된 두 번째 매개변수와 일치합니다. 여기서부터 코드가 Intent(data 매개변수)로 반환된 데이터를 쿼리하여 액티비티 결과를 처리합니다.

그러면 ContentResolver가 콘텐츠 제공자에 대한 쿼리를 수행하고, 콘텐츠 제공자는 쿼리된 데이터를 읽을 수 있게 허용하는 Cursor를 반환합니다. 

자세한 내용은 콘텐츠 제공자 문서를 참조하십시오.

인텐트 사용에 관한 자세한 정보는 인텐트 및 인텐트 필터문서를 참조하십시오.


5. 액티비티 종료하기

액티비티를 종료하려면 해당 액티비티의 finish() 메서드를 호출하면 됩니다. 

finishActivity()를 호출하여 이전에 시작한 별도의 액티비티를 종료할 수도 있습니다.


참고: 대부분의 경우, 이와 같은 메서드를 사용하여 액티비티를 명시적으로 종료해서는 안 됩니다. 다음 섹션에서 액티비티 수명 주기에 관해 논의한 바와 같이, Android 시스템이 액티비티의 수명을 대신 관리해주므로 직접 액티비티를 종료하지 않아도 됩니다. 이와 같은 메서드를 호출하면 예상되는 사용자 환경에 부정적인 영향을 미칠 수 있으며, 따라서 사용자가 액티비티의 이 인스턴스에 돌아오는 것을 절대 바라지 않는 경우에만 사용해야 합니다.