티스토리 툴바


달력

01

« 2012/01 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  •  
  •  
  •  
  •  

안드로이드의 HW configuration에서 LCD density라는 환경 설정 값을 가지고 있습니다기본적으로 이 값은 160입니다. (DEFAULT).

도넛 버전 이전에는 공식적으로 HVGA만 지원을 했고 도넛부터WGVA등이 추가되었습니.

이와 함께 LCD density 120 (LOW) 240 (HIGH) 두 개가 추가되었습니다.

아래 이미지들은 WVGA 해상도에서 LCD density 160 240인 경우를 비교해 놓은 것입니다.

보시듯이 LCD density 240일 경우 즉 고해상도에 LCD의 물리적인 사이즈가 변경이 거의 되지 않으며 HVGA랑 거의 동일한 look을 가지게 됩니다.

LCD density 160일 경우 MID같이 LCD의 물리적인 사이즈가 매우 커졌을 때 유용한 형태 인 것으로 생각됩니다.

(왜 이렇게 되는가는 표 아래쪽에 설명을 첨부하였습니다.)


Lcd.density = 160

Lcd.density = 240

Home

Apps List

Settings

실제 DPI 정보와는 약간 다른 단위가 안드로이드에 사용이 되고 있습니다.

DIP (또는 DP)라는 것으로 Device Independent Pixel의 약자입니다.

이는 디바이스의 LCD 해상도가 변경이 되어도 GUI 요소들의 물리적인 크기를 동일하게 유지하기 위한 방법입니다.

LCD density 160일 경우, 1 DIP = 1 Pixel 이라는 공식이 성립됩니다. (안드로이드가 HVGA, 160에서 출발해서 그렇습니다.)

따라서 이 density 값이 240으로 변경되면 1 DIP = 1.5 Pixel이 됩니다.

기본 생성되는 WVGA 에뮬레이터가 density 240으로 설정되어 있는데이 때문에 아이콘들이나 이미지들이 늘어나 보입니다.

(기존 20DIP x 20DIP 크기의 이미지가 HVGA (160)에서는 20pixel x 20 pixel로 보이지만 WVGA (240)에서는 30pixel x 20pixel 로 보이기 때문입니다.)

따라서 실제 물리적인 LCD의 크기가 많이 커지지 않고 해상도만 커진다면고해상도에서 더 많은 pixel을 차지하게 되므로 GUI 요소들의 실제 크기는 유사하게 유지시킬 수 있습니다. (예를 들면 저해상도 고해상도에서 모두 1인치)

Posted by 후니와갱

1. 스레드(Thread) 사용의 필요성

 

A. UI 스레드 (Thread)의 중요성

 

안드로이드에서 어플리케이션이 구동되면 main이라 불리는 스레드가 하나 생성된다. main 스레드는 UI 스레드(앞으로 이렇게 표기)라고도 불리며, 어플리케이션의 로직과 UI간의 상호작용을 돕고, 발생한 이벤트들을 위젯에게 전달해 처리 할 수 있게 하는 등 매우 중요한 역할을 담당한다.

 

 

예를 들면, 사용자가 버튼을 터치 했을 때 다음과 같은 일이 발생한다.

  • UI 스레드가 터치 이벤트를 버튼 위젯에게 전달한다.
  • 버튼 위젯은 자기 자신의 상태를 눌림(press)상태로 바꾸고 필요한 작업을 진행한다.
  • 버튼 위젯은 자기 자신을 다시 그리라는 메시지(invalidate)를 이벤트 큐(queue)에 등록한다.
  • UI 스레드는 이벤트 큐에 등록된 request를 버튼 위젯에게 전달한다.
  • 버튼 위젯은 자기 자신의 영역을 버튼 눌림 상태로 다시 그린다.

 

 

지금까지의 포스트 전에 사용한 모든 예제는 UI 스레드에서 모든 작업을 수행해왔다.

아주 간단한 작업들 이였기 때문에 별 문제가 없었지만 복잡한 작업(시간이 오래 걸리는)을 UI 스레드에서 수행하는 경우 어떤 상황이 발생하는지 보자.

 

 

 

B. UI 스레드에서 시간이 오래 걸리는 작업의 수행

 

