Ch 02 안드로이드 애플리케이션과 액티비티
목차
Section 01. 안드로이드 애플리케이션 구성요소
Section 02. 안드로이드 액티비티
Section 03. 리소스 외부화
Section 01. 안드로이드 애플리케이션 구성요소
안드로이드 애플리케이션의 구성요소는 사용자가 직접 눈으로 보며 상호작용을 하는 컴포넌트(액티비티, 알림;Notification)와 사용자의 눈으로 볼 수 없거나 백그라운드에서 실행되는 컴포넌트(콘텐츠 프로바이더, 서비스, 브로드캐스트 리시버)로 나눌 수 있다. 인텐트(Intent)와 알림(Notification)은 애플리케이션 컴포넌트라고 할 수 없지만, 각 컴포넌트들과 깊은 연관을 가지고 있다.
안드로이드 애플리케이션을 구성하는 컴포넌트는 4가지가 있다.
어플리케이션 구성요소
구성요소 |
설명 |
액티비티(Activity) |
UI제공 및 이벤트 처리 등의 유저와 어플리케이션 간의 소통을 중계하는 객체, 하나의 화면에 대해 하나의 액티비티가 대응함 |
인텐트(Intent) |
액티비티와 서비스 등을 부를 때 사용하는 메세지 객체 |
서비스(Service) |
화면표시와는 독립적으로 백그라운드에서 처리되는 오브젝트 |
콘텐츠 프로바이더 (Content Provider) |
모바일 디바이스의 데이터영역에 액세스하기 위한 오브젝트 |
액티비티, 서비스, 브로드캐스트 리시버들은 실제 실행되는 프로그램들이다. 액티비티는 눈앞에서 실행되고, 서비스는 보이지 않게 백그라운드로 실행되고, 브로드캐스트 리시버는 시스템에 무슨 일이 있을 때(예, 배터리상태, 키보드보임) 신호가 나오면 그것을 받아 처리한다. 인텐트는 이 프로그램들 사이에서의 다리와 같은 역할을 한다. 한 프로그램이 다른 프로그램으로 다른 작업을 요구하거나 데이터를 넘겨줄 때 이용되는 교량의 역할이다. 콘텐츠 프로바이더는 시스템에 저장되어 있는 콘텐츠들을 애플리케이션이 자유자재로 공유할 수 있게 한다. 이 콘텐츠는 주소(URI)의 개념으로 표시되는데 각 애플리케이션은 이 URI를 알고 있으면 자유자제로 데이터를 공유할 수 있다.
Section 02. 안드로이드 액티비티
액티비티(activity)는 사용자 인터페이스(UI)를 작성할 때는 사용하는 구성요소이다. 액티비티는 애플리케이션의 "한 화면"을 뜻하며 화면에 보이는 애플리케이션 구성의 기본 단위이다. 비주얼 인터페이스를 가지는 애플리케이션으로 하나의 액티비티에는 그리기가 가능한 윈도우를 부여된다. 액티비티의 예로는 연락처 조회, 편집 화면을 들 수 있다.
하나의 애플리케이션은 여러 액티비티로 구성 가능한데 이들의 어떻게 동작하는지 연락처 애플리케이션으로 이해해 보도록 하자. 연락처 애플리케이션은 연락처 리스트, 연락처 조회 화면, 연락처 편집 화면 등 여러 개의 화면을 보여 주고 있다. 각 화면을 옮겨가면서 새로운 액티비티가 시작된다. 때때로 액티비티는 이전의 화면에 어떤 값을 넘겨줄 수도 있어야 한다.
액티비티는 애플리케이션 컴포넌트 중 가장 중요한 역할, 사용자의 입력을 받고 사용자에게 그 결과를 보여주는 등 실질적으로 사용자와 상호작용을 하는 역할을 맡고 있다. 따라서 액티비티 구성은 애플리케이션 개발에서 가장 신경 써야 할 부분이기도 하다. 기본적으로 안드로이드가 휴대용 기기에서 돌아가는 것을 목적으로 하는 플랫폼이기 때문에 PC 와 비교해 메모리가 부족할 수밖에 없다. 그러다보니, 한 번에 여러 가지의 작업을 하다가 메모리가 부족해지면 우선순위가 낮은 작업은 메모리를 반환하여 다른 작업을 수행할 수 있도록 한다.
메모리 관리를 위해 액티비티는 액티비티 생애 주기(Activity Lifecycle)에 따라 사용자와 상호작용을 하지 않는 액티비티를 비활성화 시키거나 종료시킬 수 있다. 이러한 특성 때문에 액티비티를 구성할 때 각 액티비티의 상태변화에 따라 적절한 처리를 해주는 것이 중요하다.
2.1 액티비티 라이프 사이클
액티비티는 처음 생성되어 실행을 마치기 전까지 다양하게 상태(state)가 변환되는 과정이 라이프 사이클이며 액티비티에 상태 변화가 있을 때마다 다양한 이벤트들이 발생하는데 이때 특정의 메소드가 호출된다. 다음은 액티비티의 상태 변화에 따른 이벤트 메소드이다.
▣ onCreate()
onCreate() 메소드는 액티비티의 초기화를 담당하고 위젯 인스턴스의 생성 및 값 설정한다. 일반적으로 액티비티의 레이아웃을 설정하는 메소드인 setContentView() 메소드가 존재한다. 데이터베이스 초기화, 리스트 어댑터 초기화 등의 작업을 수행한다.
▣ onStart()
onStart()는 액티비티가 화면에 표시된다. 사용자와의 상호작용(버튼 누르기, EditText에 문자열 입력 등)은 불가능하다.
▣ onResume()
사용자와의 상호작용 가능해진다. 실질적으로 액티비티가 제 기능을 수행할 수 있게 되는 시점이 된다. Activity가 활동 스택의 제일 위에 놓이고 포그라운드 프로세스가 되었을 때를 말하며 Activity의 필요한 자원을 준비한다. 오디오, 동영상, 애니메이션을 시작한다.
▣ onPause()
사용자와의 상호작용이 중지된다. 화면에서는 아직 보이는 상태로 액티비티 종료를 대비해 상태를 저장하는 등의 작업을 수행한다. 메모리가 부족할 경우 종료될 수 있다. 다른 Activity가 화면의 일부를 가려졌을 때를 말한다. 다이얼로그, 전화, SMS 등이 Activity의 일부를 가리게 되면 onResume()에서 시작한 오디오, 동영상, 애니메이션 중지된다.
▣ onStop()
액티비티가 화면에서 보이지 않는 상태로 메모리가 부족할 경우 종료될 수 있다.
▣ onRestart()
onStop() 메소드 호출 이후 정지상태에 있던 액티비티를 다시 화면에 표시할 때 호출된다.
▣ onDestroy()
finish() 메소드를 통해 액티비티가 종료될 때 호출된다. 액티비티가 종료될 때 항상 호출된다는 보장은 없다.
다음은 생애주기에 따른 분류를 다이어그램으로 표시한 것이다.
액티비티가 생성되면 onCreate() 메소드를 호출하고 액티비티가 종료 되면 onDestroy() 메소드가 호출되는데 onDestroy() 메소드가 호출될 때까지를 액티비티의 생존기간으로 보며 onCreate() 메소드에서 데이터를 초기화하고 onDestroy() 메소드에서 자원을 해제한다.
onStart() 메소드가 호출되면 액티비티는 표시되어 있는 상태가 되고 onStop() 메소드가 호출되면 액티비티는 더 이상 표시되지 않는다. onResume() 메소드가 호출되면 액티비티는 포그라운드 상태가 되며 onPause() 메소드가 호출되면 더 이상 포그라운드 상태가 아니다. 하지만 onStop() 메소드는 호출되지 않았으므로 포그라운드 상태는 아니지만 여전히 액티비티는 보인다. 백그라운드 상태의 액티비티가 포그라운드가 되려면 onRestart() 메소드를 호출해야 한다.
2.2 액티비티 스택
안드로이드에서는 사용자 인터페이스 화면(윈도우)을 제어하기 위한 Activity라는 이름의 클래스를 제공한다. Activity 클래스는 adroid.app 패키지에 속하며 2장에서 학습한 예제에서 이미 사용했는데 이 클래스가 setConentView() 메소드를 통해 UI를 화면에 표시한다는 정도만 언급하였다.
안드로이드 어플리케이션은 다양한 기능을 제공해주기 위해서 화면을 전환한다. 이러한 화면 전환을 하기 위해서 애플리케이션을 작성하면서 여러 개의 액티비티를 사용하게 된다.
이러한 여러 개의 액티비티의 상태는 액티비티 스택(activity stack)에 의해서 관리된다. 스택은 LIFO(Last Input First Output, 후입선출) 구조로 동작한다. 다음은 액티비티가 어떻게 스택 방식에서 관리되는지를 보여주는 그림이다.
화면이 변경되는 경우 이전 액티비티는 액티비티 스택에 저장되고 액티비티 스택을 이용하여 이전 화면으로 전환이 가능하다.
2.3 액티비티 상태
안드로이드 시스템은 애플리케이션 프로세스를 관리하다가 메모리가 부족해지면 오래된 프로세스를 제거한다. 각 프로세스가 제거될 때 어느 프로세스를 먼저 제거할 것인지 판별하는 기준은 사용자가 그 프로세스를 사용하고 있느냐가 중요한 기준으로 작용한다.
일반적으로 액티비티가 수행되고 있을 때 그 중요도에 따라 4개의 프로세스 상태로 분류할 수 있다. 이러한 4 상태의 분류 중 시스템은 덜 중요한 프로세스를 먼저 제거한다.
1) 포그라운드 액티비티(foreground activity)
사용자가 현재 조작중인 최상위 화면의 액티비티를 포그라운드 액티비티라고 하며 가장 중요한 프로세스이다. 이 프로세스는 메모리가 부족해지더라도 제일 마지막에 제거된다.
2) 가시 상태의 액티비티(visible activity)
사용자 화면에는 보여지지만 포그라운드는 아닌 것을 가시 상태의 액티비티라고 한다. 예를 들면 포그라운드 다이얼로그의 뒤에 있는 액티비티를 생각하면 된다. 가시 상태의 액티비티는 포그라운드 액티비티 다음으로 중요하다.
3) 백그라운드 액티비티(background activity)
백그라운드 액티비티는 사용자에게 보여 지지 않고 멈추어진 것이다. 따라서 더 이상 중요하지 않으며 시스템은 포그라운드 또는 visible 프로세스가 메모리를 요구하면 백그라운드 액티비티를 안전하게 제거시킬 수 있다.
4) 빈 프로세스(empty process)
서비스 또는 브로드캐스트리시버 클래스와 같이 액티비티도 없고 애플리케이션 컴포넌트도 없는 것을 빈 프로세스라고 한다. 이들 프로세스들은 메모리가 부족해지면 시스템에 의해 즉시 제거된다. 이러한 이유로 액티비티 밖에서 수행되는 임의의 백그라운드 연산은 액티비티 브로드캐스트리시버 또는 서비스의 컨텍스트 내에서 실행되어야만 한다.
2.4 상태 변화 모니터링
Log 클래스는 안드로이드 시스템 로그에 심각도 수준을 출력하는 여러 정적 메서드를 제공한다. 다음은 Log 클래스가 제공해주는 메소드이다.
메소드 |
설명 |
Log.e() |
오류(errors) |
Log.w() |
경고(warnings) |
Log.i() |
정보(information) |
Log.d() |
디버깅(debugging) |
Log.v() |
세부정보(verbose) |
Windows > Show View > Other> 메뉴를 선택한 후 Android > LogCat을 선택하면 열수 있다.
소스에 Log.d() 메소드에 넣은 메시지를 디버깅 혹은 DDMS 화면 밑 부분에 LogCat이라는 영역에서 확인할 수 있다.
Log.d("test","onCreate()"); |
이것은 개발할 때 필요한 로그를 출력해주는 역할을 한다. 그런데 로그가 너무 많이 나와서 복잡하다. 작성한 어플리케이션에서 나오는 메시지만을 따로 확인하기 위해서 필터를 적용할 수 있다. Log.d() 메소드의 첫 번째 인자인 Tag 부분을 이용해서 가능하다. 녹색 + 모양을 눌러 Filter를 생성한다. Log Filter라는 창에서 Filter Name은 적당히 적은 후, 따로 메시지를 확인할 Tag부분을 "test"로 적어서 OK를 한다. 이제 LogCat 창 안에 새로운 필터 탭이 생겨서 "test"라는 Tag를 가지는 메시지는 따로 분류해서 보여준다.
<실습> 액티비티의 생명주기 이해하기
1. 이클립스에서 [File]→[New]→[Android Project] 메뉴를 선택하여 새로운 Android Project를 작성한 후 다음과 같이 메소드를 오버라이딩한 후에 다음과 같이 코딩한다.
01: 02: 03: 04: 05: 06: 07: 08: 09: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73:74: 75: 76: |
package com.example.activityLifeCycle; import! android.app.Activity; import! android.os.Bundle; import! android.util.Log; import! android.view.View; import! android.view.View.OnClickListener; import! android.widget.Button; public class ActivityLifeCycle extends Activity { private Activity activity; // 전체 수명의 시작 시에 호출됨 @Override public void onCreate(Bundle savedInstanceState) { // 액티비트를 초기화한다. super.onCreate(savedInstanceState); activity=this; setContentView(R.layout.main); Log.d("activity life cycle","onCreate()"); }
// 가시 수명으로 이어기지 건 액티비티 처리를 위해 호출 @Override protected void onRestart() { // 액티비티가 이미 화면에 보이고 있다고 생각하고 // 여기서 변경된 내용을 읽어 들인다. Log.d("activity life cycle","onRestart()"); super.onRestart(); }
// 가시 수명 시작 시 호출됨 @Override protected void onStart() { // 이제 액티비티가 화면에 보이므로, 필요한 UI 변경 사항을 적용한다. Log.d("activity life cycle","onStart()"); super.onStart(); }
// 활성 수명 시작 시 호출됨 @Override protected void onResume() { // 일시 중지된 모든 UI 업데이트나 스레드 // 혹은 액티비티에 의해 필요하지만 // 액티비티가 비활성화되면서 일시 중단된 처리를 재개한다. Log.d("activity life cycle","onResume()"); super.onResume(); }
// 활성 수명 끝에서 호출됨 @Override protected void onPause() { // 액티비티가 활성 상태의 포그라운드 액티비티가 아닐 경우 // 업데이트될 필요가 없는 UI 얻데이트나 스레드 // 혹은 CPU를 많이 사용하는 처리를 일시 중단한다. Log.d("activity life cycle","onPause()"); super.onPause(); }
// 가시 수명 끝에서 호출됨 @Override protected void onStop() { // 남아 있는 UI 업데이트나 스레드 혹은 액티비티가 화면에 보이지 않을 때 // 필요치 않은 처리를 일시 중단한다. 이 메소드가 호출되고 난 뒤에는 // 프로세스가 종료될 가능성이 있으므로 바뀐 모든 내용과 상태 변화를 지속시킨다. Log.d("activity life cycle","onStop()"); super.onStop(); }
//전체 수명 끝에서 호출 @Override protected void onDestroy() { // 스레드를 종료하고 데이터베이스 연결을 닫는 등 모든 리소를 해제한다. Log.d("activity life cycle","onDestroy()"); super.onDestroy(); } } |
2. DDMS(Dalvik Debug Monitor Service) 퍼스펙티브로 전환하여 로우캣(LogCat) 화면에 이벤트 동작에 관련된 정보가 출력해 보자. DDMS(Dalvik Debug Monitor Service) 퍼스펙티브로 전환한다. 그런 후에 디버그 정보를 보기 위해서는 [Run]-[Debug]를 선택하거나 [F11]키를 누른다. 로우캣(LogCat) 화면에 이벤트 동작에 관련된 정보가 출력된다.
Section 03. 리소스 외부화
리소스로 사용 가능한 리소드에는 문자열, 색, 이미지, 오디오, 비디오, 텍스트 문자열, 레이아웃, 테마 등이 있다. 이번 절에서는 이들 각각을 어떻게 다루어야 하는지 살펴보도록 한다.
3.1 Values 리소스 생성하기
문자열은 res/values 디렉토리에 둔 XML파일의 <resources> 엘리먼트 내에 <string> 엘리먼트를 사용하여 정의한다. 서식은 다음과 같다.
<string name=str_name>string_value</string> |
(1) 문자열 배열
이번에는 문자열들을 배열 형태로 저장하는 것을 다루어 보도록 한다. 문자열 배열은 메뉴나 리스트 목록의 값으로 사용된다. /res/values/arrays.xml에 정의한다. getStringArray() 메서드를 이용해서 문자열 배열에 접근한다.
<실습> Array 리소스 사용
1. ResourceLab01란 이름으로 안드로이드 프로젝트를 생성한 후에 다음과 같이 레이아웃을 설계한다.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:id="@+id/TextView01" android:layout_width="fill_parent" android:layout_height="wrap_content"/> <TextView android:id="@+id/TextView02" android:layout_width="fill_parent" android:layout_height="wrap_content"/> </LinearLayout> |
2. “res/values”디렉토리의 strings.xml 파일을 다음과 같이 수정한다.
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">String Array Resource</string> <string name="phone01">GALAXY A</string> <string name="phone02">MOTOROI</string> <string name="phone03">SIRIUS</string> </resources> |
3. values 폴더에 arrays.xml 파일을 추가하기 위해서 프로젝트 탐색기에서 [File] -> [New] -> [Android XML File] 메뉴를 선택한다. File:에 “arrays.xml”를 입력하고 Values를 선택한 후 <Finish> 버튼을 누른다.
4. <Add..> 버튼을 누른 후 String Array를 선택한 후 <Ok>버튼을 누른다. Name:에 smart_phone을 입력한다.
5. <Add..> 버튼을 누른 후 <Ok> 버튼을 누른다. item 엘리먼트가 추가되었다면 Value 에 “omnia:를 입력한다. 5번을 반복해서 item 엘리먼트를 3개 더 추가한다.
6. XML 리소스 파일인 array.xml에 직접 배열을 선언해서 "smart_phone" string-array 엘리먼트를 추가해 보았다. 이번에는 "android_phone" string-array 엘리먼트를 strings.xml에서 String 리소스를 참조해서 만들어 보자.
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="smart_phone"> <item>omnia</item> <item>android</item> <item>iPhone</item> </string-array> <string-array name="android_phone"> <item>@string/phone01</item> <item>@string/phone02</item> <item>@string/phone03</item> </string-array> </resources> |
7. 액티비티를 위한 자바 소스에 다음과 같이 입력한다.
package com.example.stringArrayResource;
import! android.app.Activity; import! android.os.Bundle; import! android.util.Log; import! android.widget.TextView;
public class ResourceActivity extends Activity { private static final String DEBUG_TAG= "ResourceActivity Log"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);
String result=""; String result2="";
String[] smartPhone = getResources().getStringArray(R.array.smart_phone);
for(int i=0; i<smartPhone.length; i++){ Log.d(DEBUG_TAG, "smartPhone["+ i + "] value is: "+ smartPhone[i]); result+=smartPhone[i]+","; } TextView tv01=(TextView)findViewById(R.id.TextView01); tv01.setText("smartPhone: "+result);
String[] android_phone = getResources().getStringArray(R.array.android_phone);
for(int i=0; i<android_phone.length; i++){ Log.d(DEBUG_TAG, "android_phone["+ i + "] value is: "+ android_phone[i]); result2+=android_phone[i]+","; } TextView tv02=(TextView)findViewById(R.id.TextView02); tv02.setText("android_phone: "+result2); } } |
(2) 색
색은 res/values 디렉토리에 둔 XML파일의 <resources> 엘리먼트 내에 <color> 엘리먼트를 사용하여 정의한다. 문자의 색이나 텍스트 뷰의 백그라운드 색상 등의 지정에 사용한다. 서식은 다음과 같다.
<color name=color_name>#color_value</color> |
색상 값을 정의하는 형태는 항상 “#”으로 시작한다. 그 뒤에는 RGB를 나타내는 16진수를 연속해서 사용한다. RGB 외에 투명도를 표현하는 파일값(A)를 붙일 수도 있다. ARGB(Alpha Red Green Blue) 각각의 값은 1행이 2행의 어디로든 표현할 수 있기 때문에 결국 아래 4가지 종류의 형식으로 사용할 수 있다.
형식 |
예 |
의미 |
#RGB |
#F00 |
12비트의 red 색상을 의미한다. |
#ARGB |
#8F00 |
12비트의 Alpha 50 퍼센트의 red 색상을 의미한다. |
#RRGGBB |
#FF00FF |
24비트의 magenta 색상을 의미한다. |
#AARRGGBB |
#80FF00FF |
24비트의 Alpha 50 퍼센트의 magenta 색상을 의미한다. |
다음은 색을 정의하는 예이다. 파일명은 보통 colors.xml로 한다.
<?xml version="1.0" encoding="UTF-8"?> <resources> <color name="prettyTextColor">#ff0000</color> <color name="prettyBackgroundColor">#00ff00</color> </resources |
정의한 색을 프로그램에서 참조하려면 getResource() 메소드에서 불러낸 리소스 클래스의 getColor() 메소드를 사용한다.
int myResourceColor = getResources().getColor(R.color.prettyTextColor); |
정의한 색을 다른 리소스파일에서 참조하려면 “@color/”로 정의한 이름을 연결하여 지정한다.
<TextView ... android:background="@color/prettyBackgroundColor”/> |
(3) 크기
크기란 사이즈에 이름을 부여하는 것이다. 예를 들면 자주 사용하는 문자의 사이즈를 small_size나 large_size라는 이름으로 지정해 두면 small_size의 정의를 바꿔 쓰는 것만으로 크기를 한 번에 변경할 수 있다. 크기는 res/values 디렉토리에 둔 XML 파일의 <resources> 엘리먼트 내에, <dimen> 엘리먼트를 사용하여 정의한다. 서식은 다음과 같다.
<dimen name=dimen_name>dimen_value</dimen> |
크기에 사용할 수 있는 단위는 다음과 같다.
표기 |
단위 |
의미 |
px |
픽셀 수 |
사용 중 화면에서의 픽셀 수, 해상도가 높아지면 픽셀의 물리적인 크기가 줄어든다. |
in |
인치 |
사용 중 화면에서의 인치단위의 길이 |
mm |
미리 미터 |
사용 중 화면에서의 미리 미터 단위의 길이 |
pt |
포인트 수 |
사용 중 화면에서의 1/72 인치를 1포인트로 하는 길이 |
dp |
해상도 의존하지 않는 픽셀 수 |
1는 해상도가 160dpi일 때 1픽셀. 10dp가 160dpi일 때에는 10픽셀, 320dpi일 때에는 20픽셀 |
sp |
폰트 사이즈를 고려한 픽셀 수 |
사용자가 설정하고 있는 폰트사이즈를 고려한 스케일된 픽셀 수. 실제 픽셀 수는 사용 중 화면의 해상도와 폰트 사이즈에 의해 변함 |
<팁> dpi란
dpi는 Dot Per Inch의 약자로 1인치(2.54cm)당 들어가는 점의 수를 말한다. 이 값이 클수록 같은 공간 안에 더 많은 점이 있어서 더 선명하다. 즉, 150dpi보다 300dpi가 더 선명하다.
</팁>
크기를 정의하는 파일명은 일반적으로 dimens.xml으로 한다.
<?xml version="1.0" encoding="UTF-8"?> <resources> <dimen name="small_size">8sp</dimen> <dimen name="large_size">32sp</dimen> </resources> |
정의한 사이즈를 프로그램에서 참조하려면 Context 클래스의 메소드를 사용한다.
float dimen = getResources().getDimension(R.dimen.large_size); |
정의한 사이즈를 다른 리소스파일에서 참조하려면 “@dimen/”에 정의한 이름을 붙여 지정한다.
<TextView ... android:textSize="@dimen/large_size" /> |
(4) 드로우어블
안드로이드에서는 PNG 이미지 파일을 사용하기를 권하지만 JPEG와 GIF 파일도 사용할 수 있다. 이미지파일은 res/drawable 디렉토리에 두고 BitmapDrawable의 클래스로 참조할 수 있다. 해당 이미지 파일을 프로그램에서 사용할 경우에는 확장자를 제거한 채 파일명만 기술해야한다. 예를 들면 res/drawable/icon.png라는 이미지 리소스를 프로그램에서 사용하려면 getResource() 메소드로 리소스 클래스를 불러낸 후에 getDrawable() 메소드를 사용한다.
Drawable icon = getResources().getDrawable(R.drawable.icon); |
이미지를 다른 리소스 파일로부터 참조하려면 “@drawable/”로 파일명만 기술한다.
<ImageView ... android:src="@drawable/icon"/> |
안드로이드는 나인패치 NinePatch 그래픽이라 불리는 확대 가능한 비트맵 이미지를 지원한다. 이것은 PNG 이미지이며, 여러분은 그 안에 확대 가능한 stretchable 섹션을 정의하며, 안드로이드는 디스플레이 시점에 이 오브젝트를 텍스트 문자열과 같은 가변적 크기 섹션을 수용할 수 있도록 크기를 변경할 것이다. 여러분은 일반적으로 뷰의 백그라운드에 이 리소스를 할당한다. 확대 가능한 Stretchable 이미지의 사용 예제는 안드로이드가 사용하는 버튼 백그라운드이다. 버튼은 다양한 길이의 문자열을 수용하기 위해 확대되어야 한다.
(5) 드로우어블
색 영역이란 색을 지정한 정방형의 영역이다. res/values 디렉토리에 둔 XML파일의 <resources> 엘리먼트 내에 <drawable> 엘리먼트를 사용하여 정의하면 PaintDrawable 객체가 이를 레퍼런스 한다.
<drawable name=color_name>color_value</drawable> |
다음은 색 영역을 정의한 예이다. 파일명은 보통 drawable.xml로 한다. 녹색의 영역을 정의하고 있다.
<?xml version="1.0" encoding="UTF-8"?> <resources> <drawable name="greenDrawable">#0f0</drawable> </resources |
정의한 색 영역을 프로그램에서 참조하려면 getResource() 메소드에서 불러낸 리소스 클래스의 getDrwable() 메소드를 사용한다.
ColorDrawable myResourceDrawable = (ColorDrawable)getResources(). getDrawable(R.drawable.greenDrawable); |
정의한 색 영역을 다른 리소스로부터 참조하려면 “@drawable”로 정의한 이름을 연결하여 지정한다.
<TextView ... android:background="@drawable/greenDrawable" /> |
<실습> 색, 크기, 색영역 리소스 사용
1. ColorDemendDrawableResource란 이름으로 안드로이드 프로젝트를 생성한 후에 다음과 같이 레이아웃을 설계한다.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" android:id="@+id/TextView01"/> <ImageView android:id="@+id/ImageView01" android:layout_width="200px" android:layout_height="300px" /> </LinearLayout> |
2. “res/values”디렉토리의 strings.xml 파일을 다음과 같다.
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">ColorDemendResource</string> <string name="hello">Hello Resource!</string> </resources> |
3. [New] -> [Android XML File] 메뉴를 선택한다. values를 선택한 후 파일명을 colors.xml로 기술한 후 다음과 같이 입력한다.
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="prettyTextColor">#ff0000</color> <color name="prettyBackgroundColor">#00ff00</color> </resources |
4. [New] -> [Android XML File] 메뉴를 선택한다. values를 선택한 후 파일명을 dimen.xml로 기술한 후 다음과 같이 입력한다.
<?xml version="1.0" encoding="utf-8"?> <resources> <dimen name="textPointSize">18pt</dimen> </resources> |
5. [New] -> [Android XML File] 메뉴를 선택한다. values를 선택한 후 파일명을 drawables.xml로 기술한 후 다음과 같이 입력한다.
<?xml version="1.0" encoding="utf-8"?> <resources> <drawable name="greenDrawable">#0f0</drawable> </resources> |
6. 액티비티를 위한 자바 소스에 다음과 같이 입력한다.
package com.example.colorDrawable;
import! android.app.Activity; import! android.graphics.drawable.ColorDrawable; import! android.os.Bundle; import! android.util.Log; import! android.widget.ImageView; import! android.widget.TextView;
public class ResourceActivity extends Activity { private static final String DEBUG_TAG= "ResourceActivity Log"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);
int myResourceColor = getResources().getColor(R.color.prettyTextColor); float myResourceDimension = getResources().getDimension(R.dimen.textPointSize);
TextView tv01=(TextView)findViewById(R.id.TextView01); tv01.setBackgroundColor(myResourceColor); tv01.setTextSize(myResourceDimension);
ColorDrawable myResourceDrawable = (ColorDrawable)getResources().getDrawable(R.drawable.greenDrawable); ImageView iv01=(ImageView)findViewById(R.id.ImageView01); iv01.setImageDrawable(myResourceDrawable);
Log.d(DEBUG_TAG, "myResourceColor value is: " + myResourceColor); Log.d(DEBUG_TAG, "myResourceDimension value is: " + myResourceDimension); Log.d(DEBUG_TAG, "myResourceDrawable value is: " + myResourceDrawable.getAlpha()); } } |
3.2 리소스 사용하기
(1) 코드에서 리소스 사용하기
코드에서 리소스를 사용하려면 정확한 리소스 ID와 여러분의 리소스가 컴파일된 오브젝트의 타입을 알아야 한다. 여기에 리소스를 레퍼런스하는 것에 대한 구문이 있다.
R.resource_type.resource_name |
위의 구문에서 resource_type은 R의 서브 클래스로서 리소스 타입에 따라 그 이름이 결정된다. resource_name는 XML 파일에서 정의된 리소스에 대한 name 애트리뷰트이거나, 또는 다른 파일 타입에 의해 정의된 리소스에 대한 파일 이름(확장자 없이)이다. 예를 들어 strings.xml의 string 엘리먼트 중 name 속성이 hello인 리소스를 얻기 위해서는 다음과 같이 기술한다.
R.string.hello |
자신의 애플리케이션에 의해 컴파일된 리소스는 패키지 이름 없이(단순히 R.resource_type.resource_name으로) 레퍼런스될 수 있다. 자바 코드에서는 이 필드로 문자열을 얻기 위해서는 다음과 같은 메서드를 사용해야 한다.
String strHello = getResources().getString(R.string.hello); |
getResource() 메소드는 응용프로그램의 리소스를 관리하는 android.content.res.Resources 객체를 리턴하고 getString() 메소드는 아이디에 해당하는 문자열을 리턴한다.
(2) 리소스에서 리소스 사용하기
리소스에서 다른 리소스를 참조하려면 @로 시작하는 ID를 사용한다. 예를 들면 액티비티를 구성하는 레이아웃의 리소스인 main.xml를 예로 들어 보자.
이 리소스 안의 텍스트 필드에 표시하는 문자로서 strings.xml 내의 <string name=”hello”>Hello World, HelloAndroidActivity</string>에 있는 문자열을 지정하고 싶다고 하자. 그럴 경우는 android:text=”@string/hello”와 같이 지정한다.
일반적으로 리소스ID는 다음과 같이 “@”을 붙여서 참조한다.
@[package:]type/name |
같은 애플리케이션 패키지 내의 리소스의 경우는 패키지 명을 생략할 수 있다. 예를 들면 <color name=”opaque_red”>#ff0000</color>로 정의된 리소스를 TextView의 문자 색으로 지정한다면 다음과 같이 코딩한다.
<TextView ... android:textColor="@color/opaque_red” /> |
시스템에서 정의된 리소스는 패키지로서 android를 지정한다. 시스템에서 정의된 Android.R.color.primary_text_dark라는 필드의 경우에는 @android라는 패키지명으로 시작한다.
<TextView ... android:textColor="@android:color/primary_text_dark” /> |
(3) 시스템 리소스 사용하기
시스템에 포함된 많은 리소스는 애플리케이션에서도 사용가능하다. 그런 리소스 전부는 “android.R” 클래스 안에 정의되어 있다. 이것을 레퍼런스하기 위해서 다음과 같이 android를 덧붙여야 한다.
android.R.resource_type.resource_name |
안드로이드에서 버튼의 백그라운드를 지정하는 표준 리소스를 레퍼런스하기 위해서 다음과 같이 기술해야 한다.
android.R.drawable.button_background |
다음은 시스템에 의해 정의된 표준 “블랙(black) 백그라운드” 시각적 효과를 여러분의 스크린에 적용한 것이다.
public class MyActivity extends Activity{ public void onStart(){ super.onStart(); setTheme(android.R.style.Theme_Black); } } |
(4) 현재 태마에서 스타일 사용하기
애플리케이션을 디자인할 때, 각종 화면 및 UI 엘리먼트에 단일한 포맷을 적용하기 위해 스타일과 테마를 사용할 수 있다. 스타일은 하나의 엘리먼트에 적용되는 하나 또는 그 이상의 속성에 이름을 붙인 것으로서 여러 개의 액티비티에서 일관성 있는 스타일을 적용하고자 할 때 사용한다. 예를 들어 특정 텍스트 크기와 그리고 컬러를 지정하는 스타일을 정의할 수 있고, 그런 다음 그것을 특정 유형의 뷰 엘리먼트의 인스턴스에 적용할 수 있다.
테마는 전체 스크린에 적용되는 하나 또는 그 이상의 애트리뷰트이다. 예를 들어 여러분은 액티비티가 스크린에 떠 있는 다이얼로그 박스가 되도록 디자인하기 위해, 안드로이드 Theme.dialog 테마를 스톡을 적용할 수 있는데 테마는 매니페스트 파일에 있는 activity의 애트리뷰트로 지정된다.
만일 2개 이상의 액티비티나 여러 개의 위젯에 강조를 위해 볼드에 18px 크기의 초록색으로 표현하도록 설정했다고 하자. 강조를 위해서 초록색을 빨간색으로 변경하려고 한다면 일일이 속성을 변경해야 한다. 하지만, 스타일로 지정해 놓고 강조를 위한 위젯에 이 스타일을 적용시켜두었다면 스타일에서 초록색을 빨간색으로만 바꾸면 간단하게 모든 강조를 위한 위젯에 적용할 수 있다.
스타일은 res/values 디렉토리에 둔 XML파일로 파일 이름은 styles.xml이어야만 한다. XML 파일의 <resources> 엘리먼트 내에 <style> 엘리먼트를 사용하여 정의한다. 서식은 다음과 같다.
<style name=string [parent=string] > <item name=string>Hex value | string value | reference </item> </style> |
style 엘리먼트는 하나 또는 그 이상의 <item> 엘리먼트를 보유하며, 그것들 각각은 하나의 값을 설명하고 있다. 이 값들에 대한 하나의 묶음인 스타일은 테마로써 레퍼런스될 수도 있다. 속성인 name은 이 테마를 가리키는데 사용되는 이름이 되고, parent 속성은 선택사항인 parent 테마로서 지정된 테마의 모든 값들은 이 테마로 상속될 것이다. 여러분이 지정한 동일한 이름을 갖는 임의의 값은 상속한 값을 오버라이딩한다.
<item> 엘리먼트는 이 아이템에서 사용되는 값을 기술한다. 표준 문자열, 16진수 컬러 값, 또는 임의의 다른 리소스 타입에 대한 레퍼런스가 될 수 있다.
스타일과 테마는 리소스들로서 안드로이드는 여러분이 사용할 수 있는 약간의 디폴트 스타일과 테마 리소스들을 제공한다. 하지만 필요하다면 자신의 커스텀 스타일과 테마 리소스들을 정의할 수도 있다.
커스텀 스타일과 테마를 만들기 위해서는 다음과 같은 과정을 거쳐야 한다.
여러분의 애플리케이션의 res/values 디렉토리에 styles.xml이라는 이름의 파일을 만든 후에 파일 안에 <resources> 루트(root) 노드를 추가한다. 각 스타일 또는 테마에 대해, 고유한 name과 선택 사항으로 parent 애트리뷰트를 가지는 <style> 엘리먼트를 추가한다. name은 나중에 이 스타일을 레퍼런스하기 위해 사용되며, parent는 스타일 리소스가 상속받을 스타일을 지정한다. <style> 엘리먼트 내부에, 하나 또는 그 이상의 <item> 엘리먼트에 포맷 값들을 정의한다. 각각의 <item>은 name 속성을 가지고 그것의 스타일 속성을 구분하며, 해당 엘리먼트 안에 그것의 값을 정의한다. 다른 XML 리소스, 여러분의 매니페스트 또는 애플리케이션 코드로부터 커스텀 리소스를 레퍼런스할 수 있다. |
다음은 스타일을 정의한 예로서 18sp 크기의 진한 녹색으로 문자의 스타일을 specialText이라는 이름으로 정의하고 있다. 파일명은 보통 styles.xml로 하여 res/values 디렉토리에 저장해 둔다.
<?xml version="1.0" encoding="utf-8"?> <resources> <style name="specialText" parent="@style/Text"> <item name="android:textSize">18sp</item> <item name="android:textStyle">bold</item> <item name="android:textColor">#80ff80</item> </style> </resources> |
스타일에 대한 특정 형태 값들을 지정하기 위해 <item> 엘리먼트를 사용할 수 있다. item의 name 속성은 표준 문자열, 16진수 컬러 값, 또는 임의의 다른 리소스 타입에 대한 레퍼런스를 참조할 수 있다. <style> 엘리먼트에 있는 parent 속성은 어떤 리소스로부터 현재 스타일이 값들을 상속할 것인가를 여러분이 지정할 수 있게 한다. 스타일은 여러분이 원하는 스타일을 포함하는 어떤 유형의 리소스로부터도 상속할 수 있다.
XML 레이아웃에서 커스텀 스타일을 레퍼런스하는 방법을 살펴보자. EditText 엘리먼트에서 스타일을 사용할 경우에는 정의한 스타일을 레이아웃 리소스로부터 참조하려면 “@style/”로 정의한 이름을 붙여서 지정한다.
<EditText id="@+id/EditText01" style="@style/specialText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Hello, World!" /> |
다음으로는 애플리케이션 전체 스타일을 설정하는 테마에 대해 설명하겠다. 스타일과 같이 테마 또한 XML <style> 엘리먼트로 선언되며, 그리고 같은 방식으로 레퍼런스된다. 그 차이는 여러분이 테마를 안드로이드 매니페스트 내에 있는 <application>과 <activity> 엘리먼트를 통해, 전체 애플리케이션 또는 액티비티에 추가한다. 테마는 개별적인 뷰에는 적용될 수 없다.
<?xml version=”1.0” encoding=”utf-8”?> <resources> <style name=”CustomTheme”> <item name="panelForegroundColor">#FF000000</item> <item name="panelTextColor">?panelForegroundColor</item> <item name"panelTextSize">14</item> <item name="menuItemTextColor">?panelTextColor</item> <item name=”menuItemTextSize”>?panelTextSize</item> </style> </resources> |
리소스를 레퍼런스하기 위한 @ 심볼과 ? 마크가 사용된다. @ 심볼은 이전에 다른 곳(이것은 현재 프로젝트이거나 또는 안드로이드 프레임워크일 수 있음)에서 정의된 리소스를 레퍼런스할 때 사용한다. ? 마크는 현재 로드된 테마에서의 리소스 값을 XML 리소스에서 레퍼런스할 때 사용한다. 위 예에서 보면 panelTextColor에 panelForegroundColor 테마를 사용하기 위해서 ?를 붙인 것을 확인할 수 있다.
애플리케이션의 모든 액티비티에 대해 이 테마를 설정하기 위해서는, AndroidManifest.xml 파일을 오픈해서 <application> 태그를 편집해서 테마 이름을 가지는 android:theme 속성을 포함시킨다.
<application android:theme=”@style/CustomTheme”> |
애플리케이션에 있는 오직 하나의 액티비티에만 테마를 적용하고 하고자 한다면, 대신 <activity> 태그에 그 테마 애트리뷰트를 추가한다. 안드로이드는 다른 내장된 리소스를 제공하기 때문에, 직접 그것을 만들지 않고 추가할 수 있는 몇 가지 테마가 있다. 액티비티를 다이얼로그 박스처럼 만들기 위해 Dialog 테마를 사용할 수 있다고 하였는데 그러려면 매니페스트 내에서 다음과 같이 안드로이드 테마를 레퍼런스한다.
<activity android:theme=”@android:style/Theme.Dialog”> |
<실습> 스타일 테마 리소스 사용
1. 왼쪽 화면은 실행 결과이다. StyleAndThemaDemo란 이름으로 안드로이드 프로젝트를 생성한다,
2. res/values 디렉토리에 styles.xml을 생성하여 다음과 같이 코딩한다.
<?xml version="1.0" encoding="utf-8"?> <resources> <style name="specialText" > <item name="android:textSize">18sp</item> <item name="android:textStyle">bold</item> <item name="android:textColor">#80ff80</item> </style> </resources> |
3. main.xml 레이아웃을 다음과 같이 설계한다.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:text="@string/hello" android:layout_width="fill_parent" android:layout_height="wrap_content"/> <EditText android:id="@+id/EditText01" style="@style/specialText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Hello, World!"/> <EditText android:id="@+id/EditText02" style="@style/specialText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Hello, World!"/> </LinearLayout> |
4. AndroidManifest.xml 파일을 오픈해서 <application> 태그를 편집해서 테마 이름을 가지는 android:theme 속성을 포함시킨다.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.styleAndThemaDemo" android:versionCode="1" android:versionName="1.0"> <application android:theme="@android:style/Theme.Dialog" android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".StyleAndThemaDemo" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="3" /> </manifest> |
5. 액티비티를 위한 자바 소스에 다음과 같이 입력한다.
package com.example.styleAndThemaDemo; import! android.app.Activity; import! android.os.Bundle; public class StyleAndThemaDemo extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } } |
'스마트폰공부' 카테고리의 다른 글
[스크랩] 지금은 모바일 시대. 모바일 지원 안 하는 블로그를 모바일로 변환하기 (0) | 2010.12.22 |
---|---|
[스크랩] QRcode 쉽게 만들어 사용하기 (0) | 2010.12.22 |
[스크랩] WithBanner상품배너 제작기 프로그램 (0) | 2010.12.22 |
[스크랩] 트위터 사용방법 (0) | 2010.12.22 |
[스크랩] 01. 안드로이드란 무엇인가? (0) | 2010.12.22 |