API GUIDE/2. App Components
2014. 3. 4. 22:13

저작권 표시 : 

 

Portions of this page are modifications based on work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.

 

현재 보시는 페이지는 안드로이드 오픈 소스 프로젝트에 의해 작성되고 공유된 작업물의 수정/번역본이며 크리에이티브 커먼즈 저작자 표시 2.5 라이센스에 기술된 조건의 사용 근거를 따른 것입니다.

 

본 문서의 원본은 http://developer.android.com/guide/components/activities.html이며 안드로이드 4.4 Kitkat 기준으로 설명되었습니다.






액티비티 개요(Activities)


Activity는 전화 걸기, 사진 찍기, 이메일 보내기, 맵 보기등과 같이 사용자가 뭔가 하려고 할 때 앱과 상호작용 할 수 있도록 화면을 제공하는 앱 컴포넌트다. 각 액티비티에는 UI를 그려넣을 수 있는 윈도우가 주어진다. 윈도우는 일반적으로 화면을 가득 메우지만 화면보다 작아서 다른 위도우의 위에 떠 있도록 할 수도 있다.


어플리케이션은 보통 서로 관계가 느슨한 여러 개의 액티비티로 구성되어 있다. 일반적으로 하나의 액티비티가 "main"액티비티로 지정이 되고 앱이 실행될 때 제일 처음 사용자에게 보여진다. 그리고나서 각 액티비티는 상황에 따라 다른 동작을 수행할 액티비티를 시작시킨다. 새로운 액티비티가 시작될 때마다 먼저번의 액티비티는 일시정지(pause)되고 시스템은 그 정지(stop)된 액티비티를 그대로 스택(백 스택; back stack)에 쌓아놓는다. 그리고 새로운 액티비티가 시작되면 백 스택에 푸시되고 포커스를 갖게 된다. 백스택은 스택의 기본 개념인 "Last In, First Out" 메커니즘을 따르기 때문에 사용자가 현재 액티비티에서 작업을 마치고 "뒤로"버튼을 누르면 스택의 마지막 액티비티는 스택에서 꺼내어지고 (그리고 파괴된다.) 이전의 액티비티가 복원이 된다. (한마디로 스택의 마지막 액티비티가 화면의 최전면에 표시되고 포커스를 갖게 되며 스택에서 꺼내지면 소멸된다. 백 스택은 Tasks and Back Stack에서 좀 더 자세히 논의된다.)


새로운 액티비티가 시작되어 현재 액티비티가 중지될 때, 이 변화된 상태는 액티비티의 라이프사이클 콜백 메서드를 통해 알려지게 된다. 상태변화(생성될 때, 정지될 때, 다시 복원될 때, 파괴될 때)를 알려주는 액티비티 콜백 메서드는 몇 종류가 있는데 이 메서드들은 상태 변화시에 앱이 특정 작업을 할 수 있는 기회를 제공하게 된다. 예를 들어, 액티비티가 정지되면 네트워크나 데이터베이스 연결 오브젝트 같은 덩치가 큰 오브젝트를 해제할 수도 있다. 액티비티가 정상 가동되면 해당 자원을 다시 획득할 수 있고 중단됐던 작업을 재개할 수 있다. 이런 상태의 변화는 액티비티 라이프사이클 전반에 걸쳐 발생된다.


이 문서에서는 (액티비티의 라이프사이클이 어떻게 동작하는 지를 포함해서) 액티비티를 만들고 사용하는 법에 대해 논의한다. 그래서 여러분이 다양한 액티비티의 상태 변화를 적절히 다룰 수 있도록 한다.



액티비티 생성하기(Creating an Activity)



액티비티를 생성하기 위해서는 Activity 클래스(또는 이미 존재하는 Activity의 서브클래스)의 서브클래스를 생성해야 한다. 서브클래스에서는 액티비티가 생성되고, 정지, 복귀, 파괴되는 등의 다양한 상태변화를 알려주는 콜백 메서드를 구현해야 한다. 가장 중요한 콜백 메서드는 다음의 2개다.


onCreate()

