본문 바로가기

프로그래밍/안드로이드

[안드로이드] 액티비티(Activity)와 인텐트(Intent)

1. 액티비티 추가


액티비티(Activity)는 사용자와의 인터페이스를 만들지만 자체 출력기능이 없다.

용자에게 실제로 보여지는 부분은 뷰(View) 또는 뷰그룹(ViewGroup)에 해당한다.

액티비티가 생성될 때(onCreate)마다 호출되는 setContentView 메서드가 액티비티안에 뷰를 배치하는 

명령이다.


액티비티 하나는 독립된 기능을 수행하며 액티비티끼리 중첩되지 않는다는 것도 뷰와 다른 점이다.



일단 새로운 액티비티를 추가한 뒤, 액티비티간에 통신하는 코드를 구성할 것이다.


메인 액티비티 → CALL 버튼 → 서브 액티비티


< 호출을 실시할 코드(main) >

< 호출을 실시할 xml>


< 호출이 될 코드(sub) >


< 호출이 될 xml >


간단하게 정리하면 액티비티 간 통신을 하기 위해서 

JAVA 코드 2개(메인+서브)와 XML 리소스 2개(메인+서브)가 필요한 것이다.

( ※ 메인 : 호출하는 액티비티, 서브 : 호출되는 액티비티)


☆ 주의할 점은, 매니페스트(Manifest)에 SubActivity가 명시되어 있어야 한다는 것이다. ☆



2. 인텐트


액티비티끼리 서로 호출하기 위해서 필요한 통신 장치가 인텐트(Intent)이다.

액티비티를 호출하는 메서드는 아래 메서드이다.

void strartActivity (Intent intent)

첫번째 인수(intent) : 누구를 호출하여 무슨 작업을 시킬 것인가에 대한 정보가 담겨있다.


인텐트의 생성자는 아래와 같다.


Intent () // 디폴트 생성자  , 사용되는 경우가 드묾.

Intent (Intent o) // 복사 생성자 , 사용되는 경우가 드묾.

Intent (String action [, Uri uri])

☆ Intent (Context packageContext, Class<?> cls)  // 가장 많이 사용하는 생성자

첫번째 인수 : 액티비티 클래스를 구현하는 컨텍스트(context), 보통 this를 사용한다.

두번쨰 인수 : 호출할 액티비티의 클래스

Intent (String action, Uri uri, Context packageContext, Class<?> cls)



<예제>


Intent intent = new Intent ( this , SubActivity.class )  // 네번째 생성자

첫번째 인수(this) : 메인 액티비티 자신

두번째 인수(클래스이름.class) : 호출할 클래스


이와 같이 인텐트에 호출할 대상 컴포넌트가 분명히 명시되어 있는 것을 명시적(Explicit) 인텐트라고 한다. 반면 호출 대상이 분명히 정해지지 않은 인텐트를 암시적(Implicit) 인텐트라고 한다.

 <컴포넌트(component)란?>

< 출처 : http://ggodol.tistory.com/ >

안드로이드 애플리케이션은 컴포넌트(component)로 구성되어있다. 안드로이드의 4대 컴포넌트는 액티비티(activity), 서비스(service), 방송수신자(broadcast receiver), 콘텐트 제공자(content provider)이다. 각 컴포넌트들은 하나의 독립된 형태로 존재하며, 정해진 역할을 수행한다. 이때, 인텐트를 통하여 다른 애플리케이션의 컴포넌트를 활성화시킬 수 있다.


1.3 액티비티간의 통신


인텐트는 액티비티간에 인수와 리턴값을 전달하는 도구로 사용된다. 

주로 Bundle 타입의 Extras를 활용하며. Extras는 인텐트 내의 정보 저장 주머니이며

호출하는 쪽이나 받는 쪽에서 자유롭게 액세스가 가능하다.


Extras에 값을 저장하는 메서드


Intent putExtra (String name, int value)

Intent putExtra (String name, String value)

Intent putExtra (String name, boolean value)

첫번째 인수 : 전달하는 인수에 대한 이름

두번째 인수 : 값


Extras에 저장된 값을 꺼내는 메서드


int getIntExtra (String name, int defaultValue)

String getStringExtra (String name)

boolean getBooleanExtra (String name, bolean defaultValue)

