android) 인텐트와 데이터 전달

인텐트에 클래스 객체나 컴포넌트 이름을 지정하여 호출할 대상을 확실히 알 수 있는 경우에는 '명시적 인텐트(Explicit Intent)'라고 하며, 액션과 데이터를 지정하긴 했지만 호출할 대상이 달라질 수 있는 경우에는 '암시적 인텐트(Impicit Intent)'라고 부릅니다.

암시적 인텐트는 액션과 데이터로 구성되지만 그 외에도 여러가지 속성을 가지고 있습니다.


  • 범주
액션이 실행되는 데 필요한 추가적인 정보를 제공

  • 타입
인텐트에 들어가는 데이터의 MIME 타입을 명시적으로 지정합니다.

  • 컴포넌트
인텐트에 사용될 컴포넌트 클래스 이름을 명시적으로 지정, 보통 이 정보는 인텐트의 다른 정보를 통해 결정합니다.

  • 부가데이터
인텐트는 추가적인 정보를 넣을 수 있도록 번들(Bundle) 객체를 담고 있다. 이 객체를 통해 인텐트 안에 더 많은 정보를 넣어 다른 애플리케이션 구성요소에 전달 할 수 있습니다.

인텐트에 액션과 데이터를 넣어 다른 애플리케이션의 액티비티를 띄우는 경우와 컴포넌트 이름을 이용해 새로운 액티비티를 띄우는 경우입니다.

// 인텐트 객체를 만드는 방법 #1
// 인텐트 객체를 만듭니다.
Intent intent = new Intent(getBaseContext(), AnotherActivity.class);
// 액티비티를 띄워주도록 startActivityForResult() 메소드를 호출합니다.
startActivityForResult(intent, REQUEST_CODE_ANOTHER);

// 인텐트 객체를 만드는 방법 #2
Intent intent = new Intent();
ComponentName name = new ComponentName("org.androidtown.intent.basic", "org.androidtown.intent.basic.AnotherActivity");
intent.setComponent(name);
startActivityForResult(intent, REQUEST_CODE_ANOTHER);

컴포넌트 이름은 ComponentName 객체를 만들어 인텐트에 설정하는데 두 개의 파라미터는 각각 패키지 이름과 클래스 이름이 됩니다.

액티비티 간의 전환
인텐트는 액티비티를 띄우기 의해서도 많이 사용하는데 startActivity() 메소드와 startActivityForResult() 메소드가 사용됩니다.

액티비티 B가 종료되기 전에 setResult() 메소드를 호출하면 액티비티 A에게 응답을 보낼 수 있다. 액티비티 B에서 보낸 응답은 부모 액티비티의 onActivityResult() 메소드에서 받을 수 있다. 만약 액티비티가 알 수 없는 이유로 끝나 버리거나 비정상 종료되면Activity.RESULT_CANCELED 값이 전달합니다..

시스템이 요청하는 인텐트의 정보를 받아 처리할 애플리케이션 구성요소를 찾기 위해 필요한 정보가 바로 '인텐트 필터' 이다. 즉, 인텐트 필터는 인텐트가 가지는 액션 정보를 동일하게 가질 수 있는데 이 인텐트를 해석하는 매커니즘은 기본적으로 전달하고자 하는 대상 인텐트와 설치된 앨플리케이션들이 가지는 인텐트 필터를 서로 비교하는 방식을 취하고 있습니다.

액티비티 스택과 플래그

플래그는 액티비티가 동작하는 방식을 설정할 수 있도록 해준다. 액티비티는 '액티비티 스택'이라는 것으로 관리되는데 이 스택은 액티비티를 차곡차곡 쌓아두었다가 가장 상위에 있던 액티비티가 없어지면 이전의 액티비티를 다시 실행하도록 도와줍니다.