이 메서드는 반드시 구현해야 한다. 시스템은 액티비티가 생성될 때 이 메서드를 호출한다. 기본적인 컴포넌트의 초기화를 이 메서드에서 구현한다. 이메서드를 구현할 때 가장 중요한 것은 액티비티의 UI를 위한 레이아웃을 반드시 setContentView()를 통해 정해줘야 한다.


onPause()

시스템은 사용자가 액티비티를 떠날 때 가정 먼저 이 메서드를 호출한다.(이 메서드가 호출되었다고는 해도 액티비티가 항상 파괴되는 것을 의미하지는 않는다.) 이 메서드는 사용자가 현재 세션에서 떠날 때 (사용자가 다시 돌아오지 않고 프로세스가 종료될 수 있기 때문에) 영구보존해야 하는 정보를 저장해야 하는 곳이다.


라이프사이클 콜백 함수는 여러 종류가 있다. 액티비티 간의 UI를 적절하게 제공하고 액티비티가 정지되거나 심지어는 파괴되는 갑작스런 상황에도 대응하기 위해서는 이 콜백 메서드들을 활용해야만 한다. 모든 라이프사이클 콜백 메서드는 뒤쪽 섹션(액티비티 라이프사이클 관리하기; Managing the Activity Lifecycle)에서 더 자세히 다룬다.


UI 구현하기(Implementing a user interface)

액티비티의 UI는 View 클래스로부터 파생된 뷰콘트롤들로 만들어진다. 각 뷰콘트롤들은 액티비티의 윈도우 안에서 일정 부분의 직사각형 영역을 차지하고 동작하며 사용자와 상호작용을 하도록 되어 있다. 예를 들어, 버튼 뷰는 사용자가 터치하면 특정 동작을 시작하게 된다.


안드로이드는 레이아웃을 디자인하고 꾸밀 수 있도록 많은 뷰콘트롤들을 제공한다. "위젯"은 버튼, 텍스트 필드, 체크 박스 또는 이미지 같이 사용자에게 보여지고 입력을 처리하는 뷰콘트롤들이다. "레이아웃"은 ViewGroup을 상속받은 뷰이며 linear 레이아웃, grid 레이아웃, relative 레이아웃과 같이 각각 다른 레이아웃 모델을 제공한다. ViewViewGroup 클래스를 상속받거나 또는 상속받아 만들어진 기존의 클래스를 다시 상속받아 나만의 새로운 위젯과 레이아웃을 만들어서 액티비티 레이아웃에 사용할 수도 있다.


뷰를 사용하여 레이아웃을 만드는 가장 일반적인 방법은 앱리소스에 저장된 XML 레이아웃 파일을 이용하는 것이다. 이 방법을 사용하면 디자인과 소스코드를 분리하여 관리할 수 있다. 이렇게 만들어진 레이아웃은 레이아웃의 리소스ID를 setContentView()에 넘겨 액티비티의 UI로 사용할 수 있다. 그러나 액티비티의 코드안에서 새로운 View를 만들고 ViewGroup에 집어넣을 수도 있다. 그런 후에 최상위 ViewGroupsetContentView() 메서드에 넘겨 사용할 수 있다.


UI를 만드는 법은 User Interface 문서를 참고하기 바란다.


매니페스트에 액티비티 선언하기(Declaring the activity in the manifest)

만들어둔 액티비티가 시스템에서 액세스가 가능하도록 하려면 manifest 파일에 반드시 선언을 해 주어야 한다. 액티비티를 선언하려면 아래 예제처럼 <application> 엘리먼트의 내부에 <activity> 엘리먼트로 선언한다.


1
2
3
4
5
6
7
<manifest ... >
  <application ... >
      <activity android:name=".ExampleActivity" />
      ...
  </application ... >
  ...
</manifest >
 


이 엘리먼트에는 액티비티의 레이블, 아이콘, 테마 스타일 같은 속성을 정의하기 위한 몇몇 속성들이 있다. android:name 속성은 액티비티의 클래스명만 입력해 주면 된다. 일단 앱을 게시하고나면 앱의 숏컷과 같은 기능이 제대로 동작하지 않는 문제가 발생하기 때문에 이 이름은 바꿔줄 수가 없다. (이 문제에 대한 내용은 블로그의 Things That Cannot Change 포스트를 읽어보기 바란다.)


