본문 바로가기

안드로이드

액티비티와 인텐트


일반적인 컴퓨터에서는 애플리케이션 단위로 실행되지만 안드로이드에서는 액티비티 단위로 실행된다.


용어 정리


1. 애플리케이션(application)

- 안드로이드는 애플리케이션은 여러개의 액티비티들로 구성된다.

- 액티비티들은 애플리케이션 안에서 느슨하게 묶여 있다.

- 하나의 애플리케이션은 .apk를 확장자로 가지는 하나의 파일 안에 저장된다.


2. 액티비티(activity)

- 사용자가 어떤 작업을 할 수 있는 화면을 가지고 있는 애플리케이션 구성 요소이다.

- 각 액티비티는 사용자 인터페이스가 그려지는 윈도우를 가지고 있다.

- 안드로이드에서는 실행의 단위가 애플리케이션이 아니고 액티비티이다.


3. 태스크(task)

- 관련된 액티비티의 그룹으로 정의할 수 있고 이들 액티비티들은 액티비티 스택에 나열되어있다.

- 즉 하나의 태스크는 스택에 있는 액티비티들로 구성된다.


4. 액티비티 스택(activity stack) = 백스택(back stack)

- 사용자가 BACK 키를 누르면 안드로이드는 현재 액티비티를 제거하고 이전 액티비티로되돌아간다. 따라서 사용자가 방문한 액티비티들은 어딘가에 기억되어 있어야 한다. 이런 용도로 사용되는 것이 액티비티 스택이다.

- 안드로이드는 새로운 액티비티가 시작될 때마다 액티비티를 스택의 맨 위에 삽입된다.(PUSH)

- 만약 사용자가 BACK 키를 누르면 현재 액티비티는 스택에 제거되고(POP) 스택에 저장된 이전 액티비티로 되돌아간다.

- 스택의 맨 위에 있는 액티비티는 현재 실행되고 있는 액티비티이다.


5. 인텐트(intent)

- 하나의 액티비티에서 다른 액티비티를 시작하려면 액티비티의 실행에 필요한 여러 가지 정보들을 보내주어야 한다. 이때 사용하는 메시지가 인텐트이다.

- 액티비티와 같은 컴포넌트들은 인텐트라고 불리는 메시지를 통해서 활성화된다.

- 인텐트 메세징은 컴포넌트들을 실행 시간에 바인딩하는 기법이다.


인텐트의 종류

5-1. 명시적 인텐트(explicit intent)

- 타킷 컴포넌트의 이름을 지정한다.




예제1 )


activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.jiyeon.myapplication.MainActivity">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="여기는 액티비티1입니다."/>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="이미지 표시 액티비티 열기"/>
</LinearLayout>




layout2.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="여기는 액티비티2입니다."/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="닫기"/>
</LinearLayout>




MainActivity.java

package com.jiyeon.myapplication;

import android.app.Activity;
....

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Button b = (Button)findViewById(R.id.button1);
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

//액티비티를 실행할려면 인텐트 객체를 생성해야한다.

//두번째 이름을 알고 있으므로 두 번째 액티비티의 클래스 이름을 인수로 주어서 인텐트 객체를 생성한다.

//즉 명시적인 인텐트를 사용하는 것이다.
Intent intent = new Intent(MainActivity.this,Activity2.class);
startActivity(intent);
}
});


}
}



Activity2.java

package com.jiyeon.myapplication;

import android.app.Activity;
...

/**
* Created by jiyeon on 2016-04-03.
*/
public class Activity2 extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout2);

Button b = (Button)findViewById(R.id.button2);
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

//이벤트 리스너에서는 버튼이 클릭되면 finish() 메소드를 호출하여서 현재의 액티비티를 종료한다.
finish();
}
});


}

}


AndroidMainfest.xml


<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jiyeon.myapplication">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

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

//android:name에는 액티비티의 클래스 이름을 적어준다. 

//같은 패키지에 있는 경우에는 앞에 .을 찍어나 아니면 단순히 클래스 이름만 적어준다.

//다른 패키지라면 패키지 이름을 포함한 완전한 경로 이름을 적어야 한다.
<activity android:name="Activity2" android:label="Activity"></activity>
</application>

</manifest>





예제2)


activity_main.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.administrator.myapplication.MainActivity">

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="서브 액티비티로부터 문자열 반환받기"
android:id="@+id/button" />

<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="________________________________"/>

</LinearLayout>






sub.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<EditText
android:id="@+id/edit"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<requestFocus></requestFocus>
</EditText>
<LinearLayout
android:id="@+id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center">

<Button
android:id="@+id/button_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="입력완료"/>
<Button
android:id="@+id/button_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="취소"/>
</LinearLayout>
</LinearLayout>





AndroidManifest.xml