어플리케이션을 개발하다 보면 어떤 작업들은 계산의 복잡도 때문에 또는 작업에 필요한 리소스가 늦게 준비되는 등의 이유로 리턴 시간이 오래 걸리는 경우가 많이 있다. 수학적으로 아주 복잡한 계산이 필요하거나, DB로부터 많은 정보를 끌어 올 때 등과 같은 경우에 수초에서 수분이 걸리는 작업을 수행해야 될 경우가 있다.

 

예를 들어 인터넷 사이트 상에서 용량이 적은 이미지를 다운 받아 화면에 표시하는 작업을 UI 스레드에서 구현 했다. 현재 네트워크 상황이 좋지 않아 이미지를 다운 받는데 20초 정도가 걸린다고 가정해 보자. 이미지를 다운받기 시작한 후 10초 정도 경과했을 때 기다리다 지친 사용자는 '취소' 버튼을 눌렀다. 하지만 사용자가 버튼을 눌렀을 때 발생하는 버튼 클릭 메시지를 취소 버튼에 전달하는 역할을 하는 UI 스레드는 이미지 다운로드 루틴에서 아직 리턴 하지 않았으므로 사용자가 새로 발생시킨 메시지를 처리 할 수 없는 상황이 발생해 버린다. 결과적으로 사용자는 중간에 취소 하고 싶어도 취소 할 수 없을뿐더러 20초 동안 아무 반응도 하지 않는 화면을 바라보고 있어야만 한다. 심지어는 이 시간 동안 전화가 온다고 하더라도 전화를 받지 못할 수도 있다.

 

안드로이드에서는 이런 상황을 방지 하기 위해 UI 스레드가 5초 이상 반응을 하지 않는 어플리케이션의 경우 'Application Not Responding(ANR)' 다이얼로그를 팝업 시켜 사용자가 어플리케이션을 강제 종료 해 버릴 수 있도록 하고 있다.

 

이런 극단적인 방법을 쓰는 이유는 UI가 사용자와 디바이스간의 유일한 소통 창구이며 특정 어플리케이션의 문제가 디바이스의 전반적인 운영(전화, 문자 수신 등등)에 큰 악영향을 미칠 수 있기 때문이다. 사용자가 마음대로 작동할 수 없는 디바이스는 고장 난 회로 덩어리에 불과할 뿐이다.

 

예제를 보면서 이런 경우를 한번 재현 시켜 보자.

이 번 포스트의 예제는 Progress bar 한 개와 몇 개의 버튼으로 이루어 져 있는데, 버튼을 누르면 약 6초 정도가 걸리는 작업을 UI 스레드에서 실행해 문제를 일으키거나 다양한 스레드 기법을 사용하여 문제를 해결하기도 하는 것을 보여준다. 실재 어플리케이션에서는 worker 스레드 내부는 복잡한 계산이나 DB querying, 자원 다운로드 같은 것을 수행하겠지만 본 예제에서는 SystemClock.sleep(float) 메소드로 0.6초간 시간을 때우다 progress bar를 10% 채우는 것을 100%가 될 때까지 반복한다.

 

예제는 다음과 같은 초기 화면 구성을 하고 있다.

'01. Thread 사용안함' 버튼을 누르면 두 번째 그림처럼 버튼이 클릭된 상태로 6초간 디바이스의 모든 동작이 정지한것 처럼 보인다 (UI 스레드가 block 되었다고 표현한다). 이 동안은 현재 실행중인 작업을 중단하거나, 어플리케이션을 종료하거나, 심지어 전화를 받는 작업조차 불가능 하며, 6초 정도가 지나면 block이 풀리면서 Progress Bar가 한번에 100%로 변해 버린다.

 

이 6초 동안 다른 버튼을 클릭하는 등 UI를 사용하면 메시지를 바로 해당 UI 위젯에 전달 할 수 없음으로(복잡한 계산을 수행 중) 메시지 queue에 보관된다. UI 스레드가 복잡한 작업을 완료 후 메시지 queue에 있는 다음 메시지를 처리할 때 5초 이상 대기한 메시지가 있다면 안드로이드는 다음과 같은 ANR 창을 팝업 시켜 사용자에게 문제가 있는 어플리케이션임을 알리고 강제종료 시킬지 계속 기다릴지 선택할 수 있게 한다. (ANR 상황을 재현하기 위해서는 예제에서 1번 버튼을 클릭하자 마자 2번 버튼을 클릭하고 작업이 완료되기를 기다린다. 1번 버튼만 클릭하고 아무것도 안하고 기다리면 ANR창이 안 나타나니 참고)

 

 