새로운 액티비티를 만들어 매니페스트 파일에 등록하면 그 액티비티는 startActivity() 메소드를 이용해 실행될 수 있습니다. 이렇게 실행된 액티비티는 화면에 띄워지는데 새로운 액티비티가 화면에 띄워지게 되면 이전에 있던 액티비티는 액티비티 스택에 저장되고 새로운 액티비티가 화면에 보이는 구조이다. 화면에 보이던 액티비티가 없어지면 액티비티 스택의 가장 위에 있던 액티비티가 화면 상에 보이면서 재실행됩니다.

결국, 새로운 화면이 보이게 되면 이전의 화면들은 그 화면의 뒤에 차곡차곡 가려져 있다고 생각 할 수 있다. 만약 동일한 액티비티를 여러 번 실행한다면 동일한 액티비티가 여러 개 스택에 들어가 있고 동시에 데이터를 여러 번 접근하거나 리소스를 여러 번 사용하는 문제가 발생할 수 있습니다. 이러한 문제를 해결해주는 것이 바로 플래그입니다.

[Reference]
FLAG_ACTIVITY_SINGLE_TOP
FLAG_ACTIVITY_NO_HISTORY
FLAG_ACTIVITY_CLEAR_TOP

FLAG_ACTIVITY_SINGLE_TOP 플래그는 액티비티를 생성할 때 이미 생성된 액티비티가 있으면 그 액티비티를그대로 사용하라는 플래그입니다.
액티비티가 이미 메모리 상의 객체로 만들어져 있는 경우에는 액티비티를 다시 띄우더라도 onCreate()메소드가 호출되지 않으므로 onNewIntent() 메소드를 재정의해 사용해야 합니다.

FLAG_ACTIVITY_NO_HISTORY는 처음 이후에 실행된 액티비티는 액티비티 스택에 추가되지 않습니다. 즉, 플래그가 설정되어 있지 않은 경우에는 이전에 실행되었던 액티비티가 스택에 추가되므로 [Bank]키를 누르면 이전의 액티비티가 보이게 되지만 이 플래그를 사용하면 항상 맨 처음에 실행되었던 액티비티가 바로 보이게 됩니다.

FLAG_ACTIVITY_CLEAR_TOP으로 설정하면 이 액티비티 위에 있는 다른 액티비티를 모두 종료시키게 됩니다. 이 플래그는 홈 화면과 같이 다른 액티비티보다 항상 우선하는 액티비티를 만들 때 유용하게 사용할 수 있습니다.

부가 데이터

액티비티 간에 데이터를 전달하기 위해 사용하는 번들 객체는 인텐트 안에 들어 있기 때문에 put(), get() 메소드를 이용해 데이터를 넣거나 볼 수 있습니다.

전달하고 싶은 데이터가 기본 데이터 타입이 아닌 객체인 경우에는 객체 자체를 전달할 수 없습니다. 따라서 객체의 데이터들을 바이트 배열로 변환하여 전달하거나 또는 Serializable 인터페이스를 구현하는 객체를 만들어 직렬화한 후 전달할 수 있습니다. android에서는  인터페이스를 이용해 내부적인 데이터 전달 메커니즘이 만들어져 있기 때문에 Parcelable 인터페이스를 권장합니다.

Parcelable 인터페이스를 구현하여 객체를 직접 전달하려면 다음과 같은 두 가지 메소드를 구현합니다.
[Reference]
public abstract int describeContents()
public abstract void writeToParcel(Parcel dest, int flags)

writeToParcel() 메소드는 객체가 가지고 있는 데이터를 Parcel 객체로 만들어 주는 역할을 합니다. 이 Parcel 객체는 Bundle 객체처럼 read()와 write() 메소드를 제공하므로 기본 데이터 타입을 넣고 확인할 수 있도록 합니다. 위의 두 가지 메소드를 구현하였다면 CREATOR라는 상수를 만들어야 하는데 이 상수는 Parcel 객체로부터 데이터를 읽어 들여 객체를 생성하는 역할을 합니다.

댓글 없음:

Powered by Blogger.