IBM Korea Skip to main content
       IBM 홈    |  제품 & 서비스  |  고객지원 & 다운로드  |  회원가입  

MIDlets 클래스
모든 J2ME 프로그램의 기반하에 구축하기

Soma Ghosh
선임 개발자, Entigo
2002년 3월

여러분은 자바 가상 머신을 메모리 용량이 적고 자원이 제한되어 있으며 네트워크로 연결된 환경에 적합하게 만들고 싶을 것이다. K 가상 머신 (KVM)의 중심에 특수한 자바 클래스가 있는데, MIDlet이 그것이다. 이 글에서 Soma Ghosh는 여러분에게 MIDlet 클래스의 장단점을 소개하고 여러분 자신의 J2ME 애플리케이션을 구축할 때 이를 활용하는 방법을 소개하겠다. 여러분은 MIDlet의 이론을 배우고 난 후 그녀가 구축하는 샘플 프로그램을 통해 그 기술이 실행되는 것을 확인하게 될 것이다.

이 주제에 대해 내가 작성한 이전 글에서 나는 Java 2 Platform, Micro Edition (J2ME)의 기초 사항들에 대해 논의하였다. 그 글을 읽어보지 않은 분이라면 이 글을 읽기 전에 아마도 그것을 먼저 읽어 보아야 할 것이다. J2ME의 가장 중요한 구성 요소가 MIDlet이다. 여기서 우리는 MIDlet의 상태와 상태 애플리케이션 뿐 아니라 이벤트와 예외를 처리하기 위한 기법들을 검토하면서 MIDIet을 상세히 살펴보도록 하겠다. 또한 여기에서 설명된 개념들을 입증해 줄 간단한 애플리케이션을 구축해 봄으로써 결론을 짓도록 하겠다. 이 글을 끝낼 때쯤이면 여러분은 여러분 자신의 J2ME 애플리케이션을 작성하는 중일 것이다.

MIDlet이란 무엇인가?

Mobile Information Device Profile (MIDP)은 이동 전화나 기본적인 수준의 팜탑 장비와 같은 모바일 정보 장비를 타겟으로 하는 자바 API 세트이다. MIDlet은 MIDP 애플리케이션을 말한다. 이 글에서는 MIDletMID 애플리케이션라는 용어가 교대로 사용된다. MIDlet은 J2ME 실행 환경의 구성 요소가 된다.

MIDlet은 모바일 장비에서 작동하도록 설계되었으며 자바 가상 머신의 핵심만 모은 버전인 K Virtual Machine (KVM)의 애플리케이션 관리자에 의해 실행되고 제어되도록 만들어졌다.javax.microedition.midlet.MIDlet 클래스는 MIDlet과 애플리케이션 관리자 사이의 인터페이스로 작동한다. 이 클래스의 메소드는 애플리케이션 관리자가 MIDlet을 만들고 구동시키고 중지시키고 없애도록 해준다.

J2ME 애플리케이션은 javax.microedition.midlet.MIDlet 클래스를 확장해야 하는데, 이는 다음 작업들에 대한 프레임워크를 제공한다.:

  • 애플리케이션 관리자가 MIDlet 상태 변화를 통지하고 요청함으로써 MIDlet을 제어하도록 한다.

  • MIDlet이 애플리케이션 관리자가 관리하는 애플리케이션 레지스터리인 애플리케이션 디스크립터 (application descriptor)로부터 특성을 검색할 수 있도록 한다.

그림 1은 MIDlet과 애플리케이션 관리자 간의 상호작용을 보여준다.

그림 1. MIDlet 환경
The MIDlet environment

MIDlet의 상태

MIDlet은 그 수명 주기 동안 다양한 상태 로 있을 수 있다. 이 상태들은 애플리케이션 관리자가 런타임 환경 내에서 여러 MIDlet들의 행동을 관리하도록 해 준다. 애플리케이션 관리자는 MIDlet들을 개별적으로 시작시키고 중지시킴으로써 주어진 시점에 어떤 MIDlet이 작동할지 선택할 수 있다. 애플리케이션 관리자는 또한 MIDlet의 상태를 유지보수한다. MIDlet은 다음 상태들 중 하나로 있을 수 있다.:

  • 작동 : MIDlet은 구동시에 작동 상태로 들어가고 일부 자원을 차지할 수 있다.
  • 중지 : 중지 상태에서 MIDlet은 공유된 자원을 해제하고 정지한다.
  • 파기 : 이것은 MIDlet의 종료 단계이다. 종료된 MIDlet은 모든 자원을 해제하고 애플리케이션 관리자에 어떤 영속적인 상태를 저장해야 한다.