이와 같이 시간이 오래 걸리는 작업은 UI thread가 아닌, worker / background 라고 불리는 별도의 스레드에서 실행 함으로 UI 스레드의 block을 해결할 수 있다.


이제부터 안드로이드에서는 어떻게 스레드(thread)를 구현하는지 살펴 보자.

 

 

 

 

2. 스레드(Thread) 구현에 필요한 것들

 

A. Thread 객체

 

Thread 는 어떤 작업들을 병렬로 실행 가능하게 하는 자바 객체이다. 각 Thread는 CPU로부터 타임퀀텀이라는 사람이 느낄 수 없는 정도로 짧은 CPU 점유 시간을 각각 번갈아 가면서 할당 받아 자신에게 할당된 작업을 진행함으로 엄밀한 의미에서는 진짜 병렬수행은 아니지만 인간의 관점에서 보면 너무 빨리 이런 일이 진행 되기 때문에 2개 이상의 작업이 동시에 일어나는 것처럼 보인다. Thread는 자신이 실행할 메소드, 인자, local 변수를 위한 별도의 callstack을 가진다. 같은 VM내부(안드로이드에서 각각의 어플리케이션은 별도의 VM을 할당 받는다)의 Thread들은 상호작용(interact)이 가능하며, Thread 자신이 제공하는 여러 메소드나 Object로부터 상속하는 여러 객체를 사용해 Thread간의 동기(Synchronization)를 유지할 수 있다. (스레드의 동기화는 안드로이드만의 주제가 아님으로 깊은 설명은 추후 기회가 된다면 다루려고 한다)

 

안드로이드에서 Thread 객체를 사용하는 방법은 2가지가 있는데,

첫째는 Thread 클래스를 subclassing하는 새 객체를 정의해고 Thread:run() 메소드를 오버라이딩 하는 방법이고,

둘째는 new 연산자로 새로운 Thread 객체를 생성하면서 생성인자로 Runnable 인터페이스(스레드에서 실행될 logic포함)를 전달하는 방식이다.

 

데모에서는 두 번째 Runnable 인터페이스를 사용하는 방식을 사용했다.

 

 

 

B. Runnable 인터페이스

 

 

Runnable 인터페이스는 위와 같은 상속 구조를 가지고 있으며, 딱 하나의 abstract 메소드를 제공 하는데, 바로 run()이란 메소드이다.

새 Work 스레드 생성시 Thread객체의 생성인자로 전달되는  Runnable 인터페이스의 run() 메소드는 새 work 스레드가 실행할 작업을 포함해야하며, run()은 생성된 새 work 스레드가 시작되면 자동으로 호출된다.

 

 

 

 

3. 스레드(Thread)에서의 UI 업데이트

 

위에 설명한 Thread와 Runnable을 사용해 다음과 같이 별도의 work 스레드를 구현 한다면 UI blcking 문제를 해결 할 수 있다. 하지만 한가지 주의할 점이 있으니 살펴보자.

 

잠재적 문제를 가지는 Thread 구현

접기

01 public void onClick(View v) {
02     ......
03  
04     if else (v == btnThread01) {
05         // 새로운 스래드와 내부에서 실행될 Logic을 Runnable로 객체화 함.
06         Runnable increaseProgress = new Runnable() {
07              
08             // Runnable interface의 유일한 abstract method 구현.
09             // run() 메소드는 본 Runnable객체가 공급된 Thread가 시작할때 자동으로 호출.
10             public void run() {
11                 for(nProgress = 0; nProgress<=100; nProgress+=10) {
12                     try {
13                         bar.setProgress(nProgress);
14                     }
15                     catch(Exception e) {
16                         Log.w("h-exception", e.toString());                        
17                     }
18                     SystemClock.sleep(600);
19                 }
20             }
21         };
22          
23          
24         // 위에 선언한 Runnable객체에 구현된 logic을 실행할 새로운 Thread 객체 생성
25         Thread worker = new Thread(increaseProgress);
26          
27         // 새로운 스레드 시작됨 -> Runnable interface의 run()메소드가
28         // 새로운 스레드에서 실행됨.
29         worker.start();
30     }
31  
32     ......
33 }

접기

 

 

위의 코드를 실행 시켜 보면 6초간에 걸쳐 10%씩 순차적으로 100%까지 증가하는 정상적인 progress bar가 구현된 것을 볼 수 있다. 또 전 예제와 다르게 UI가 block되지 않아 다른 UI이벤트에 대해서도 즉각 반응함을 볼 수 있다. 하지만 위의 예제는 잠재적으로 심각한 오류를 일으킬 소지를 가지고 있다.

 

