poniedziałek, 2 maja 2011

Warunkowa kompilacja j2me w srodowisku NetBeans

Pisanie aplikacji na urządzenia mobilne w j2me nie jest prostą sprawą. Niby specyfikacja KVM (Kilobyte Virtual Machine) jest jedna i narzucona przez Oracle’a (dawniej Sun’a), ale konkretną implementację dostarcza producent danego telefonu komórkowego. Ponadto mamy sporo różnych modelów telefonów, różniących się od siebie wielkością ekranu, ułożeniem przycisków, szybkością procesora itd. Często przychodzi potrzeba dostarczenia aplikacji zoptymalizowanej pod konkretny telefon. Przedstawię poniżej w artykule jak można tego dokonać za pomocą warunkowej kompilacji w NetBeans’ie.

Warunkowa kompilacja to bardzo stary pomysł znany mi z czasów języka C (a może i był używany wcześniej). Polega ona na dodaniu do kodu źródłowego pewnych instrukcji, które zostaną wykonane jeszcze przed właściwą kompilacją. Spowoduje to wybranie odpowiednich fragmentów kodu, które zostaną dołączone do wynikowego programu. Projektanci języka Java całkowicie zrezygnowali z warunkowej kompilacji ze względu, że jest ona wrogiem numer 1 obiektowości. Gdy J2ME ujrzała światło dzienne i gdy coraz więcej telefonów zaczęło wspierać tą funkcjonalność, zrozumiano że jednak pewna możliwość konfigurowania kodu przed właściwą kompilacją jest niezbędna. I tak się narodziła warunkowa kompilacja w NetBeans'ie. Oczywiście wiem, że obecnie mamy XML’e, Dependency injection, Inversion of control i inne możliwości konfiguracji naszych aplikacji, ale nie mają one zastosowania w świecie j2me. Powstały co prawda projekty Signal Framework i Spring ME coś ala IoC dla j2me, ale jak dla mnie to sztuka dla sztuki i zastosowanie zerowe (i tak trzeba całość kompilować).

Dobra czas przejść do konkretów. Poniżej prezentuję fragment kodu, który używam w swojej aplikacji, z wykorzystaniem warunkowej kompilacji:

private void drawHelpMenu(Graphics g) {
//#if MobileTouchScreen
    helpSprite.setPosition(getWidth() - helpSprite.getWidth(),
            getHeight() - helpSprite.getHeight());
    helpSprite.paint(g);
//#else
    String  back = I18n.getText(I18n.LESSON_HELP);
    g.setFont(getSmallFont());
    g.drawString(back, getWidth(), getHeight(),
            Graphics.RIGHT | Graphics.BOTTOM);
//#endif
}

Interesujące fragmenty to te zaczynające się od //#. Są to instrunkcje preprocesora. Jak to działa? Gdy mamy ustawione ability MobileTouchScreen, to wówczas linijki 3-5 zostaną skompilowane, w przeciwnym wypadku linijki 7-10 zostaną wstawione w ciało metody drawHelpMenu(...). Prawda ze proste?

Teraz nadszedł czas na zarządzanie naszymi “zdolnościami” (chyba nienajlepsze tłumaczenie). Klikamy prawym przyciskiem myszy na nazwę projektu i wybieramy z menu opcję Properties. Tam w kategorii Abilities możemy zobaczyć jakie mamy ustawione właściwości dla obecnej konfiguracji naszego projektu. Właściwości mogą posiadać wartość, ale nie muszą.


Proponuję teraz utworzyć sobie nową konfigurację. Z pola Project Configuration wybieramy Add Configuration I wpisujemy nazwę nowej konfiguracji I następnie klikamy OK. Możemy tutaj jeszcze wybrać szablon, na podstawie którego zostanie utworzona konfiguracja.


Po kliknięciu OK wracamy do poprzedniego ekranu i teraz możemy modyfikować naszą konfigurację. Najpierw musimy odznaczyć pole Use Values from „DefaultConfiguration”. Dzieki temu przycisk Add staje się aktywny. Klikamy i w nowym oknie wpisujemy nasze ability MobileTouchScreen.


Klikamy OK i w oknie z właściwościami naszego projektu pojawiła się nowa pozycja w tabelce właściwościami danej konfiguracji.

Teraz chcąc skompilować projekt, używając nowej konfiguracji, należy ją wybrać z menu w górnej części okna.


Jak popatrzymy na nasz kod to zobaczymy, że NetBeans koloruje tło pod kodem nalezącym do warunkowej kompilacji:


Dodatkowo dodał komentarze na początku linii pomiędzy //#else a //#endif. Dzięki temu kod nie będzie dołączony do kompilowanej aplikacji. Zmiany te są zapisywane w pliku na dysku (polecam sprawdzić) i NetBeans nie zawsze chce się odświeżyć (w sensie widoku pliku źródłowego). Warto wtedy zamknąć i otworzyć na nowo plik, aby wiedzieć co edytować. Ponadto mechanizm ten zapewnia bezbolesny eksport do innego środowiska IDE, które nie wspiera tego mechanizmu. Całość zostanie potraktowana jako zwykły komentarz.

Z drugiej strony mechanizm może utrudniać merge’owanie i śledzenie zmian w kodzie. No chyba że wszyscy będą pamiętać, aby przed commit’em jedną, zawsze tą samą konfigurację ustawić.

Czy blok if else endif to wszystko co daje nam warunkowa kompilacja w NetBeans? Nie. Z ciekawszych opcji mamy jeszcze //#condition NAZWA_ABILITY i dzięki której decydujemy czy dany plik ma być dołączony do danego build’a, czy nie. Deklaracja musi być jednak umieszczona na początku pliku!

No dobra, mamy już skonfigurowany kod, ale co z innymi zasobami? Np, z grafiką, którą np. potrzebujemy tylko do wersji z obsługiwanym ekranem dotykowym? Mamy możliwość zdefiniowania zasobów, które mają się w takiej konfiguracji znaleźć. W tym celu przechodzimy do właściwości projektu i wybieramy Librares & Resources. Odznaczamy Use Values from „DefaultConfiguration” i już możemy dodawać katalogi, biblioteki i inne wymagane projekty.

Nie pozostaje teraz nic innego jak wziąć się do roboty i zacząć odpowiednio dostosowywać nasze mobilne aplikacje.

Brak komentarzy:

Prześlij komentarz