그림 2는 MIDLet의 상태 변화를 보여주고 있다. 화살표는 허가된 상태 변화를 나타낸다. 예를 들어, 작동 상태의 MIDlet은 중지 상태나 파기 상태 중 하나로 이동할 수 있다.

그림 2. MIDlet의 상태 변화
MIDlet state changes

상태 구현 : 한 상태에서 다른 상태로 이동하기

애플리케이션 관리자는 상태를 바꾸기 위해 MIDlet에 특정 메소드를 호출한다. MIDlet은 이 메소드를 구현하여 자신의 내부 행동과 자원 활용을 애플리케이션 관리자가 지시하는대로 업데이트시킨다.:

  • startApp(): 이 메소드는 MIDlet에게 작동 상태로 들어간다는 신호를 보내며, MIDlet의 대화형 화면 환경을 설정하기 위한 초기화 절차들로 구성되어 있다.

  • pauseApp(): 이 메소드는 MIDlet에게 작동을 멈추고 중지 상태로 가라고 신호한다.

  • destroyApp(): 이 메소드는 MIDlet에게 작동을 종료하고 파기 상태로 가라고 지시한다.

MIDlet은 스스로 몇 가지 상태를 개시하고, 이 메소드들 중 하나를 호출하여 애플리케이션 관리자에게 이러한 상태 변화들을 통지할 수 있다.:

  • notifyDestroyed(): 자신이 파기 상태로 들어갔음을 애플리케이션 관리자에게 통지하기 위해 MIDlet이 사용하는 메소드이다.

  • notifyPaused(): 이 메소드는 MIDlet이 작동 상태로 있고 싶지 않으며 중지 상태로 가고 싶다고 애플리케이션 관리자에게 통지한다.

  • resumeRequest(): 이 메소드는 MIDlet이 작동 상태로 가고 싶어함을 표시하는 메커니즘을 제공한다. 이 메소드에 대한 호출은 애플리케이션 관리자가 사용하는데, 어떤 애플리케이션이 작동 상태로 갈지를 결정한다. 애플리케이션 관리자가 한 MIDlet을 활성화하기로 결정하면 그 MIDlet의 startApp() 메소드를 호출할 것이다.

MIDlet은 애플리케이션 관리자로부터 지정된 특성들을 검색하는 메커니즘을 받았다. getAppProperty() 메소드가 그것이다. MIDlet 배치의 일부분으로 제공되는 이 특성들은 애플리케이션 디스크립터 파일과 manifest가 조합된 것으로부터 얻어진다.

startApp() 혹은 pauseApp() 동안 런타임 예외가 발생하면 MIDlet은 즉시 파기될 것이다.

MIDlet의 이벤트 처리

사용자가 MIDlet과 상호작용할 때, 이벤트가 생성된다. MIDlet은 자신의 이벤트 처리 메커니즘의 일부분으로 특정 인터페이스들을 제공하여 애플리케이션이 이벤트를 통지받고 이에 대해 응답할 수 있도록 한다. 각 인터페이스는 콜백 (callback) 이라고 알려진 메소드를 제공하는데, 이것은 이벤트에 응답하여 애플리케이션이 실행시키는 프로그래머 정의 메소드를 호출하는 것이다.

MIDlet이 실행되고 있는 동안 생성되는 이벤트들은 다음과 같다. :

  • 화면에서 입력되는 명령문
  • 화면 아이템의 내부 상태의 변화
  • MIDlet과 관련된 폰 데이터베이스의 내부 상태의 변화

MIDlet 이벤트 처리 메커니즘은 listener 모델에 기반하고 있다. 각 객체는 이벤트를 통지받고 여기에 응답할 수 있도록 Listener를 구현해야 한다. 이를 위해 MIDlet은 ItemStateListener, CommandListener, RecordListener라는 세 인터페이스를 제공한다. 각각을 상세하게 살펴 보자.

CommandListener

CommandListener는 화면 출력될 수 있는 아이템 (예 : 화면에 입력되는 명령어)들에서 생성되는 이벤트를 MID 애플리케이션에게 통지하는 책임을 가진다. CommandListener는 listener를 확장하는 객체가 구현해야 하는 commandAction(Command c, Displayable d)메커니즘을 제공한다. 이 메소드는 명령어 이벤트가 Displayable d에 발생했음을 가리킨다.