<activity android:name=".SubActivity" android:label="SubActivity" ></activity> //추가


MainActivity.java

package com.example.administrator.myapplication;

import android.app.Activity;
...

public class MainActivity extends Activity {
static final int GET_STRING = 1;
TextView text;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Button button = (Button) findViewById(R.id.button);
text = (TextView) findViewById(R.id.text);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent in = new Intent(MainActivity.this, SubActivity.class);
startActivityForResult(in, GET_STRING); //서브 액티비티 실행
}
});

}
//액티비티로부터 결과를 받는다.
protected void onActivityResult(int requestCode, int resultCode, Intent data){
if(requestCode == GET_STRING){
if(resultCode == RESULT_OK){
text.setText(data.getStringExtra("INPUT_TEXT"));
}
}
}

}


SubActivity.java


package com.example.administrator.myapplication;

import android.app.Activity;
...

/**
* Created by Administrator on 2016-04-04.
*/
public class SubActivity extends Activity {
EditText edit;

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

edit = (EditText) findViewById(R.id.edit);
Button button_ok = (Button) findViewById(R.id.button_ok);
button_ok.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//메인 액티비티로 결과를 보낸다.
Intent intent = new Intent();
intent.putExtra("INPUT_TEXT",edit.getText().toString());
setResult(RESULT_OK, intent);
finish();
}
});

Button button_cancel = (Button) findViewById(R.id.button_cancel);
button_cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setResult(RESULT_CANCELED);
finish();
}
});

}
}






5-2. 암시적 인텐트(implicit intent)

- 타킷 컴포넌트의 이름을 지정하지 않는다. 대신에 아주 암시적으로 컴포넌트를 지정하는 것이다.

- 특정한 타깃이 없으므로 안드로이드는 인텐트를 처리할 수 있는 가장 최적의 컴포넌트를 탐색하여야 한다.

- 안드로이드는 컴포넌트가 가지고 있는 인텐트 필터를 암시적인 인텐트와 비교하여 탐색을 수행한다.


전체적인 구조


Intent intent = new Intent(Intent.ACTION_SEND); //이메일 전송을 의미하는 인텐트 생성
intent.putExtra(Intent.EXTRA_EMAIL,recipientArray); //이메일의 송신자를 엑스트라 필드에 기술한다.
startActivity(intent);


- 인텐트 객체

● 컴포넌트 이름(component name)

  - 인텐트를 처리하는 타깃 컴포넌트의 이름이다.

  - 타킷 컴포넌트의 완전한 이름과 패키지 이름을 적어주면 된다.

  - 만약 이름이 없으면 암시적 인텐트가 되어서 안드로이드가 최적의 타깃 컴포넌트를 찾아준다.

  - setComponent(), setClass(), setClassName()으로 설정할 수 있고 getComponent()로 읽을 수 있다.

● 액션(action)

  - 액션은 수행되어야 하는 작업을 나타낸다.

  - 많은 액션들이 Intent 객체 안에 String 타입의 상수로 정의되어 있다.

 

자주 사용하는 액션

상수

타깃 컴포넌트 

액션 

 ACTION_VIEW

 액티비티

 데이터를 사용자에게 표시한다. 

 ACTION_EDIT

 액티비티

 사용자가 편집할 수 있는 데이터를 표시한다.

 ACTION_MAIN

 액티비티

 테스크의 초기 액티비티로 설정한다. 

 ACTION_CALL

 액티비티

 전화 통화를 시작한다. 

 ACTION_SYNC

 액티비티

 모바일 장치의 데이터를 서버 상의 데이터와 일치시킨다. 

 ACTION_DIAL

 액티비티

 전화번호를 누르는 화면을 표시한다.


● 데이터(data)

  - 작업에 필요한 데이터를 나타낸다.

  - 예를들면 액션이 ACTION_VIEW이면 무엇을 사용자에게 표시할 것인지를 주어야 한다.

  - 데이터는 URI 형식을 사용한다.

  - setData()와 getData() 메소드를 사용하여서 인텐트 객체에 데이터를 설정하고 접근할 수 있다.



Intent intent = new Intent(Intent.ACTION_CALL); //액션이 ACTION_CALL인 인텐트를 생성한다.

intent.setData(Uri.parse("tel:01012341234")); //01012341234번 전화번호를 데이터로 설정한다.
startActivity(intent); //인텐트를 시작한다.


● 카테고리(Categoty)

   - 액션에 대하여 추가적인 정보를 제공한다.

  - 예를들어 CATEGORY_LAUNCHER는 액티비티가 최상위 애플리케이션으로 론처에 나타내야한다는 것을 의미한다.

  - addCategoty() 메소드는 카테고리를 인텐트 객체 안에 위치시킨다

  - removeCategory()는 이전에 추가된 카테고리를 삭제한다.

  - getCategory()는 현재 인텐트 객체 안에 있는 모든 카테고리를 반환한다.