매니페스트에 액티비티를 선언하는 법에 대해 좀 더 자세히 알고 싶으면 <activity> 엘리먼트의 도움말을 참고하기 바란다.


인텐트 필터 사용하기(Using intent filters)

다른 앱에서 액티비티를 활성화시킬 수 있도록 하기 위해서 - <intent-filter> 엘리먼트를 사용하여 - 다양한 인텐트 필터를 <activity> 엘리먼트의 아래에 둘 수 있다.


안드로이드 SDK 툴을 사용하여 새로운 앱을 생성하면 텅빈 액티비티가 자동으로 생성된다. 이 액티비티는 "main" 액션과 "launcher" 카테고리를 나타내는 인텐트 필터가 자동으로 추가되어 있다. 인텐트 필터를 다음과 같이 생성된다.


1
2
3
4
5
6
<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> 엘리먼트는 이 액티비티가 시스템의 앱 런처(사용자가 액티비티를 시작할 수 있도록 하는) 목록에 표시되도록 선언하고 있다.


만일 다른 앱에서 액티비티를 활성화시키는 것을 막고자 한다면 다른 인텐트 필터는 필요없다. 위 예제처럼 오직 하나의 액티비티만 "main" 액션과 "launcher" 카테고리를 선언하면 된다. 다른 앱에서 사용하지 못하도록 만든 다른 액티비티들은 인텐트 필터를 가져서는 안되며 명시적인 인텐트를 통해서 시작시킨다. (이 내용은 다음 섹션에서 설명된다.)


하지만 액티비티가 암시적 인텐트에 반응하도록 하려면 (어떤 어플리케이션에서 발생된 암시적 인텐트이건 관계없이) 액티비티에 적절한 인텐트 필터를 정의해 주어야 한다. 응답하고자 하는 각 종류별 인텐트에 대해서 <intent-filter>를 사용하여 인텐트 필터를 정의해 준다. <intent-filter>에는 필히 <action> 엘리먼트가 포함되어야 하며 액션에 따라 <category>, <data> 엘리먼트가 포함되어야 할 수도 있다. 이 엘리먼트들의 조합에 따라 액티비티가 응답하고자 하는 인텐트를 정의할 수 있다.


어떻게 하면 인텐트에 액티비티가 응답하도록 할 수 있는지에 대해 더 많은 정보를 얻고 싶다면 인텐트와 인텐트 필터(Intents and Intent Filters) 문서를 참고하기 바란다.



액티비티 구동하기(Starting an Activity)



다른 액티비티를 실행시키려면 실행시킬 액티비티에 대한 설명이 담긴 Intent를 파라메터로 하여 startActivity() 메서드를 호출한다. 인텐트는 실행시키려고 하는 정확한 액티비티를 지정하고 수행하고자 하는 액션에 대해 설명을 담고 있다. (시스템은 이 인텐트의 정보를 바탕으로 최적의 액티비티 - 다른 어플리케이션에 속한 액티비티라고 하더라도 - 찾아준다.) 인텐트는 실행된 액티비티가 액션을 수행하는 데 사용할 수 있는 데이터를 전달해 줄 수도 있다.


동일 어플리케이션의 액티비티라면 이미 존재하는 액티비티를 간단하게 실행시켜야 할 때도 있다. 이것은 실행시키고자 하는 액티비티의 클래스명을 가지고 명시적 인텐트를 생성함으로써 가능하다. 아래의 예제는 하나의 액티비티가 SignInActivity라는 이름을 가진 다른 액티비티를 실행시키는 방법에 대한 것이다.


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