ItemStateListener

ItemStateListener는 화면 아이템 (예 : 화면에 있는 TextField 의 값)의 내부 상태 변화를 MID 애플리케이션에게 통지하며, 아이템의 내부 상태가 사용자에 의해 변경되었을 때 호출되는 itemStateChanged(Item I)메소드를 제공한다. 내부 상태의 변화는 사용자에 의해 발생한다.:

  • ChoiceGroup에서 선택된 값들 변경하기

  • 대화형 Gauge의 값 조정하기

  • TextField에 값을 입력하거나 수정하기

  • DateField에 날짜나 시간 입력하기

여러분은 내가 작성한 이전 글에서 이들 화면 아이템에 관해 더 배울 수 있다.

아이템에 언제 새 값을 입력해야 하는지의 결정은 장비에 달려 있다. 예를 들어, TextField 내에 텍스트 편집을 구현하는 것은 장비에 따라 아주 다양하다.

ItemStateListener는 애플리케이션이 대화형 아이템의 값을 변경한 경우에는 호출되지 않는다. 사용자가 변경했을 때만 호출된다.

RecordListener

RecordListener의 책임은 애플리케이션과 연관되어 있는 레코드 스토어에서 레코드 변경과 관련된 이벤트를 받는 것이다. 이것을 사용하려면 애플리케이션은 RecordListener 가 제공하는 다음 메소드들을 구현해야 한다. :

  • recordAdded(): 레코드가 레코드 스토어에 추가되었을 때 호출된다.

  • recordDeleted(): 레코드 스토어의 레코드가 변경된 후에 호출된다.

  • recordChanged(): 레코드 스토어에서 레코드가 삭제된 후 호출된다.

Listener와 객체 연결시키기

MIDlet이 실행될 때 객체들이 이벤트에 응답할 수 있도록 Listeners가 이들 객체들에 연결되어야 한다. MIDlet 클래스는 이벤트 listener를 객체와 연결시키기 위한 특정 메소드들을 제공한다.:

  • setCommandListener(): 이 메소드는 모든 명령어에 대한 listener를 Displayable에 설정하며, 이전의 CommandListener를 바꾼다

  • setItemStateListener(): 이 메소드는 화면 아이템에 대한 아이템 상태 listener를 설정하며, 이전의 itemStateListener를 바꾼다.

  • addRecordStateListener(): 이 메소드는 레코드 스토어에 레코드 상태 listener를 추가한다.

그림 3은 MIDlet 이벤트 처리 모델이다.

그림 3. MIDlet 이벤트 처리
MIDlet event handling

MIDlet의 예외

MIDlet은 예외 처리 기능을 사용해 예외적인 상황을 처리할 수 있다. 예외란 프로그램이 실행되는 동안 정상적인 명령의 흐름을 혼란시키는 이벤트를 말한다. MIDlet은 자바 예외 처리 메커니즘의 모델을 보존하고 있다. 그러한 에러가 메소드에 발생했을 때, 메소드는 예외 객체를 만들어 이를 런타임 시스템에 넘겨 준다. 예외 객체는 예외의 유형 및 예외가 발생했을 때 프로그램의 상태 등 예외에 관한 정보를 가지고 있다. 그러면 런타임 시스템은 에러를 처리하기 위해 몇 가지 코드를 발견해야 한다. 자바 전문 용어에서, 예외 객체를 만들어 이를 런타임 시스템에 넘겨 주는 것은 예외를 던진다(throwing an exception)라고 불린다.

앞에서 살펴 보았듯이, MIDlet은 수명 주기 동안 다양한 상태로 있을 수 있다. MIDlet은 요청된 MIDlet 상태 변화가 실패했음을 함축적인 MIDletStateChangeException을 던짐으로써 알려준다.

자바 예외 처리에 관한 상세 정보는 아래의 참고 자료 부분을 참조한다.

예제 : 전화기 이미지 애플리케이션

이번 섹션에서 우리는 다양한 단계에서의 MIDlet의 역할을 보여주는 J2ME 이미지 애플리케이션을 개발할 것이다. 이 애플리케이션은 또한 이벤트 처리 메커니즘을 통해 종료하는 기능도 가질 것이다.

PhoneImage 애플리케이션은 자신의 MIDIet 메소드에 대한 호출에 대응하여 하나의 생성자를 불러온다. 이 생성자는 전화기 화면 환경, 전화기 화면 아이템, 애플리케이션을 종료시키기 위한 화면 명령어를 생성하여 초기화 절차를 수행한다.