값이 전달되지 않았을 경우 두 번째 인수로 저장된 디폴트가 리턴된다.

문자열은 null이 리턴된다.



리턴값을 돌려주는 액티비티를 호출하는 메서드

void startActivityForResult (Intent intent, int requestCode)

두번째 인수 : 호출한 대상을 나타내는 식별자


호출된 액티비티가 종료되면 다음 메스드가 호출된다.

void onActivityResult (int requestCode, int resultCode, Intent data)

첫번째 인수 : 액티비티를 호출할 때 전달한 요청코드

두번째 인수 : 액티비티의 실행결과

세번째 인수 : 데이터 값


즉, 두 개의 메서드를 정의해야 한다.



<문자열 편집 액티비티 예제>



1. 메인엑티비티 → 2. 서브액티비티 → 3. 문자열 입력 → 4. 메인액티비티로 다시 돌아옴


2개의 자바 코드와 2개의 XML 파일이 필요하다.


<메인(호출하는) XML>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Sample"
/>
<Button
android:id="@+id/btnedit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="mOnClick"
android:text="Edit"
/>
</LinearLayout>

<서브(호출되는) XML>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<EditText
android:id="@+id/stredit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<Button
android:id="@+id/btnok"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="mOnClick"
android:text="OK"
/>
<Button
android:id="@+id/btncancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="mOnClick"
android:text="Cancel"
/>
</LinearLayout>


<메인(호출하는).JAVA>


먼저 큰 그림으로 관찰하자.


일단 onCreate 메서드 부분은 제외하고 구조적인 흐름만 살펴보면

startActivityForResult와 onActivityResult 부분으로 나뉘는 것을 볼 수 있다.


public class ExerciseExam extends Activity {
TextView mText;
final static int ACT_EDIT = 0; // ☆ 편집 액티비티의 요청코드는 "0번" (상수) ☆

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_excercise_exam);

mText = (TextView)findViewById(R.id.text);
}

public void mOnClick(View v) {
switch (v.getId()) {
case R.id.btnedit:
Intent intent = new Intent(this, SubActivity.class);
intent.putExtra("TextIn", mText.getText().toString());


/* Extras (정보 주머니)에 값을 저장하는 메서드


Intent putExtra (String name, String value)

첫번째 인수(name) : 전달하는 인수에 대한 이름 (자유롭게 붙일 수 있음)

두번째 인수(value) :  Extra에 값을 저장 (mtext의 String 값을 저장)


*/

startActivityForResult(intent, ACT_EDIT);


/* 리턴값을 돌려주는 액티비티 호출하는 메서드


   void startActivityForResult (Intent intent, int requestCode) 

   두번째 인수 : 호출한 대상을 나타내는 식별자 (여기서는 requestCode = 0) 


*/


break;
}
}

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


/* 서브액티비티의 실행 결과를 onActivityResult 메서드로 전달받는다.

     메인에서 호출한 액티비티가 종료되면 위 메서드를 호출한다.


void onActivityResult (int requestCode, int resultCode, Intent data)

첫번째 인수 : 액티비티를 호출할 때 전달한 요청코드

두번째 인수 : 액티비티의 실행결과
세번째 인수 : 전달받는 데이터                          

*/


switch (requestCode) {
case ACT_EDIT:
if (resultCode == RESULT_OK) {
mText.setText(data.getStringExtra("TextOut"));


// 만약 결과코드로 RESULT_OK를 전송받았다면

// Extra로부터 "TextOut"의 이름을 가진 // String을 값을 가져온다.

}
break;
}
}
}


<서브(호출되는).JAVA>

public class SubActivity extends Activity {
EditText mEdit;

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sub);

mEdit = (EditText)findViewById(R.id.stredit);
Intent intent = getIntent(); // 전달된 인텐트를 구현

// 이 안에는 액티비티가 해야할 동작, 데이터, 추가 정보가

// 있다.


String text = intent.getStringExtra("TextIn");


/* Extra에 저장된 값을 읽어오는 메서드


String getStringExtra (String name)

첫번째 인수(name) : Extra에 "TextIn"이라는 이름으로 저장된 값을 읽어온다.      메인 액티비티에서 "TextIn"에 저장된 값을 mText.getText.toSring()로 지정했다.      맨 처음에는 sample이라는 값을 읽어올 것이다.

*/