안드로이드 UI 위젯들은 스레드 세이프 (Threadsafe)하게 디자인 되지 않았기 때문이다.

 

만약 두 개 이상의 스레드가 동시에 UI위젯 자원에 접근하여 이를 조작 하려고 한다면 개발자가 예상하지 못한 결과가 일어날 수도 있다. 여기서 사용된 ProgressBar객체는 별 문제 없이 작동하지만, UI스레드에서 생성된 TextView가 worker 스레드에서 직접 컨트롤 되면, run-time exception이 발생하며 exception 처리가 안되어 있을 경우 어플리케이션이 강제 종료 될 수도 있다.

 

사용자에게 좀 더 낳은 UX(User eXperience)를 제공하기 위해 사용된 Thread가 자칫 잘못 사용되면 어플리케이션의 안정성을 해치기 때문에 올바르게 구현하는 것이 중요하다.

 

Worker 스레드에서 실행된 결과가 UI 위젯에 안전하게 반영되기 위해서는 어떻게 코드를 작성해야 하는지 다음 단락에서 살펴보자.

 

 

 

 

4. 올바른 스레드(Thread) 구현 방법

 

안드로이드는 복수의 스레드가 하나의 UI 위젯에 동시에 접근해서 일어날 수 있는 잠재적인 문제를 해결하기 위해 다음과 같은 절차로 work스레드가 UI위젯에 접근하게 끔 어플리케이션을 구성한다.

  • worker 스레드가 UI 위젯에 적용할 작업을 메시지 queue에 추가 함
  • UI 스레드가 메시지를 dispatch해 해당 UI위젯에 메시지를 전달 함
  • UI 위젯은 메시지 대로 자신의 상태를 update함.

 

정리하면 하나의 자원에 동시에 접근할 수 있는 스레드를 하나로 제한해서 혼선을 줄이는 것이 핵심이다. 이를 그림으로 표현하면 다음과 같다.

(물론 일반적인 스레드 동기화 방법 mutex, semaphore, critical section등을 사용할 수도 있다).

 

 

 

안드로이드에서는 위와 같이 UI스레드만 UI위젯에 접근하게 하기 위해 3가지 방법을 사용 할 수 있는데 각각 다음과 같다.

 

 

 

A. Thread 구현 예 01: View:post(…) 이용

 

View 클래스는 post() 메소드를 제공 하는데, 메소드의 설명은 다음과 같다.


public boolean post (Runnable action)

parameter

action: 메시지 queue에 queue될 Runnable 객체.

return

true: Runnable객체가 메시지 queue에 성공적으로 queue됨.

false: Runnable 객체를 메시지 queue에 queue하는데 실패함.

 

 

View:post(…) 메소드는 다음과 같이 사용 가능하다.

접기

01 public void onClick(View v) {
02     // ......
03     else if (v == btnThread02) {
04         new Thread(new Runnable() {
05             @Override
06             public void run() {
07                 for(nProgress = 0; nProgress<=100; nProgress+=10) {
08                      
09                     // ProgressBar 객체는 View로 부터 상속 함.
10                     // post 메소드는 UI 스레드의 메시지 큐에 bar객체에게 전달할
11                     // Runnable을 queue함.
12                     bar.post(new Runnable() {
13                         public void run() {
14                             // UI 스레드 메시지 큐에 저장될 메시지의 핵심
15                             bar.setProgress(nProgress);
16                         }
17                     });
18                     // 실제로는 복잡한 계산등 시간이 소모되는 작업 수행 되겠지만
19                     // 데모에서는 0.6초간 sleep함  
20                     SystemClock.sleep(600);
21                 }
22             }
23         }).start(); // 스레드 실행  
24     }
25     //......
26 }

접기

 

 

위의 코드에서 보면 2개의 Runnable 객체가 사용되는데 목적을 정리하면 다음과 같다.

새 Thread의 생성인자로 전달되는 Runnable: Thread가 start() 메소드에 의해 시작되면 자동 실행됨. 이 Runnable 내부에서 bar.post()와 sleep을 실행함.

bar.post(…)의 인자로 전달되는 Runnable: UI 스레드의 메시지 큐에 메시지(ProgressBar인스턴스 bar를 증가 시킴)를 등록 함.

 