전화기 화면 환경은 Display 클래스에 의해 표시된다. MIDlet당 정확히 하나의 Display 인스턴스가 있고, PhoneImage 생성자는 getDisplay() 메소드를 호출함으로써 그 인스턴스에 대한 참조를 얻는다.:


            display = Display.getDisplay(this);

이 애플리케이션의 UI 측면은 그래픽 이미지 데이터를 보유하기 위해 사용되는 javax.microedition.lcdui.Image 클래스이다. Image 객체들은 화면 장치와 독립적으로 존재한다. 그들은 화면과 무관한 메모리에만 존재하며, 애플리케이션이 명시적인 명령어(Canvaspaint() 메소드에서처럼)를 발행하지 않는 한 혹은 Image 객체가 Form 화면이나 Alert 화면 내에 위치하고 그 화면이 갱신되기 전까지는 화면에 표시되지 않을 것이다.

이미지는 그들이 만들어진 방식에 따라 가변일 수도 있고 불변일 수도 있다. 불변 이미지는 일반적으로 자원 번들, 파일 혹은 네트워크에서 이미지 데이터를 로딩함으로써 만들어진다. 이들은 한 번 만들어지면 수정할 수 없다. 가변 이미지는 화면과 무관한 메모리에서 만들어진다. 애플리케이션은 이를 위해 Graphics 객체를 명확하게 생성한 후 이들을 표시할 수 있다. Alert, Choice, Form 혹은 ImageItem 객체에 있는 이미지는 불변이어야 한다. 런타임 환경이 애플리케이션에게 통지하지 않고 언제든지 화면을 업데이트하기 위해 이들을 사용할 수 있기 때문이다.

PhoneImage 애플리케이션은 javax.microedition.lcdui.Image 클래스의 createImage(String resourceName) 메소드를 호출함으로써 불변 이미지 아이템을 생성한다. 이 메소드는 지정된 자원에서 얻어지는 해독된 이미지 데이터들로부터 불변 이미지를 생성하는데, 이 데이터들은 장비 구현에 따라 자원 번들 내에 혹은 파일 시스템상에, 혹은 네트워크상에 존재할 수 있다. resourceName은 지원되는 이미지 포맷 중 하나로 된 이미지 데이터를 포함하고 있는 자원의 이름을 표시하고 있다. 구현은 PNG (Portable Network Graphics) 포맷 v.1.0에 저장되어 있는 이미지들을 지원해야 한다.

자원 명이 null일 경우 메소드는 NullPointerException을 던진다. 자원이 존재하지 않거나 데이터를 로딩할 수 없거나 이미지 데이터를 해독할 수 없는 경우에는 IOException을 던진다. Listing1은 이 모든 것이 어떻게 작동하는지 보여준다.

Listing 1.이미지 생성하기

               try
     {
              image = Image.createImage("/img/JavaPowered-8.png");
                    
     }
     catch (java.lang.NullPointerException exc)
     {
          exc.printStackTrace();
     }
     catch (java.io.IOException ioExc)
     {
          ioExc.printStackTrace();
     }

startApp

PhoneImage 애플리케이션은 startApp()메소드를 호출함으로써 작동 상태로 들어간다. Image 아이템은 Form 객체 (Listing 2 참조)에 내장되어 있다. 구현은 화면 배치, 순환 및 스크롤링을 처리한다. Form 역시 화면 명령어와 연결되어 있다.

Listing 2.전화기 화면에 이미지 추가하기

displayForm = new Form("Image");
displayForm. append(
                new ImageItem("Default Layout",
                image,
                ImageItem.LAYOUT_DEFAULT,
                "Image Cannot be shown"));
displayForm.addCommand(exitCommand);

startApp() 메소드는 Listing 3과 같이 각 명령어를 listener에 연결하고 Form을 현재 표시 가능한 아이템으로 정의함으로써 이벤트 처리 메커니즘을 설정한다.

Listing 3. 화면에 사용자 상호작용 특성 추가하기

displayForm.setCommandListener(this);
displayForm.setItemStateListener(this);

애플리케이션 관리자가 pauseApp() 메소드를 호출하면 PhoneImage 애플리케이션이 정지 상태로 들어간다. 이는 백그라운드 작업이 없거나 레코드 스토어가 종료되었을 때 사용하는 무연산 메소드이다. destroyApp() 메소드는 PhoneImage 애플리케이션의 종료 단계를 시작시킨다. 이 메소드는 모든 자원을 해제하는 책임을 가지고 있다.