그러나 여러분이 만든 액티비티의 데이터를 사용해서 이메일 또는 문자메시지를 보내거나 상태 업데이트 같은 액션을 수행해야 할 수도 있다. 이런 경우 여러분의 어플리케이션에 해당 액션을 수행할 수 있는 기능이 없으면 그 액션이 수행 가능한 다른 어플리케이션의 액티비티를 통해서 수행해야 한다. 이럴 때 인텐트가 아주 유용하다. 수행하고자 하는 액션에 대한 내용을 인텐트에 담아 생성하면 시스템은 다른 어플리케이션에서 적절한 액티비티를 찾아 실행시켜준다. 만일 해당 인텐트를 처리할 수 있는 액티비티가 여러 개 존재한다면 사용자는 그 중에서 하나를 골라 실행시킬 수 있다. 다음은 사용자가 이메일 메시지를 보내려고 할 때 인텐트를 생성하는 예제 코드다.


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


EXTRA_EMAIL 부가정보키와 함께 이메일을 받는 수신자들의 이메일 주소를 문자열 배열로 만들어 인텐트에 추가한다. 이메일 어플리케이션이 이 인텐트를 받게 되면 부가정보에 있는 문자열의 배열을 읽어 이메일 작성폼의 "수신자" 항목에 입력시킨다. 이 때, 이메일 어플리케이션의 액티비티가 실행되고 사용자가 일을 마치면 여러분의 액티비티로 다시 복귀하게 된다.


액티비티 구동시키고 결과 받기(Starting an activity for a result)

경우에 따라서는 여러분이 실행시킨 액티비티로부터 어떤 결과를 돌려받아야 할 때가 있다. 이럴 때는 startActivity() 메서드 대신에 startActivityForResult() 메서드를 호출한다. 실행시킨 액티비티로부터 결과를 돌려받기 위해서는 onActivityResult() 콜백 메서드를 구현해 주어야 한다. 실행시킨 액티비티의 일이 완료되면 결과를 Intent에 담아 onActivityResult() 메서드를 통해 넘겨준다.


아래 코드는 사용자로 하여금 연락처 중에 하나를 선택하도록 하고 선택된 연락처 정보를 사용해서 어떤 작업을 수행하도록 하는 예제다. 이 예제는 인텐트를 생성하고 그 결과를 처리하는 법을 보여준다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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}, nullnullnull);
        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() 메서드에 대한 기본 로직을 보여주고 있다. 첫번째 if문은 조건 검사로써 요청에 대한 작업이 성공이었는지 - 성공이었다면 resultCodeRESULT_OK일 것이다. - 그리고 요청했던 작업에 대한 결과로 호출된 것이 맞는 지 - 예제에서는 requestCode의 값이 startActivityForResult()를 호출할 때 넘겨 준 요청코드와 맞는지를 확인하고 있다. 조건 검사가 끝나면 반환된 Intent(data 파라메터)의 데이터를 쿼리하여 액티비티의 결과를 처리한다.


데이터는 ContentResolver(예제에서는 getContentResolver() 메서드로 획득)로 컨텐트 프로바이더에 쿼리하여 Cursor를 획득하고 이 Cursor를 이용해 읽고자 하는 데이터를 다시 쿼리한다. 더 많은 정보는 Content Providers 문서를 참고하기 바란다.


이 섹션의 내용에 대해 더 자세히 알고 싶다면 인텐트와 인텐트 필터(Intents and Intent Filters) 문서를 참고하기 바란다.



액티비티 닫기(Shutting Down an Activity)



액티비티는 finish() 메서드를 호출하여 닫을 수 있다. 또한 finishActivity() 메서드를 사용하면 앞서 구동시킨 다른 액티비티도 닫을 수 있다.


Note : 대부분의 경우, 이런 메서드들을 직접 호출하여 액티비티를 종료하지 말아야 한다. 액티비티 라이프사이클에 대해 설명하고 있는 다음 섹션의 내용과 같이 안드로이드 시스템이 액티비티의 수명을 관리하고 있기 때문에 액티비티를 직접 종료시킬 필요가 없다. 이 메서드들은 사용자가 예상하지 못한 상황에 맞닥뜨리게 되는 부정적인 상황을 초래하기 때문에 이 액티비티에 사용자가 머물러서는 안된다는 확실한 이유가 있을 때만 직접 호출해야 한다.


posted by 리치크루