if (text != null) {
mEdit.setText(text);
}
}

public void mOnClick(View v) {
switch (v.getId()) {


case R.id.btnok: // OK 버튼을 누르면! 아래와 같은 코드가 작동한다.
Intent intent = new Intent();
intent.putExtra("TextOut", mEdit.getText().toString());

/* Extras (정보 주머니)에 값을 저장하는 메서드


Intent putExtra (String name, String value)

첫번째 인수(name) :  이번에는 TextIn이 아니라 TextOut이다.

두번째 인수(value) :  편집한 문자열을 저장 (mEdit의 String 값을 저장)

*/


setResult(RESULT_OK,intent); // 인텐트의 작업 결과를 대입 ( 편집 완료했으면 OK )


/* 결과를 대입하는 메서드


void setRresult (int resultCode, Intent data )

첫번째 인수 : 인텐트의 작업 결과 (여기서는 RESULT_OK 또는 RESULT_CANCELED) 두번째 인수 : 리턴값 (여기서는 전달할 데이터값이 있음!)


*/


finish();
break;


case R.id.btncancel: // CANCEL 버튼을 누르면! 아래와 같은 코드가 작동한다.


setResult(RESULT_CANCELED); // 인텐트의 작업 결과 ( 취소했으면 CANCEL )

/* 여기서는 전달할 데이터값이 없음!



finish();
break;
}
}
}


Sub액티비티의 작업값을 돌려받아야 한다면

Main액티비티에서 startActivityForResult 메서드를 써야 하고,  다음 onActivityResult를 작성해주어야 한다.


Sub액티비티에서 결과코드(resultCode)를 두 개 정의하고 있다.

한개는 RESULT_OK(완료) , 한개는 RESULT_CANCELED(취소)이다.


메인엑티비티에서 ACT_EDIT (요청코드 0번)에 대해 "서브액티비티의 실행결과로 RESULT_OK"가 왔으면, 데이터를 얻어오는 작업을 수행한다. 따라서 인텐트로 전달된 추가 정보(data) 중 TextOut의 이름을 가지는 문자열을 읽어 텍스트뷰에 대입한다.


이러한 전체적인 구조를 보는 것이 중요하다. (나도 이해하는 데 오래걸렸다. 두 세 번 읽어보도록 하자)



1.4 암시적 인텐트


암시적 인텐트(implicit Intent) : 호출대상이 명확하게 정의되어 있지 않은 인텐트를 말한다

암시적 인텐트를 사용하면 다른 패키지의 액티비티나 서비스의 호출이 가능하다.

버튼을 4개 배치한 레이아웃


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button
android:id="@+id/web"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="mOnClick"
android:text="web"
/>
<Button
android:id="@+id/dial"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="mOnClick"
android:text="dial"
/>
<Button
android:id="@+id/picture"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="mOnClick"
android:text="picture"
/>
<Button
android:id="@+id/other"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="mOnClick"
android:text="other"
/>
</LinearLayout>


코드는 아래와 같다.

public class ExerciseExam extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_excercise_exam);
}

public void mOnClick(View v) {
Intent intent;
switch (v.getId()) {
case R.id.web:
intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"));
startActivity(intent);
break;
case R.id.dial:
intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:015-123-4567"));
startActivity(intent);
break;
case R.id.picture:
intent = new Intent(Intent.ACTION_VIEW);
String sd = Environment.getExternalStorageDirectory().getAbsolutePath();
Uri uri = Uri.fromFile(new File(sd + "/test.jpg"));
intent.setDataAndType(uri, "image/jpeg");
startActivity(intent);
break;
case R.id.other:
intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(new ComponentName("exam.memo", "exam.memo.Memo"));
//intent.setClassName("exam.memo", "exam.memo.Memo");
startActivity(intent);
break;
}
}
}


ACTION_VIEW : 뭔가를 보여준다

ACTION_DIAL : 전화를 건다.

ACTION_MAIN : 메인 액티비티를 실행한다.


안드로이드 시스템에는 자주 사용되는 암시적 인텐트를 처리하는 액티비티가 기본적으로 설치되어 배포된다. 암시적 호출이 발생할 때 시스템은 매니페스트를 검색하여 최적의 컴포넌트를 찾는다.