commandAction 메소드 (Listing 4 참조)는 PhoneImage MIDlet이 명령에 응답하도록 하며, 모든 화면 명령어 작업시 호출된다. exitCommand가 호출되었을 때 MIDlet을 종료시키는 exitCommand의 핸들러가 정의된다.

Listing 4. 명령어 콜백 구현하기

public void commandAction (
  Command c, Displayable s) {
    if (c == exitCommand) {
            destroyApp(false);
            notifyDestroyed();

    }

   }

Listing 5는 PhoneImage 애플리케이션의 전체 소스 코드이다. :

Listing 5. PhoneImage


// Import of API classes

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.util.*;

 

//A first MIDlet with simple text and a few commands.

public class PhoneImage extends MIDlet 

               implements CommandListener, ItemStateListener {

 

//The commands

private Command exitCommand;

//The display for this MIDlet

private Display display;

// Display items e.g. Form and Image


Form displayForm;
Image image;


public PhoneImage() {

            display = Display.getDisplay(this);
               exitCommand = new Command("Exit", Command.SCREEN, 1);

               try
                 {
                   image = Image.createImage("/img/JavaPowered-8.png");
                    
               }
               catch (java.io.IOException ioExc)
               {
                    ioExc.printStackTrace();
               }
 

 

 }

 

 // Start the MIDlet by creating the Form and 

 // associating the exit command and listener.

  public void startApp() {

                  displayForm = new Form("Image");
                     displayForm. append(
                new ImageItem("Default Layout",
                                image,
                                ImageItem.LAYOUT_DEFAULT,
                                "Image Cannot be shown"));

                    displayForm.addCommand(exitCommand);

                     displayForm.setCommandListener(this);

                     displayForm.setItemStateListener(this);

                     display.setCurrent(displayForm);

  }

  

  public  void itemStateChanged(Item item)

  {

 

  }

  

  // Pause is a no-op when there is no background

  // activities or record stores to be closed.

  public void pauseApp() { }

 

  // Destroy must cleanup everything not handled 

  // by the garbage collector.

  public void destroyApp (boolean unconditional) { }

 

  // Respond to commands. Here we are only implementing

  // the exit command. In the exit command, cleanup and

  // notify that the MIDlet has been destroyed.

  public void commandAction (

  Command c, Displayable s) {

    if (c == exitCommand) {

            destroyApp(false);

            notifyDestroyed();

    }

   }

 }

그림 4는 장치 에뮬레이터상에서 실행되는 애플리케이션이다.

그림 4. PhoneImage 애플리케이션
The PhoneImage application

결론

모든 이동 전화나 호출기에서 작동하는 무선 애플리케이션의 작성이 MIDlet으로 훨씬 쉬워졌다. MIDlet의 잘 정의된 아키텍처는 광범위한 기능을 제공하지만 요약된 아키텍처를 유지하는 잘 정의된 메소드 세트를 기반으로 구축되었다. 나는 이 글이 여러분 자신의 MIDlet 구축에 착수하는데 도움이 되기를 바란다.

참고 자료

목 차:
MIDlet란 무엇인가?
MIDlet의 상태
MIDlet의 이벤트 처리
MIDlet의 예외
예제 : 전화기 이미지 애플리케이션
결론
참고 자료
필자 소개
기사에 대한 평가
관련 dW 링크:
Think small with J2ME
Subscribe to the developerWorks newsletter
US 원문 읽기
Also in the Java zone:
Tutorials
Tools and products
Code and components
Articles
필자소개
컴퓨터 과학 및 공학을 전공한 Soma Ghosh는 지난 6년 동안 다양한 범위의 전자 상거래와 네트워킹 자바 애플리케이션을 개발해 왔다. 그녀는 무선 상거래가 업계의 가까운 미래가 될 것이라고 믿고 있으며 최근에는 기존 데스크탑 모델을 무선으로 만드는 시도에 관심을 가져 왔다. 그녀는 현재 B2B 판매 및 서비스측 전자 상거래 제품의 개척자인 Entigo사의 선임 애플리케이션 개발자로 일하고 있다.
이 기사에 대하여 어떻게 생각하십니까?

정말 좋다 (5) 좋다 (4) 그저그렇다 (3) 수정보완이 필요하다(2) 형편없다 (1)

  회사소개  |  개인정보 보호정책  |  법률  |  문의