카테고리 상수

상수

설명 

 CATEGORY_BROWSABLE

 타깃 액티비티가 브라우저에 의하여 시작되어서 이미지와 같은 데이터를 표시할 수 있다.

 CATEGORY_GADGET

 액티비티가 다른 액티비티 안에 개짓으로 내장된다.

 CATEGORY_HOME

 홈 화면을 표시하는 액티비티이다.

 CATEGORY_LAUNCHER

 액티비티가 최상위 애플리케이션으로 론처에 나열된다.

 CATEGORY_PREFERENCE

 타깃 액티비티가 환경 설정 패널이다.


● 엑스트라(extra)

  - 타깃 컴포넌트로 전달되어야 하는 추가적인 정보를 가지고 있다.

  - "키-값(key-value)" 쌍으로 지정된다. 예를 들어 ACTION_TIMEZONE_CHANGED 인텐트는 새로운 시간대를 나타내는 "time-zone" 엑스트라를 가지     고 있다.

  - put..() 메소드를 이용하여서 다양한 유형의 엑스트라 데이터를 추가한다.

  - get..() 메소드를 이용하여서 엑스트라 데이터를 읽을 수 있다.



인텐트 필터

- 컴포넌트는 자신들이 처리할 수 있는 인텐트의 종류를 안드로이드 시스템에 알리기 위하여 하나 이상의 인텐트 필터를 가진다.

- 컴포넌트의 기능을 기술하고 컴포넌트가 수신할 수 있는 인텐트의 집합을 기술한다.

- 명시적 인텐트는 무엇을 포함하고 있든지 상관없이 항상 타깃 컴포넌트로 전달되지만 암시적 인텐트는 컴포넌트의 인텐트 필터를 통과해야만이 컴포넌   트로 전달된다.


1) 액션 비교

  - 인텐트의 액션은 필터에 나열된 액션 중의 하나와 반드시 일치하여야 한다.

  - 만약 필터가 어떤 액션도 나열하지 않았다면 어떤 인ㅌ넨트도 필터를 통과할 수 없다.

  - 만약 인텐트 객체가 어떤 액션도 지정하지 않았다면 자동적으로 필터를 통과한다.

<intent-filter ...>

   <action android:name="com.example.project.SHOW_CURRENT"  />

   <action android:name="com.example.project.SHOW_RECENT"  />

   <action android:name="com.example.project.SHOW_PENDING"  />

    ...

</intent-filter> 


2) 카테고리 비교

  - 인텐트 객체 안의 모든 카테고리가 필터의 카테고리와 일치되어야 한다.

  - 카테고리를 가지지 않은 인텐트 객체는 항상 카테고리 테스트를 통과한다.

  - 한가지 예외가 있는데 안드로이드는 startActivity()로 전달되는 모든 암시적 인텐트는 "android:intent.category.DEFAULT" 카테고리에 속한다고 가정한다. 따라서 암시적 인텐트를 받고자 하는 액티비티들은 "android.intent.category.DEFAULT"를 인텐트 필터에 나열하여야 한다. "andoir.intent.action.MAIN"과 "android.intent.category.LAUNCHER"를 가지고 있는 액티비티는 예외인데 이들 액티비티들은 "android.intent.category.DEFAULT"를 나열하지 않아도 암시적인 인텐트를 받을 수 있다.


<intent-filter ...>

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

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

   ...

</intent-filter>

 

3) 데이터 비교

  - 데이터 타입이나 URI를 지정하지 않은 인텐트는 필터가 아무런 URI나 데이터 타입을 지정하지 않은 경우에만 테스트를 통과한다.

  - 데이터 타입이나 URI 중에서 하나만 지정한 인텐트는 필터도 똑같이 하나만 지정한 경우에 테스트를 통과한다.

  - 데이터 타입과 URI을 모두 지정한 인텐트는 데이터 타입과 URI가 모두 필터와 일치하여야한다.

  - 하나의 예외로 필터가 데이터 타입만을 지정하였다면 "file:"이나 "content:"가 붙은 URI를 가지는 인텐트는 테스트를 통과된다.   


<intent-filter>

  <data

       android:mimeType="video/*"    //mimeType속성은 데이터의 MIME타입을 지정한다 '*'와 같은 와일드 카드 문자를 사용할 수있다.

       android:scheme="http"       />

  ...

</intent-filter>





'안드로이드' 카테고리의 다른 글

switch custom  (0) 2016.04.21
apk 파일 디컴파일 하기  (0) 2016.04.08
이벤트 처리2  (0) 2016.03.31
이벤트 처리  (0) 2016.03.31
레이아웃  (0) 2016.03.31