결과적으로, 새로 생성된 work 스레드의 역할은 긴 시간이 필요한 작업을 처리 후 특정자원(UI 위젯 등)의 상태 update 명령을 메시지 큐에 등록하는 것까지이고, 저장된 메시지가 UI위젯에 전달 되는 시기는 전적으로 UI스레드의 상태에 따라 결정되게 된다.

 

우선 순위가 높은 작업(전화, 문자 수신 등)의 메시지가 갑자기 발행하면 저장된 메시지(UI위젯 update)의 앞으로 등록(세치기) 시켜 우선 적으로 처리 함으로 디바이스의 신뢰성을 높일 수 있다.

 

 

 

B. Thread 구현 예 02: Activity:runOnUiThread(…) 이용

 

또 다른 방법은 Activity가 제공하는 runOnUiThread(…) 메소드를 사용하는 방법이다.

우선 runOnUiThread(…) 메소드의 설명을 살펴보자.


public final void runOnUiThread (Runnable action)

Parameter

action: 바로 실행되거나 메시지 큐에 등록될 메시지 (runOnUiThread()가 call 되는 위치에 따라 다름)


 

코드 내부에서는 다음과 같이 사용 가능하다.

접기

01 public void onClick(View v) {
02     //......
03     else if (v == btnThread03) {
04         new Thread(new Runnable() {
05             @Override
06             public void run() {
07                 for(nProgress = 0; nProgress<=100; nProgress+=10) {
08                     // 현재 UI 스레드가 아님으로 메시지 큐에 Runnable을 등록 함
09                     runOnUiThread(new Runnable() {
10                         public void run() {
11                             // 메시지 큐에 저장될 메시지의 핵심
12                             bar.setProgress(nProgress);
13                         }
14                     });
15                     // 복잡한 작업 simulating   
16                     SystemClock.sleep(600);
17                 }
18             }
19         }).start();
20     }  
21     //......
22 }

접기

 

 

runOnUiThread메소드의 특징은 자신이 어디서 call 되었는지에 따라 처리 방법이 다른 것인데, UI스레드 내부에서 call되었으면 인자로 제공된 Runnable이 바로 실행되고, UI 스레드가 아니라면 메시지 큐에 등록 시켜서 UI스레드의 스케쥴에 맞춰 실행 할 수 있게 처리한다. 예제에서는 별도의 work 스레드 안에서 사용되었으므로 바로 실행되지 않고 메시지 큐에 등록된다.

 

 

 

C. Thread 구현 예 03: Handler객체 이용

 

마지막으로 android.os.Handler객체를 사용한 Thread구현 방법이 있다. 우선 Handler의 상속 구조는 다음과 같다.

 

 

Handler객체에서 메시지 큐에 메시지를 추가하는 메소드는 다음 두 가지 이다.


final boolean post(Runnable r)

parameter

r: 메시지 큐에 추가 할 Runnable.

return

true: 메시지 큐에 성공적으로 r 추가

false: r을 메시지 큐에 추가 실패

 

 

코드 내부에서 사용하는 방법은 다음과 같다.

Handler객체를 사용한 스레드구현 01 – post(…) 이용

접기

01 public class MyActivity extends Activity {
02  
03     private ProgressBar mProgress;
04     private int mProgressStatus = 0;
05  
06     private Handler mHandler = new Handler();
07  
08     protected void onCreate(Bundle icicle) {
09         super.onCreate(icicle);
10  
11         setContentView(R.layout.progressbar_activity);
12  
13         mProgress = (ProgressBar) findViewById(R.id.progress_bar);
14  
15         // 오래 걸리는 작업을 work 스레드에서 실행 함
16         new Thread(new Runnable() {
17             public void run() {
18                 while (mProgressStatus < 100) {
19                     mProgressStatus += 10;
20  
21                     // PorgressBar인스턴스 update 메시지를 메시지 큐에 등록
22                     mHandler.post(new Runnable() {
23                         public void run() {
24                             // work 스레드 내부에서 명령이 실행되는 것이 아니라
25                             // post(..)에 의해 메시지 큐에 추가됨.
26                             mProgress.setProgress(mProgressStatus);
27                         }
28                     });
29                 }
30             }
31         }).start();
32     }
33 }

접기

 

 

 

다음은 두 번째 방법이다.

 

final boolean sendMessage(Message msg)

parameter

msg: 메시지 큐에 추가될 메시지.

return

true: msg가 성공적으로 메시지 큐에 추가 됨

false: msg가 메시지 큐에 추가 되지 않음

 

 

sendMessage(Message)를 사용할 경우는 다음과 같이 구현한다.

Handler객체를 사용한 스레드구현 02 – sendMessage(…) 이용

접기

01 public class MyActivity extends Activity {
02  
03     private ProgressBar mProgress;
04     private int mProgressStatus = 0;
05  
06     // Handler 객체를 생성하고
07     // handleMessage(Message)를 오버라이딩하여
08     // mHandler 인스턴스에게 전달 되는 모든 메시지를 처리함.
09     private Handler mHandler = new Handler(){
10         @Override
11         // 어떤 메시지가 전달되어도 progress bar를 설정함.
12         public void handleMessage(Message msg) {
13             mProgress.setProgress(mProgressStatus)
14         }
15     };
16  
17     protected void onCreate(Bundle icicle) {
18         super.onCreate(icicle);
19  
20         setContentView(R.layout.progressbar_activity);
21  
22         mProgress = (ProgressBar) findViewById(R.id.progress_bar);
23  
24         // 오래 걸리는 작업을 work 스레드에서 실행 함
25         new Thread(new Runnable() {
26             public void run() {
27                 while (mProgressStatus < 100) {
28                     mProgressStatus += 10;
29  
30                     // 메시지를 발생시킴. 메시지 큐에 저장되며
31                     // UI 스레드는 메시지를 mHandler 객체로 전달함.
32                     // 결과적으로 UI 스레드에서 
33                     // mHnadler의 handleMessage(Message)에 의해 처리됨.
34                     mHandler.sendMessage(mHandler.obtainMessage());          
35                 }
36             }
37         }).start();
38     }
39 }

Posted by 후니와갱
2010/06/10 11:40

[공통] ArrayAdapter 안드로이드 관련2010/06/10 11:40

- 공동의 인터페이스 어댑터

String[] items = {"a", "b", "c", "d", "e"};
new ArrayAdapter<String>(this, android.R.layout.simple_list, items);

ArrayAdapter 클래스의 생성 메소드에는 다음과 같은 세 개의 인자를 넘겨준다

* Context 인스턴스 (일반적으로는 포함될 액티비티의 인스턴스를 사용한다)
* 사용할 뷰의 리소스 ID
* 화면에 표시할 실제 내용이 들어 있는 배열


public View getView(int position, View convertView, ViewGroup parent)
{
   if(convertView == null) {
       convertView = new TextView(this);
   }

   convertView.setText(buildStringFor(position));

   return convertView;
}

getView() 메소드는 다음과 같은 세 개의 인자를 넘겨 받는다.

* 화면에 표시할 항목이 전체 배열에서 몇 번째 항목인지를 가리키는 번호
* 해당하는 위치에 이미 사용중이던 화면 표시 위젯
    (스크롤돼 다시 화면에 나타난다면 이미 존재할 수도 있고, 만약 완전히 처음 호출됐다면
      인스턴스를 새로 만들어야 한다)
* 화면 표시 위젯을 포함하는 선택 위젯, 항목에 해당하는 표시용 위젯을 생성할 때 필요한 경우기 있다.


- 그 밖의 어댑터
 * CursorAdapter
 * SimpleAdapter : XML 리소스에 들어 있는 내용을 반환해준다.
 * ActivityAdapter와 ActivityIconAdapter : 특정 인텐트를 사용해 실행할 수 있는 액티비티 이름이나 아이콘을 사용할 수 있다.

- 예제

public class IUSpinnerAdapter extends ArrayAdapter 
{
  private Context context = null;   // 타켓 액티비니
  private List items = null; // 데이터 배열

  public IUSpinnerAdapter(Context context, List items) {
    super(context, R.layout.list_row, items);
    this.context = context;
    this.items = items;
  }

 //  재활용가능한 뷰 객체를 반환한다.
  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    final int _position = position;
    View row = convetView;
    IUSpinnerWrapper wrapper = null;

   if(row == null) {
      LayoutInflater inflater = LayoutInfalter.from(context);  // 따로 설명할 예정임
      row = inflater.inflate(R.layout.list_row, null);
      wrappper = new IUSpinnerWrapper(row);
      row.setTag(wrapper);
   }else {
        wrapper = (IUSpinnerWrapper)row.getTag();
    }

    wrapper.getAccountCode.setText(items.get(position).trim());

   return row;
  }
}
Posted by 후니와갱