DreamsComeTrue.xt

„tam, gdzie spełniają się marzenia…”

lis
22

Kurs Java ME – II część

Dodano [Listopad 22, 2011]

Witajcie!

„Wytrwałość drogą do sukcesu” – taka myśl mi przyszła do głowy siadając do pisania kolejnej części naszego kursu. Niezmiernie się cieszę że tu jesteście (mam nadzieję że nie „z przypadku”) i że chcecie rozwijać swoje zdolności w oparciu o nowe technologie (czy może być coś piękniejszego?). Nie rozwódźmy się już dalej (hehe – czy pasję programowania można porównać do małżeństwa?) tylko wskoczmy od razu w nasz cyfrowy świat.

Na poprzedniej lekcji dowiedzieliście się czym (ogólnie) jest Java ME, skąd ją można pobrać, jak skonfigurować środowisko pracy a także poznaliście sposób tworzenia najprostszej aplikacji na urządzenia mobilne. Trochę się nawet z nią podroczyliśmy aby następnie ujrzeć efekt naszej pracy na cudownym, kilkucalowym ekraniku…emulatora (na razie).

Dziś „wejdziemy” trochę głębiej, a mianowicie zobaczymy co tak naprawdę znajduje się pod „maską” naszej aplikacji, poznamy kod źródłowy „szkieletu” programu, który będziemy wykorzystywać przez cały kurs, dowiecie się jak wygląda cykl życia aplikacji mobilnej, a także wprowadzimy pierwsze kontrolki „wysokiego poziomu” (jeśli nie pamiętacie o co chodzi, przeczytajcie jeszcze raz poprzednią lekcję).

Dużo tego. Nie przerażajcie się – będzie jeszcze więcej :) Ale czyż nie dlatego tu jesteśmy?

 

Zaczynamy.

 

Rozdział drugi – „Co diabeł skrywa pod spódnicą”

 

Zanim rozpoczniemy tworzenie nowego projektu, proszę Was byście jeszcze raz spojrzeli na ten, nad którym pracowaliśmy ostatnio (jeśli nie macie go u siebie, możecie ściągnąć go z mojej strony – link jest na końcu pierwszej części kursu). Dla przypomnienia, zamieszczę tutaj kod źródłowy (odpowiednio sformatowany), który wygenerował nam NetBeans – jeśli chcecie sami go zobaczyć w Waszym IDE, kliknijcie dwa razy na nazwę Waszego projektu w okienku Projects, potem na Source Packages, następnie hello a potem HelloMIDlet.java (gdy zamiast kodu pojawiło się okienku przebiegu działania programu lub budowania GUI, wybierzcie Source z menu ViewEditors:

package hello;
  1.  
  2. import javax.microedition.midlet.*;
  3.  
  4. import javax.microedition.lcdui.*;
  5.  
  6. public class HelloMIDlet extends MIDlet implements CommandListener
  7.  
  8. {
  9.  
  10. private boolean midletPaused = false;
  11.  
  12. private Command exitCommand;
  13.  
  14. private Form form;
  15.  
  16. private StringItem stringItem;
  17.  
  18. /**
  19.  
  20. * The HelloMIDlet constructor.
  21.  
  22. */
  23.  
  24. public HelloMIDlet ()
  25.  
  26. {
  27.  
  28. }
  29.  
  30. /**
  31.  
  32. * Initilizes the application.
  33.  
  34. * It is called only once when the MIDlet is started. The method is called before the <code>startMIDlet</code> method.
  35.  
  36. */
  37.  
  38. private void initialize() {
  39.  
  40. // write pre-initialize user code here
  41.  
  42. // write post-initialize user code here
  43.  
  44. }
  45.  
  46. /**
  47.  
  48. * Performs an action assigned to the Mobile Device – MIDlet Started point.
  49.  
  50. */
  51.  
  52. public void startMIDlet() {
  53.  
  54. // write pre-action user code here
  55.  
  56. switchDisplayable(null, getForm());
  57.  
  58. // write post-action user code here
  59.  
  60. }
  61.  
  62. /**
  63.  
  64. * Performs an action assigned to the Mobile Device – MIDlet Resumed point.
  65.  
  66. */
  67.  
  68. public void resumeMIDlet() {
  69.  
  70. // write pre-action user code here
  71.  
  72. // write post-action user code here
  73.  
  74. }
  75.  
  76. /**
  77.  
  78. * Switches a current displayable in a display. The display instance is taken from getDisplay method. This method is used by all actions in the design for switching displayable.
  79.  
  80. * @param alert the Alert which is temporarily set to the display; if null, then nextDisplayable is set immediately
  81.  
  82. * @param nextDisplayable the Displayable to be set
  83.  
  84. */
  85.  
  86. public void switchDisplayable(Alert alert, Displayable nextDisplayable) {
  87.  
  88. // write pre-switch user code here
  89.  
  90. Display display = getDisplay();
  91.  
  92. if (alert == null) {
  93.  
  94. display.setCurrent(nextDisplayable);
  95.  
  96. } else {
  97.  
  98. display.setCurrent(alert, nextDisplayable);
  99.  
  100. }
  101.  
  102. // write post-switch user code here
  103.  
  104. }
  105.  
  106. /**
  107.  
  108. * Called by a system to indicated that a command has been invoked on a particular displayable.
  109.  
  110. * @param command the Command that was invoked
  111.  
  112. * @param displayable the Displayable where the command was invoked
  113.  
  114. */
  115.  
  116. public void commandAction(Command command, Displayable displayable) {
  117.  
  118. // write pre-action user code here
  119.  
  120. if (displayable == form) {
  121.  
  122. if (command == exitCommand) {
  123.  
  124. // write pre-action user code here
  125.  
  126. exitMIDlet();
  127.  
  128. // write post-action user code here
  129.  
  130. }
  131.  
  132. }
  133.  
  134. // write post-action user code here
  135.  
  136. }
  137.  
  138. /**
  139.  
  140. * Returns an initiliazed instance of exitCommand component.
  141.  
  142. * @return the initialized component instance
  143.  
  144. */
  145.  
  146. public Command getExitCommand() {
  147.  
  148. if (exitCommand == null) {
  149.  
  150. // write pre-init user code here
  151.  
  152. exitCommand = new Command("Exit", Command.EXIT, 0);
  153.  
  154. // write post-init user code here
  155.  
  156. }
  157.  
  158. return exitCommand;
  159.  
  160. }
  161.  
  162. /**
  163.  
  164. * Returns an initiliazed instance of form component.
  165.  
  166. * @return the initialized component instance
  167.  
  168. */
  169.  
  170. public Form getForm() {
  171.  
  172. if (form == null) {
  173.  
  174. // write pre-init user code here
  175.  
  176. form = new Form("Welcome", new Item[] { getStringItem() });
  177.  
  178. form.addCommand(getExitCommand());
  179.  
  180. form.setCommandListener(this);
  181.  
  182. // write post-init user code here
  183.  
  184. }
  185.  
  186. return form;
  187.  
  188. }
  189.  
  190. /**
  191.  
  192. * Returns an initiliazed instance of stringItem component.
  193.  
  194. * @return the initialized component instance
  195.  
  196. */
  197.  
  198. public StringItem getStringItem() {
  199.  
  200. if (stringItem == null) {
  201.  
  202. // write pre-init user code here
  203.  
  204. stringItem = new StringItem("Hello", "Hello, World!");
  205.  
  206. // write post-init user code here
  207.  
  208. }
  209.  
  210. return stringItem;
  211.  
  212. }
  213.  
  214. /**
  215.  
  216. * Returns a display instance.
  217.  
  218. * @return the display instance.
  219.  
  220. */
  221.  
  222. public Display getDisplay ()
  223.  
  224. {
  225.  
  226. return Display.getDisplay (this);
  227.  
  228. }
  229.  
  230. /**
  231.  
  232. * Exits MIDlet.
  233.  
  234. */
  235.  
  236. public void exitMIDlet ()
  237.  
  238. {
  239.  
  240. switchDisplayable (null, null);
  241.  
  242. destroyApp (true);
  243.  
  244. notifyDestroyed ();
  245.  
  246. }
  247.  
  248. /**
  249.  
  250. * Called when MIDlet is started.
  251.  
  252. * Checks whether the MIDlet have been already started and initialize/starts or resumes the MIDlet.
  253.  
  254. */
  255.  
  256. public void startApp ()
  257.  
  258. {
  259.  
  260. if (midletPaused)
  261.  
  262. {
  263.  
  264. resumeMIDlet ();
  265.  
  266. } else
  267.  
  268. {
  269.  
  270. initialize ();
  271.  
  272. startMIDlet ();
  273.  
  274. }
  275.  
  276. midletPaused = false;
  277.  
  278. }
  279.  
  280. /**
  281.  
  282. * Called when MIDlet is paused.
  283.  
  284. */
  285.  
  286. public void pauseApp ()
  287.  
  288. {
  289.  
  290. midletPaused = true;
  291.  
  292. }
  293.  
  294. /**
  295.  
  296. * Called to signal the MIDlet to terminate.
  297.  
  298. * @param unconditional if true, then the MIDlet has to be unconditionally terminated and all resources has to be released.
  299.  
  300. */
  301.  
  302. public void destroyApp (boolean unconditional)
  303.  
  304. {
  305.  
  306. }
  307.  
  308. }

Trochę długi ten kod, czyż nie? Nie martwcie się, tak naprawdę aplikację na telefon można zmieścić w kilku linijkach, o czym niedługo się przekonacie. Jednak tutaj – mamy jeszcze wiele dodatkowych rzeczy, dzięki czemu korzystanie z aplikacji jest wygodniejsze. Pewnie wielokrotnie obiło się Wam o uszy słowo „MIDlet” – i zastanawiacie się czym on tak naprawdę jest i dlaczego o nim wspominamy podczas tego kursu.

 

„Na początku, Bóg stworzył…”

 

MIDlet – to kolaż dwóch słów: „MID” + „let”. Pierwsze z nich odnosi się do pojęć które przyswaliśmy sobie w poprzedniej lekcji: Mobile Information Device Profile – czyli zestaw wymagań jakie musi spełniać dane urządzenie mobilne, by mogło obsłużyć naszą aplikację. Drugie, to skrót od słowa „applet” – znają je wszyscy, którzy dłużej programują w Javie, i dotyczy aplikacji uruchamianych w przeglądarce internetowej na wirtualnej maszynie Javy.

Konkluzja – MIDlet to aplikacja przeznaczona na urządzenie mobilne. Z czego się składa MIDlet? Tworzą go zazwczyaj dwa pliki – ich nazwa zawiera w sobie nazwę naszej aplikacji, natomiast jeden z nich ma rozszerzenie JAR a drugi JAD. Czym są te pliki?

  • plik JAR (Java Archive) – to najogólniej mówiąc paczka przechowująca kod wykonywalny naszej aplikacji wraz z wszystkimi niezbędnymi do jej działania danymi (zasobami). Znajdziecie więc w niej skompilowane pliki CLASS (o nich później), wszelkie grafiki, dźwięki i inne dane z których korzysta nasza aplikacja oraz plik manifestu o którym opowiem za chwilę. Co ciekawe – pliki JAR możecie otwierać każdym narzędziem służącym do dekompresji danych (jak np. 7-Zip) gdyż do ich stworzenia wykorzystuje się właśnie algorytm ZIP. Dzięki temu możecie podejrzeć, co twórca aplikacji umieścił w jej wnętrzu.
  • plik JAD (Java Archive Descriptor) to zwykły plik tekstowy opisujący naszą aplikację, tak, by wirtualna maszyna która ją uruchamia (czyli nasz ukochany telefon) wiedziała jak ma postąpić podczas ładowania pliku JAR. Plików JAD nie będziemy zwykle edytować, gdyż całkiem dobrze robi to za nas nasze IDE (NetBeans bądź Eclipse).

Zastanawiacie się pewnie – skoro w poprzedniej lekcji utworzyliśmy aplikację Java ME, sprawdziliśmy w emulatorze jak ona działa – to by znaczyło, że gdzieś te pliki musiały zostać wygenerowane. Nie mylicie się :) Niektórzy z Was pewnie już odkryli miejsce, gdzie kompilator zapisał sobie nasz plik wykonywalny: przy otwartym katalogu z projektem znajduje się katalog dist – wejdźcie w niego, a Waszym oczom ukaże się taki oto widok:

 

Katalog lib możecie zignorować. Jak widzicie – mamy dwa, omówione powyżej pliki. Oczywiście nie można ich tak prosto uruchomić, klikając dwukrotnie na Projekt1.jar gdyż są one przeznaczone do uruchomienia w emulatorze (czyli np. w naszym IDE). Jednak zdradzę Wam jeden sekret który niewąptliwie przyczyni się do naszej dominacji nad ludzkoś….eeee… – do uszczęśliwienia naszej twarzy :) Te dwa pliki…to tak naprawdę WSZYSTKO czego potrzebujecie by uruchomić Waszą aplikację na telefonie! Nie więcej, nie mniej – wystarczy je tylko skopiować na swój telefon i zainstalować (nie podam metody instalacji, gdyż każdy producent urządzenia mobilnego ustanowił swoje standardy; jeśli nie wiecie jak to zrobić poczytajcie w dokumentacji lub Internecie pod hasłem „Instalowanie aplikacji Java” dla swojego telefonu). Kurtyna wreszcie opadła – teraz już możemy tworzyć pełnowymiarowe aplikacje podbijające masowe rynki gdyż wiemy co należy zrobić, by skłonić naszego wibrującego przyjaciela (bez skojarzeń proszę :) ) do współpracy.

 

O czym my tu ostatnio… A tak, MIDlety :) Programowanie urządzeń mobilnych polega właśnie na pisaniu MIDletów – bez względu na to, czy będzie to kalendarz biznesowy, aplikacja do sprawdzania pogody czy własna implementacja gry Kółko i Krzyżyk – wszystkie z nich zachowują ten sam, podstawowy szkielet. Przyjżyjmy się mu z bliska.

 

Każdy MIDlet jest klasą (Javy, dla ścisłości. :) ) Żeby jednak nasz telefon wiedział że ma do czynienia z aplikacją mobilną – nasza klasa musi dziedziczyć po – uwaga, będzie niespodzianka – klasie „MIDlet” :)

To nie wszystko. Nasz program musi posiadać również zdefiniowane trzy metody:

 

  1. startApp()
  2. destroyApp()
  3. pauseApp()

które to obsługują poszczególne stany MIDletu. Czym jest stan? Najogólniej mówiąc – stan definiuje „osobowość” w jakiej znajduje się lub może się znaleźć nasza aplikacja. MIDlety posiadają trzy główne stany:

  • aktywny
  • spauzowany
  • zniszczony

a naszym zadaniem jest ich poprawne obsłużenie. Cykl pracy aplikacji mobilnej przedstawia następujący wykres:

MIDlet rozpoczyna pracę po utworzeniu instancji jego obiektu (a więc przy użyciu new) – ważne jest więc, by klasa dziedzicząca po MIDlet posiadała publiczny, domyślny konstruktor! Wywoływana jest wtedy metoda startApp, której celem jest przygotwanie aplikacji. Umieszcza się tutaj zwyczajowo kod ładujący potrzebne zasoby, tworzący obiekty pomocnicze, ekrany (o ekranach było w poprzedniej lekcji), itp. . Jeśli w trakcie tworzenia obiektu, MIDlet wywoła wyjątek – jest on niszczony. Jak widzicie na wykresie, MIDlet tylko chwilowo znajduje się w stanie Paused, tuż po jego utworzeniu – zaraz potem przechodzi w stan Active (aktywny), tuż po wykonaniu kodu znajdującego się w metodzie o sygnaturze:

  1. protected void startApp(  ) throws MIDletStateChangeException;

Jeżeli nie chcemy, by nasza aplikacja uruchomiła się natychmiast, w trakcie wywoływania tej metody rzucamy wyjątek klasy MIDletStateChangeException co spowoduje, że aplikacja znajdzie się w stanie Paused i będziemy ją mogli uruchomić później. Jeżeli jednak wystąpi błąd, który ma spowodować że aplikacja nie będzie działała poprawnie (np. nie może odnaleźć pliku z zasobami jak grafika, dźwięki) – powinniśmy wywołać metodę notifyDestroyed (o niej później). Ostatecznie, gdy wyrzucimy jakikolwiek inny wyjątek, znaczyć to będzie, iż wystąpił tzw. błąd fatalny, aplikacji nie da się już uratować i trzeba ją zamknąć przy wykorzystaniu metody destroyApp. Po wykonaniu kodu inicjalizycyjnego zawartego w metodzie startApp…MIDlet kończy swoją pracę :) Tak jest, nie ma tu jakichś ukrytych sztuczek, nie ma tajemniczo wygenerowanej pętli przyjmującej polecenia użytkownika – to od nas w 100% zależy jak ma wyglądać interakcja z MIDletem. Zwykle, zaraz po zainicjowaniu wszystkich niezbędnych obiektów tworzymy interfejs użytkownika (GUI) i pozwalamy użytkownikowi na wprowadzanie komunikatów (przycisków). Można również uruchomić osobny wątek w którym to będzie wykonywana logika aplikacji, bądź też dodać zaplanowane zadania, które MIDlet będzie wykonywał w ustalonym czasie. Gdy MIDlet jest aktywny może przyjąć jeszcze dwa inne stany: zapauzowany oraz zniszczony. Kiedy MIDlet jest zapauzowany? Nie mamy sami na to wpływu – przejście MIDletu w ten stan dokonuje sama maszyna wirtualna Javy ME, kiedy wykryje jakąś akcję zewnętrzną, jak np. nadchodzące połączenie telefoniczne. Wywoływana jest wtedy właśnie metoda:

  1. protected abstract void pauseApp(  );

a sam MIDlet staje się zadaniem w tle (drugorzędnym). Dlaczego tak ważne jest obsłużenie tej metody? Ano – w czasie gdy MIDlet jest zapauzowany TRACI dostęp do ekranu naszego telefonu! Nie ma sensu zatem ciągła aktualizacja jego logiki, gdyż zużywa się wtedy tylko niepotrzebnie i tak już ograniczone zasoby naszego urządzenia. Zwykle, w stanie zapauzowania wstrzymuje się wykonywanie kodu odpowiedzialnego za odświeżanie ekranu, można też np. wyłączyć obsługę dźwięków w naszej aplikacji, zablokować timery, zamknąć połączenia sieciowe itp. – robić wszystko co niezbędne by aplikację „podtrzymać na życiu” ale nie pozwolić jej rozgrzewać niepotrzebnie naszego urządzonko :) . Zauważcie, że gdy skończy się połączenie telefoniczne, i platforma Javy wykryje, że można wznowić działanie MIDletu, PONOWNIE jest wywoływana metoda startApp! Pojawiło się zatem interesujące pytanie: przecież w metodzie tej umieszczony był cały kod inicjalizacyjny! Czy zatem wszystkie obiekty tam powstałe będą utworzone od nowa? Odpowiedź brzmi: niesetety tak. Dlatego też – bardzo ważny jest rozsądek przy projektowaniu aplikacji – by uniknąć niepotrzebnych i nieporządanych efektów jakie mogą powstać przy wielokrotnym alokowaniu tych samych obiektów. Czy jest na to jakieś rozwiązanie? Oczywiście :) Przecież mamy jeszcze konstruktor MIDlet’u! Zasada jest taka – w metodzie startApp umiesczamy inicjalizację tych wszystkich obiektów, które będą zwalniane w metodzie pauseApp, do konstruktora MIDlet’u ładujemy natomiast cały pozostały kod – proste, czyż nie?
Może się jednak zdarzyć, iż nasz MIDlet nie będzie chciał wrócić „do życia”, np. gdy skończy się połączenie telefoniczne, z jakichś nieznanych powodów nie będzie możliwe powrócenie ze stanu „zapauzowany” na stan „aktywny” (gdyż np. zostanie rzucony wyjątek typu: MIDletStateChangeException). Co się dzieje wtedy? Nasza aplikacja przechodzi w trzeci stan: „stan zniszczenia”. Jak nazwa nam podpowiada – to miejsce, z którego nie możemy powrócić do „normalnego” funkcjonowania MIDletu ponieważ za chwilę zostanie on usunięty z pamięci. W metodzie tej oprogramowujemy całą logikę odpowiedzialną za zwalnianie zasobów, które wcześniej zaalokowaliśmy, zapisujemy stan aplikacji do późniejszego uruchomienia, wyłączamy dźwięki, zamykamy połączenia sieciowe, zabijamy wszystkie pracujące wątki, itd.. Deklaracja metody którą musimy oprogramować wygląda następująco:

  1. public abstract void destroyApp(boolean unconditional) throws MIDletStateChangeException;

Jak widzicie, metoda ta przyjmuje parametr – unconditional, z którego zrozumieniem może być troche problemów. Generalnie – parametr ten przeważnie ma wartość „true” – co oznacza, że MIDlet nie może wpływać na przebieg procesu jego zamykania. Tak więc gdy gdzieś w kodzie znajdzie się fragment:

  1. destroyApp (true);
  2. notifyDestroyed ();

wirtualna maszyna Javy wykona kod znajdujący się w tej metodzie (zwolnienie zasobów) a następnie wywoła metodę notifyDestroyed (o której za chwilę). Gdy jednak do tej metody przekażemy argrument „false” musimy pamiętać by umieścić ten kod wywołujący w bloku „try-catch”. Teraz, gdy maszyna Javy wykona kod znajdujący się w metodzie destroyApp, nie przejdzie do dalszego wykonywania instrukcji (a więc metoda notifyDestroyed jako kolejna się nie wykona) – tylko wyrzuci wyjątek typu MIDletStateChangeException, którego blok obsługi powinien pozostać raczej pusty. Tak więc, poprawny kod dla tego przypadku wygląda następująco:

  1. try
  2. {
  3. destroyApp (true);
  4. notifyDestroyed ();
  5. }
  6. catch (MIDletStateChangeException ex)
  7. {
  8. }

Do czego służy, o tajemniczo brzmiącej nazwie metoda notifyDestroyed? Ma ona za zadanie poinformować wirtualną maszynę Javy: tak, skończyłem już swoją pracę, możesz mnie usunąć z pamięci :) Jakie to proste! Ważne dla nas jest zapamiętać następujące fakty:
- gdy maszyna Javy sama chce zakończyć naszą aplikację (bo np. brakuje pamięci lub wystąpił wyjątek), wywoła ona metodę destroyApp z parametrem „true” – co spowoduje wywołanie kodu w niej się znajdującego i bezwarunkowe wyjście z aplikacji. Metoda notifyDestroyed NIE JEST już wtedy wywoływana,
- kiedy sami chcemy zakończyć pracę MIDletu (skończył obliczenia, użytkownik wybrał z menu opcję „Wyjście”, etc) – musimy ręcznie wywołać metodę notifyDestroyed, a za kilka chwil maszyna Javy usunie nasz program z pamięci. Uwaga! W tym przypadku NIE JEST również wywoływana „magicznie” metoda destroyApp, tuż przed wyjściem z aplikacji ponieważ maszyna Javy zakłada, iż aplikacja już zwolniła swoje zasoby jeśli chce być zamknięta. Dlatego – zaleca się taki schemat postępowania jak przedstawiłem powyżej – najpierw wywołanie metody: destroyApp, następnie notifyDestroyed. Kropka.
Aha – jeżeli myślicie o poprawnym zamykaniu MIDletu za pomocą takich „sztuczek” jak System.exit () – nie uda się Wam to, gdyż maszyna Javy rzuci wtedy wyjątkiem typu SecurityException. Tak więc używanie wspomnianych wyżej funkcji jest „jedyną słuszną” metodą na zamknięcie naszej aplikacji.
Co ciekawe, MIDlet może jeszcze wywołać dwie metody, które wpływają na jego stan. Pierwsza z nich:

  1. public final void notifyPaused(  );

służy do poinformowania systemu, iż MIDlet ma się znaleźć w stanie „zapauzowania”. Występuje tu jednak ta sama zależność jak przy stanie „zniszczenia” – a więc, gdy ręcznie wywołamy tę metodę, MIDlet NIE WYKONA kodu znajdującego się w metodzie pauseApp, gdyż zakłada iż metoda ta została już przetworzona (dzieje się tak automatycznie, gdy aplikacja zostanie zapauzowana przez samą maszynę Javy). Musimy wobec tego stosować się do tego samego wzoru jak opisałem powyżej.
Ostatnia z metod do obsługi stanu aplikacji:

  1. public final void resumeRequest(  );

jest „przeciwieństwem” metody notifyPaused. Informuje ona platformę Javy, że ze stanu „zapauzowania” chcemy z powrotem przejść w stan „aktywny”. Po kilku chwilach aplikacja może zostać wznowiona poprzez ponowne wywołanie metody startApp. Omawiana metoda zwykle jest wywoływana przez zewnętrze wątki aplikacji, bądź timer’y które zostały uaktywnione gdy aplikacja została zawieszona.
Uff! Dużo tego, na razie tyle teorii nam wystarczy – czas zastosować ją w praktyce. Przewińcie stronę kilkadziesiąt centymetrów wyżej – zamieściłem tam kod projektu na którym teraz ćwiczymy. Przeglądając go na pewno, w jego dolnej części zauważycie trzy najważniejsze metody każdego MIDletu – a więc: startApp, pauseApp i destroyApp. Pozostałym kodem nie przejmujcie się – został on wygenerowany przez NetBeans’a i służy (jak się wczytacie) do wygodnego korzystania z często powtarzających się zadań przy programowaniu MIDletu. Na chwilę obecną możemy jednak o wszystkim poza tymi trzema metodami – zapomnieć.
Naszą zabawę rozpoczniemy z pierwszą z nich: startApp. Usuńcie kod w niej się znajdujący i zastąpcie go tak, by funkcja wyglądała w następujący sposób:

  1. public void startApp ()
  2.     {
  3.         Display display = getDisplay();
  4.         Form form = new Form ("Java ME – czesc II");
  5.         StringItem stringItem = new StringItem ("Moja druga aplikacja JavaME\n", ":)");
  6.         form.append (stringItem);
  7.         display.setCurrent(form);
  8.     }

Resztę kodu pozostawcie bez zmian. Po skompilowaniu i uruchomieniu Twoim oczom ukaże się piękny widok:

Gratuluję! Udało Ci się stworzyć aplikację dla JavyME edytując kod źródłowy :) . To dopiero początek, a możliwości są niemałe. Zanim przejdziemy dalej – kilka słów wyjaśnienia dla kodu jaki dodaliśmy. Zaczęliśmy od:

  1. Display display = getDisplay();

Dzięki tej linijce, do zmiennej display możemy pobrać referencję na aktualny „ekran” (o ekranach mówiłem na poprzedniej lekcji) – dzięki czemu będziemy mogli na nim rysować. Zauważcie, że metody getDisplay nigdzie w kodzie nie ma zdefiniowanej a mimo to ją wywołujemy. Jak to możliwe? Nasza klasa dziedziczy przecież po klasie MIDlet więc możemy podejrzewać, że to w niej jest ta „magia” zdefiniowana (podejrzenia całkiem słuszne :) ) – i jak się później okaże dzięki metodom tej klasy zrobimy jeszcze kilka pożytecznych rzeczy. Mając referencje na ekran tworzymy obiekt klasy Form:

  1. Form form = new Form ("Java ME – czesc II");

Klasa Form służy do definiowana obiektów które będą zajmować wirtualnie nasz cały ekran i będzie możliwe umieszczanie w nich tzw. kontrolek. O co chodzi? Występuje tu ta sama analogia co w programowaniu komputerów. Klasa Display to odpowiednik naszego komputerowego ekranu, pulpitu. Natomiast klasa Form – to nic innego jak okienko aplikacji. Kontrolka natomiast to wszystko to, co występuje w oknie, a więc przyciski, listy wyboru, przyciski wyboru (tzw. checkbox, radiobutton) oraz etykiety (czyli pola wypełnione tekstem którego nie możemy edytować). Kontrolek jest wystarczająco dużo by poświęcić im tylko jeden rozdział, dlatego też w kolejnych lekcjach będę je sukcesywnie omawiał. Na razie poznaliśmy najważniejszy element „budulcowy” aplikacji – a więc formę (będę używał bardziej swojsko brzmiącego określenia – formatkę) na której umieszczamy pozostałe elementy. Zauważcie, że sama formatka nie ma reprezentacji wizualnej, czyli nie ma ramki, przycisków maksymalizacji, minimalizacji, ikonki, itd. – czyli tego wszystkiego co występuje w systemach operacyjnych na naszych komputerach. Wszystko to dlatego, by nie marnowała niepotrzebnie miejsca na ograniczonym ekraniku naszego telefonu, a dodatkowo – w danej chwili, na ekranie może być widoczne TYLKO jedna formatka, tak więc nie ma możliwości zmiany ich rozmiaru (choć jest możliwość przełączania się między nimi). Formatka posiada za to tytuł, który jest widoczny w jej górnej części i który – jak się domyślacie przekazany został w jej konstruktorze. Następnie tworzymy naszą pierwszą kontrolkę:

  1. StringItem stringItem = new StringItem ("Moja druga aplikacja JavaME\n", ":)");

Klasa StringItem, dziedzicząca po Item reprezentuje zwykłe, statyczne pole tekstowe (nie możemy go edytować z poziomu telefonu), które może służyć, np. jako pole informacyjne. Przyjmuje ona dwa parametry: pierwszy z nich określa etykietę czyli dodatkowy opis do naszego tekstu, nastomiast drugie – tekst właściwy. Po pomyślnym stowrzeniu tej kontrolki NIC na ekranie nie zobaczycie :) Dzieje się tak dlatego – iż mimo że rezyduje ona już w pamięci, to nie jest skojarzona z żadną formatką (a jak pamiętacie – formatka jest miejscem do przechowywania kontrolek właśnie). Aby związać ze sobą te dwa obiekty potrzebna jest linijka:

  1. form.append (stringItem);

która spowoduje dodanie naszej kontrolki do listy kontrolek kontrolowanych przez formatkę. Teraz – jakiekolwiek działania na formatce będą wpływały również na naszą kontrolkę (co umożliwi np. jej rysowanie). Mimo to – na ekranie i tak jeszcze nic nie zobaczycie :) :) Dopiero ostatnia linijka:

  1. display.setCurrent(form);

spowoduje przypisanie naszej formatki do aktualnego ekranu naszej aplikacji – co spowoduje jej wyświetlenie. Metoda setCurrent klasy Display przyjmuje argument typu Displayable jako argument – a skoro każda klasa typu Form implementuje ten interfejs – może zostać ustawiona jako aktualny ekran – ot, i cała magia!
Czas na obslugę metody pauseApp. Tak samo jak poprzednio, umieśćcie w niej następujący kod:

  1. public void pauseApp ()
  2.     {
  3.              licznik ++;
  4.     }

Na samym dole aplikacji dodajcie następujące pole:

  1. private int licznik = 0;

A do metody startApp dopiszcie na końcu następujące linijki:

  1.     pauseApp ();
  2.         notifyPaused ();
  3.         resumeRequest ();

(będą one symulować przychodzące połączenie do Waszego telefonu – a więc umożliwią wprowadzanie aplikacji w stan „zapauzowania”). Po skompilowaniu i uruchomieniu – zauważycie że metody startApp oraz pauseApp wywoływane są naprzemiennie co powoduje wyświetlanie zmieniającego się licznika naszej aplikacji:

Super! Widzimy że wszystko działa jak należy. Pamiętajcie jednak że metoda ta nie powinna być wywoływana z wnętrza naszej aplikacji – tym zajmuje się automatycznie maszyna Javy – naszym zadaniem jest tylko poprawne jej obsłużenie – czyli zatrzymanie aktualizacji przebiegu wszystkich wątków naszej aplikacji (spokojnie, aplikacje wielowątkowe również będziemy pisać).
Czas na ostatnią metodę – kończenie pracy naszego MIDletu. Jak pamiętacie – możemy to wymusić programowo dzięki wywołaniu metody notifyDestroyed. Zedytujmy więc kod naszej metody startApp tak, aby wyglądała następująco:

  1.  public void startApp ()
  2.     {
  3.         Display display = getDisplay();
  4.         Form form = new Form ("Java ME – czesc II");
  5.         stringItem = new StringItem ("Licznik: ", Integer.toString (licznik));
  6.         form.append (stringItem);
  7.  
  8.         display.setCurrent (form);
  9.  
  10.         pauseApp ();
  11.         notifyPaused ();
  12.         resumeRequest ();
  13.  
  14.         if (licznik > 20)
  15.         {
  16.             try
  17.             {
  18.                 notifyDestroyed ();
  19.             }
  20.             catch (InterruptedException ex)
  21.             {
  22.                 ex.printStackTrace ();
  23.             }
  24.         }
  25.     }

Interesujące dla nas w tym przypadku są linijki zaczynające się od warunku:

  1. if (licznik > 20)

Jeśli licznik ma określoną wartość, wymuszamy na aplikacji jej zamknięcie poprzez wysłanie do maszyny Javy zapytania w metodzie notifyDestroyed. Ponieważ maszyna Javy nie widzi ku temu przeciwwskazań (a czemu miałaby?) zamyka posłusznie naszą aplikację. Zagadka na przypomnienie – czy wywołana zostanie metoda destroyApp? Aby to sprawdzić: do metody startApp zaraz poniżej wywołania metody:

  1. notifyDestroyed ();

dodajmy linijkę:

  1. Thread.sleep (4000);

co spowoduje uśpienie wykonania naszej aplikacji na 4 sekundy tuż przed jej zakończeniem, natomiast do sama metoda destroyApp powinna wyglądać następująco:

  1.  public void destroyApp (boolean unconditional)
  2.     {
  3.         stringItem.setText ("Konczymy…");
  4.     }

co powinno spowodować przypisanie nowego napisu do naszej kontrolki. Gdy uruchomimy aplikację, okazuje się, że…tekst na kontrolce w ogóle się nie zmienia – a znaczy to, że zgodnie z przewidywaniami – nasza implementacja metody destroyApp nie została uruchomiona. Aby to zrobić, musimy ją jawni wywołać zaraz przed wywołaniem metody notifyDestroyed w metodzie startApp, która ostatecznie powinna wyglądać następująco:

  1. public void startApp ()
  2.     {
  3.         Display display = getDisplay();
  4.         Form form = new Form ("Java ME – czesc II");
  5.         stringItem = new StringItem ("Licznik: ", Integer.toString (licznik));
  6.         form.append (stringItem);
  7.  
  8.         display.setCurrent (form);
  9.  
  10.         pauseApp ();
  11.         notifyPaused ();
  12.         resumeRequest ();
  13.  
  14.         if (licznik > 20)
  15.         {
  16.             try
  17.             {
  18.                 destroyApp (true);
  19.                 notifyDestroyed ();
  20.  
  21.                 Thread.sleep (2000);
  22.             }
  23.             catch (InterruptedException ex)
  24.             {
  25.                 ex.printStackTrace ();
  26.             }
  27.         }
  28.     }

Dopiero teraz naszym oczom ukaże się oczekiwany rezultat:

Na tym dziś skończymy. Z wydawałoby się prostego tematu jakim jest wprowadzenie do MIDletów, powstała dość rozbudowana lekcja, która mam nadzieję – nie zamieszała Wam zbytnio w głowach :) Dzisiaj dowiedzieliście się:
- czym jest MIDlet, jakie są jego składowe i jaka jest jego fizyczna reprezentacja na dysku twardym,
- jakie stany występują w MIDletach, jak się pomiędzy nimi przełączać, czego ustrzegać się podczas ich zarządzania,
- jak wygląda podstawowy szkielet aplikacji JavaME,
- kilku zdań wprowadzenia o budowaniu interfejsów użytkownika na urządzenia mobilne z wykorzystaniem API „wysokiego” poziomu.

Na kolejnej lekcji poznamy sposób obsługi komunikatów w MIDletach, dzięki czemu będziemy mogli odpowiadać w naszej aplikacji na reakcje użytkownika (naciśnięcia klawiszy).
Dziękuję Wam wszystkim za uwagę :)
Do usłyszenia!

paź
20

Kurs Java ME – I część

Dodano [Październik 20, 2011]

 

Witajcie w pierwszej części kursu poświęconego programowaniu urządzeń mobilnych a w szczególności telefonów komórkowych. Postanowiłem, że umieszczę taki materiał na swoim blogu, zarówno jako sprawdzenie swoich umiejętności programistycznych jak i też – by przystępnym (mam nadzieję :) ) językiem wyjaśnić różne zawiłości które mogą sprawiać początkującym programistom trudności. Nie będę się zajmował (na razie) tak nowoczesnymi – choć istniejącymi już od wieków technologiami – jak Iphone czy Android – na nie też być może przyjdzie czas :) W obecnej chwili skupię się raczej na tych wszystkich magicznych elektronicznych cudeńkach na które może sobie pozwolić większość ludzkości – a więc: jeśli tylko Wasz telefon wspiera uruchamianie aplikacji przygotowanych na platformę Java ME (Micro Edition) – nie uciekajcie, właśnie na Was czekam. Mam nadzieję, że wszyscy Ci, którzy tu trafią mają jako-takie pojęcie o programowaniu (szczególnie podstawy Javy byłyby na miejscu) – jeśli jednak pojawi się zapotrzebowanie – taki wprowadzający mini-kurs również mogę przygotować.

A więc, zapnijcie pasy, rozpoczynamy przygodę :)

 

  1. Rozdział pierwszy – „Jak sobie pościelesz…”

 

Jedna z prawd programistycznych brzmi: „najwięksi hardkorzy programują w Notatniku” :)

Jakkolwiek może wydawać się to Wam śmieszne, nie ukrywam – jest w tym trochę racji. Przede wszystkim wyrabia się dzięki temu nawyk częstego sięgania do dokumentacji, przy braku podpowiedzi ze strony IDE (wikipedia LINK) programistycznego zmuszeni (albo zachęcani) jesteśmy do głębszego poznawania API w jakim nam przyszło pracować, a także – czasami zupełnie niepotrzebne jest uruchamianie całej tej maszynerii po to by stworzyć aplikację w czterdziestu linijkach kodu, by pochwalić się przed dziewczyną jak to ekranik w jej telefonie może fajnie mrugać i wyświetlać imię jedynego Ukochanego (zupełnie nieprzypadkowo podaję taki przykład, sami zobaczycie :) ).

Jednak w dobie nowoczesnej technologii taka metodologia tworzenia oprogramowania nie za bardzo się przyjęła. Jeszcze wielokrotnie będę wspominał TO słowo, ale zapamiętajcie – dla klienta równorzędny z jakością wykonania, a może nawet – o większej wartości jest dziś CZAS. Dlatego więc niezbędne są narzędzia, pewne „ulepszacze” które zapewnią nam najlepszą wydajność. Tak jest w każdej innej dziedzinie zawodowej, nie inaczej jest w informatyce. W miarę, jak ten kurs będzie rósł, będę prezentował różne narzędzia potrzebne/przydatne w codziennej pracy programistycznej.

Co więc będzie nam potrzebne w dalszej wędrówce?

  • maszyna wirtualna Javy, czyli w zasadzie całe środowisko uruchomieniowe w którym będzie pracowała nasza aplikacja. Tutaj przyjemna niespodzianka, gdyż od samego początku jest ona dostępna wszędzie (na każdą platformę, urządzenie) i dla wszystkich – zupełnie za darmo. Właśnie te aspekty zadecydowały o tak ogromnej popularności i wszechstronności Javy. Możecie ją pobrać na swój komputer ze strony firmy Oracle → link.Oczywiście maszyny tej nie zainstalujecie na Waszych telefonach – ta, którą przed chwilą ściągnęliście na Wasz komputer posłuży nam do testów naszych aplikacji. Nie przejmujcie się jednak, gdyż praktycznie w każdym obecnie istniejącym na rynku urządzeniu mobilnym powinna być już wbudowana przez producenta jakaś implementacja maszyny Javy a sprawdzić to możecie chociażby pytając Waszą ulubioną wyszukiwarkę internetową czy z nazwą Waszego telefonu skojarzone są takie słowa kluczowe jak: „Java”, „Java ME”, „MIDP”, „CLDC” – jeśli któreś z nich wystąpi – jesteśmy na dobrej drodze,
  • SDK dla Javy ME – dużo skrótów :) S(ource) D(evelopment) K(it) – to zbiór bibliotek, kodów źródłowych i dokumentacji może niekoniecznie potrzebnych do programowania, ale w OGROMNYM stopniu ułatwiających pracę. Uwierzcie – o wiele efektywniej pracuje się, gdy wiemy coś więcej na temat danej klasy czy pakietu niż gdybyśmy mieli się tego domyślać tylko z jej nazwy.W przypadku programowania urządzeń mobilnych nie będziemy poznawać wszystkich „wnętrzności” Javy, choć – osobiście namawiam siebie i Was do tego jak najbardziej :) . Jak dobrze wszyscy wiemy, w zależności od wymagań i potrzeb możemy wykorzystywać odpowiednie podzbiory tego ogromnego środowiska, które samo w sobie zostało podzielone na trzy główne gałęzie:a) Java ME – Java Micro Edition, czyli wszystko, co wiąże się z programowaniem urządzeń mobilnych, główny punkt naszych zainteresowań,b) Java SE – Java Standard Edition, główny „trzon” Javy, wiele jego elementów wykorzystamy również przy pracy z telefonami, jednak zapewnia on o wiele szersze usługi, jak: obsługa wielowątkowości, implementacja kolekcji, wsparcie dla graficznego interfejsu użytkownika, obsługa strumieni (plików, internetu, …) i wiele, wiele, wiele więcej. Niejednokrotnie będę się również odwoływał do tej części bibliotek Javy,c) Java EE – Java Enterprise Edition, część biznesowa Javy, a więc to, co przydaje się przy tworzeniu dużych aplikacji dla przedsiębiorstw, tam gdzie wymagana jest skalowalność i implementacja komunikacji na najwyższym poziomie – na razie nie dotykam tej warstwy Javy, ale gdy ten kurs się skończy, kto wie… :)

 

Nasz wybór padł więc naturalnie na Javę w wersji ME – możecie ją ściągnąć z (link).

 

  • IDE, czyli I(ntegrated) D(evelopment) E(nvironment) – potocznie rozumiany jako „program do pisania programów”. Jak wspomniałem na początku – nic Was nie powinno powstrzymywać przed programowaniem w Notatniku, jednak dla początkujących polecam na start (i w sumie przez całą swoją karierę) korzystanie z takiego środowiska, i to z dwóch powodów:a) programuje się po prostu szybciej, wydajniej – obecne środowiska są bardzo przyjazne dla użytkownika, starają się mu pomóc w jak największym stopniu, a dodatkowo – oferują nieocenioną pomoc przy dalszym zarządzaniu aplikacją (debugowanie, deployment),b) korzystanie z IDE jest standardem praktycznie w każdym zakładzie pracy, firmie – więc tylko na Waszą korzyść wpłynie znajomość standardów powszechnie używanych.

 

Nie chcę wszczynać jakiejkolwiek wojny pomiędzy zwolennikami „jednego słusznego środowiska” a przeciwnikami innego – to Wam pozostawiam wybór, to Wy z czasem „poczujecie”, gdzie Wam się pracuję po prostu lepiej – i tak będzie chyba najrozsądniej. Osobiście mogę polecić dwa uznane, sprawdzone – i co najważniejsze – DARMOWE :) środowiska programistyczne:

Jak już mówiłem – dzięki polityce propagowania Javy, a ku naszej uciesze – wszystko co z nią związane jest dostępne publicznie, dla jak najszerszej grupy odbiorców.

 

Skoro dotarliście do tego miejsca, to znaczy, że magiczny świat programowania jeszcze Was dostatecznie nie przeraził (z czego się cieszę) i macie ochotę brnąć dalej.

Mając więc skompletowane narzędzia instalujemy je w wyżej podanej kolejności na komputerze. Ponieważ sam osobiście do pisania aplikacji pod Java ME używam NetBeans’a (o tym jak skonfigurować Eclipse’a pokaże w kolejnych lekcjach), środowisko to, nie potrzebuje żadnego konfigurowania aby móc zacząć pracę. Pamiętajcie tylko, by podczas instalacji zaznaczyć odpowiednią platformę do instalacji:

 

Gdy instalacja się zakończy, mamy w zasadzie wszystko przygotowane, by móc rozpocząć pisanie naszej pierwszej aplikacji :) Ponieważ szkielet tworzenia wszystkich kolejnych aplikacji będzie przebiegał podobnie, przedstawię go tutaj „obrazkowo”:

1. Zaczynamy od utworzenia projektu.

  • Uruchamiamy NetBeans’a, z menu File wybieramy New Project…

 

 

  • W powstałym oknie, w grupie Categories zaznaczamy Java ME, a w drugim oknie Projects wybieramy Mobile Application, klikamy na Next:

 

  • wybieramy nazwę projektu (np.: „Projekt1”), wskazujemy lokację, czyli miejsce na dysku twardym naszego komputera, gdzie ma być on umieszczony, oraz upewniamy się, że mamy ZAZNACZONE obie opcje: „Set as Main Project” oraz „Create Hello MIDlet”. Ten krok tylko teraz tak wygląda, pamiętajcie, żeby w każdej kolejnej lekcji powtarzać cały ten proces tak samo jak teraz, z małym wyjątkiem – gdy będziecie dochodzili do tego kroku, zawsze ODZNACZAJCIE punkt: „Create Hello MIDlet”, gdyż NetBeans wygeneruje dla Was szablonowy kod, który niekoniecznie będzie nam potrzebny. Klikamy na Next.

 

  • okienko, które teraz się pojawiło, pozwala na wybór platformy emulatora naszego telefonu (zwykle jest ona wbudowana w SDK dostarczane przez Javę, nie radzę zmieniać), wybór samego telefonu (o czym za chwilę) oraz ustawienia dotyczące tzw. konfiguracji i profili. Emulator urządzenia mobilnego jaki znajduje się w Waszym SDK może symulować różne możliwości konkretnych telefonów, jak np. wielkość i rozdzielczość wyświetlacza, obecność i rodzaj klawiatury, obsługa protokołów komunikacyjnych jak IrDA, GPS, BlueTooth i inne. Co więcej – niektórzy producenci telefonów dostarczają swoje własne emulatory, dzięki czemu możemy „prawie” dokładnie poczuć jak nasza aplikacja w rzeczywistości mogłaby się zachować na konkretnym modelu. Ja jednak radzę Wam zostać przy tych dostarczonych wraz z SDK gdyż działają porządnie a także umożliwiają dość rozbudowaną konfigurację (o dostosowywaniu emulatora do naszych potrzeb, jeśli będzie taka konieczność, napiszę w którejś z przyszłych lekcji). Konkretny wygląd modelu do emulowania możecie również zmienić podczas pracy nad aplikacją, więc w chwili obecnej będzie to wybór raczej czysto estetyczny – ja wybieram: DefaultCldcJtwiPhone.
    Czas na konfiguracje i profile. Obiecuję, że rozpiszę o tym szerzej w jednej z przyszłych lekcji, jednak na chwilę obecną zapamiętajcie, iż te dwie opcje służą do ustawienia, kolokwialnie mówiąc – jak bardzo zaawansowany jest Wasz telefon. Konfiguracje określają podstawowe wymagania co do technikaliów urządzenia, a więc – pamięci, mocy obliczeniowej, zużycia energii, łączności. Te, używane w Java ME to tzw. CLDC (Connected Limited Device Configuration). CLDC zakłada że urządzenie przez nie obsługiwane: 

  • ma od 160kB do 513kB pamięci na całe środowisko uruchomieniowe Javy,
  • posiada 16 lub 32-bitowy procesor,
  • ma niskie zużycie energii,
  • posiada zdolność do podłączenia do internetu.

Oprócz tego, konfiguracja czyni niedostępną znaczą część możliwości Javy dostępną w wersji SE co jest zrozumiałe biorąc pod uwagę skalę urządzenia. W trakcie trwania kursu, będę omawiał również wszystkie te elementy, bez których musimy się w jakiś sposób obejść.

Profile definiują natomiast kontrakt pomiędzy urządzeniem a Twoją aplikacją, a więc zapewniają zestaw odpowiednich API, które będziesz mógł wykorzystywać przy tworzeniu aplikacji.

Na chwilę obecną – pozostawmy te ustawienia, które sugeruje nam NetBeans (CLDC 1-1, oraz MIDP-2.0), jednak jeśli się okażę, że Wasza aplikacja nie chce działać na konkretnym urządzaniu, może się okazać, iż jest to urządzenie starszej daty i nie spełnia wymogów określonych przez daną konfigurację bądź profil (o tym jakie konfiguracje i profile obsługuje dane urządzenie możecie zapytać Internet :) ). Klikamy wobec tego na Next.

 

  • w ostatnim oknie klikamy po prostu na Finish. Gratuluję!!! Twój pierwszy projekt został utworzony, czas przyjrzeć się mu dokładnie.

 

Możecie od razu zauważyć, że w okienku Projects pojawiły się nowe katalogi, pliki. Nas jednak będzie (jak na razie) interesował jedynie katalog Source Packages – to tutaj znajdują się wszystkie paczki i pliki źródłowe projektu. Kliknijcie dwa razy na ten napis, rozwinie się gałąź. Znajdziecie w niej paczkę o nazwie hello a w niej plik o nazwie HelloMIDlet.java – gdy go otworzycie Waszym oczom może się ukazać widok podobny do tego:

Jeśli chodzi o programowanie pod JavaME to NetBeans znacząco prześciga tutaj Eclipse’a między innymi dzięki wielu „ulepszaczom”, które czynią pracę z tą platformą o wiele ciekawszą. Za chwilę zajmiemy się niektórymi z nich. Żeby rozbudzić Wasze emocje, podpowiem, iż NetBeans posiada nawet wbudowany mini edytor do tworzenia gier! Ale spokojnie, spokojnie – czeka nas świetlana przyszłość :)

Na razie zajmijmy się tym, co widzimy na ekranie. Centralną jego część wypełnia edytor kodu źródłowego/narzędzie do budowania interfejsu użytkownika/kontroler przepływu informacji. Po kolei:

  • kliknięcie w przycisk Source przenosi nas w bezpośredni tryb edycji kodu źródłowego – to właśnie tam spędzimy najwięcej czasu, ale i tam mamy największe możliwości,
  • przycisk Screen służy do wizualnego budowania interfejsu użytkownika (po ludzku – możecie sobie zwyczajnie „wyklikać” to, jak ma wyglądać ekran aplikacji),
  • ostatni przycisk, Flow pozwala natomiast w sposób wizualny prześledzić, jak będzie pracowała nasza aplikacja, a dokładniej – jak będzie wyglądało w niej przechodzenie pomiędzy ekranami.

 

Zastanawiacie się pewnie dlaczego użyłem słowa „ekranami”, skoro Wasz ukochany telefon posiada tylko jeden i to w dodatku malutki :) kawałek szkiełka na którym możecie coś zobaczyć. Otóż programowanie w Javie ME opiera się na koncepcji tzw. „ekranów”. Każdy ekran to takie coś, jak kartka papieru w Waszym notatniku – na kartce możecie dowolnie rysować, umieszczać różne elementy graficzne. Trzymacie się jednak zwykle pewnego porządku – o ile nie jesteście tak roztargnięci jak czasem mi się zdarza być – wszystkie one zachowują pewną spójność. Kiedy tylko macie kolejną myśl, ideę – umieszczacie ją na nowym arkuszu by można było ją później łatwiej odnaleźć. Tak samo jest w Javie ME – tworzycie np. ekran startowy, na którym wyświetlacie logo waszej firmy, użytkownik naciska przycisk, lub po odpowiednim czasie – to okno się przełącza na inne, na którym dajecie mu np. do wyboru kilka opcji: Nowy plan, Zapisane spotkania, Kalendarz, itp. . Użytkownik wybiera jedną z nich, ten ekran się „chowa”, pojawia się inny, zgodny z wyborem… Czujecie już o co chodzi? :) W praktyce takie programowanie okazuje się bardzo przyjemne, bo nie mamy bałaganu, wszystko jest grzecznie poukładane, oddzielone.

 

Mało tego. Twórcy Java ME byli jeszcze bardziej zapobiegliwi i dali nam tak naprawdę DWA podejścia do tworzenia aplikacji. Tak naprawdę – chodzi tutaj bardziej o sposób przedstawiania informacji użytkownikowi niż metodologię programowania. Otóż JavaME posługuję się dwoma trybami renderowania (czyli inaczej – wyświetlania) grafiki. Wchodzą tu w grę takie pojęcia jak „niski poziom” (low level) i „wysoki poziom” (high level).

 

  • przy wykorzystaniu możliwości niskiego poziomu mamy praktycznie nieograniczone możliwości jeśli chodzi o wygląd naszej aplikacji. Tworzenie jej jednak jest wtedy znacznie bardziej żmudne, gdyż operujemy praktycznie na samym fizycznym urządzeniu, a więc wykorzystujemy takie prymitywy graficzne jak: punkty, linie, prostokąty, okręgi, rysownie obrazków, tekstu. Uwaga – tego trybu będziemy używali WYŁĄCZNIE do tworzenia gier; mimo tego – nikt nie broni tworzenia interfejsu użytkownika w tym trybie i z pewnością wyglądałby on cudownie – jednak jest to naprawdę syzyfowa praca.
  • „wysoki poziom” nie daje natomiast tak szerokich możliwości, za to – bardzo przyjemnie, prosto – i co najważniejsze – szybko, tworzy się w niczym GUI – czyli graficzny interfejs użytkownika. W trybie tym mamy dostęp do takich elementów jak: pola tekstowe, przyciski wyboru, listy, paski postępu i inne elementy często spotykane w aplikacjach mobilnych które ułatwiają pracę z nimi.

 

Postanowiłem że w kursie tym omówię zarówno jeden jak i drugi tryb, mimo iż kurs w zamierzeniu miał pozwolić Wam rozpocząć tworzyć aplikacje multimedialne (taka ładna nazwa dla gier :) ) – a jak wiadomo – przecież nie samymi grami żyje człowiek…prawda?

Skoro już wiemy czym są ekrany, przyjrzyjmy się jak może wyglądać taki najprostszy z nich. Przełączcie się na widok Screen (jeśli zginął Wam edytor kodu źródłowego, możecie go ponownie otworzyć, klikając dwukrotnie na plik HelloMidlet.java bądź wybierając View Editors Screen. Waszym oczom ukaże się taki oto widok:

Device Screen to ekran naszej aplikacji. Widzimy na nim ułożone (na razie przez NetBeans’a – już niedługo przez nas :) ) elementy tworzące interfejs użytkownika. Obok ekranu znajdują się Assigned Resources czyli zasoby przypisane od naszego ekranu (o nich później). Zupełnie na prawo, w okienku Palette widzimy natomiast kontrolki, czyli elementy tworzące interfejs aplikacji. Jak mówiłem wcześniej – ten widok kodu źródłowego pozwala nam tworzyć aplikację poprzez klikanie, a dokładniej za pomocą metody „przeciągnij i upuść”.

Spróbujcie nawet teraz. Najpierw usuniemy element typu StringItem który już znajduję się na naszym ekranie. Aby to uczynić, w lewym dolnym rogu NetBeans’a macie okienko Navigator – znajdują się w nim wszystkie elementy tworzące dany ekran poukładane w hierarchii drzewa. Wystarczy że odszukacie element o nazwie stringItem, klikniecie na niego prawym przyciskiem myszy i wybierzecie Delete. Element zniknął z ekranu :) Teraz, z panelu Palette z prawej strony wybieramy StringItem (znajduje się on w kategorii Items). Klikamy na niego i przeciągamy na ekran naszego urządzenia. Powinniście otrzymać taki rezultat:

 

Teraz, możemy ustawić właściwości naszej kontrolki. Zmienia się je w okienku Properties, które znajduje się w prawym dolnym rogu NetBeans’a. Odszukajcie tam element o nazwie Label. Obok niego znajduje się wartość tej właściwości, która w naszym przypadku równa się napisowi stringItem. Możecie ją zmienić na coś bardziej opisowego, w stylu: JavaME – pierwszy projekt. Trochę niżej macie inną właściwość, o nazwie Text – tę również możecie zmienić z <null> na np.: Programowanie w JavaME jest bardzo proste!!! :D . Jak widzicie Wasze zmiany są natychmiast uaktualniane w głównym oknie aplikacji – i jeśli wszystko poszło we właściwym porządku a Wasz komputer nie choruje na ospę wietrzną – to ujrzycie taki rezultat jak u mnie:

 

Brawo!!! Możecie z ciekawości spojrzeć na dwa inne ekrany podglądu kodu źródłowego: Source oraz Flow, jednak zauważycie że w tym drugim nic tak naprawdę się nie zmieniło! I dobrze – nie zmieniliśmy przecież schematu DZIAŁANIA aplikacji, tylko jej WYGLĄD. I tak właśnie będzie wyglądało tworzenie programów na urządzenia mobilne: część czasu przeznaczamy na zbudowanie wyglądu aplikacji, drugą część natomiast – na oprogramowanie interakcji z użytkownikiem. Czyż nie jest to cudowne? :)

Gdy mamy tak przygotowaną aplikację możemy wreszcie ją sprawdzić w działaniu (nie mogliście się doczekać, wiem :) ). Jest to w zasadzie bardzo proste. Na górze NetBeans’a macie przyciski odpowiedzialne za budowanie (ikonki z młotkiem), uruchomienie (zielona strzałka) i debugowanie projektu (strzałka z kawałkiem kodu źródłowego). Polecam uruchamianie aplikacji w trybie debugowania, gdyż mamy wtedy możliwość pracy krokowej, zakładania pułapek – ogółem – testowania aplikacji gdy działa tak jak nie potrzeba. W przyszłości powiem więcej na temat różnych opcji uruchamiania emulatora oraz tzw. deployingu aplikacji (czyli uruchamiania ich na realnych telefonach). Gdy wykonaliście wszystkie kroki powyższego kursu zgodnie z ich intencją, po naciśnięciu przycisku zielonej strzałki, Waszym oczom powinien się ukazać niniejszy widok:

 

 

(w emulatorze, zaraz po uruchomieniu, musicie nacisnąć przycisk znajdujący się pod napisem Launch – emulator dosłownie e-mu-lu-je nasze urządzenie, tak, jak gdybyśmy faktycznie uruchamiali na nim naszą aplikację :) ).

 

Myślę, że zdążyliście już przysnąć kilkukrotnie, dlatego powoli zbliżamy się ku końcowi tej części kursu. Jestem świadom tego że wiele rzeczy pominąłem, że być może w niektórych krokach było zbyt powierzchownie, ale takie są początki – jest dużo nowej wiedzy, a tutaj sprawdza się od wieków metoda „małych kroczków” – i taką też będę stosował.

W dzisiejszym kursie nauczyliście się

  • jak rozpocząć przygodę z JavaME,
  • podstawowe pojęcia dotyczące programowania urządzeń mobilnych,
  • konfiguracja środowiska NetBeans do pracy z JavaME,
  • tworzenie przykładowego projektu,
  • budowa IDE NetBeans’a i jego elementy istotne przy tworzeniu aplikacji na urządzenia mobilne,
  • pierwsza wprawka w budowaniu GUI na telefony,
  • uruchamianie i testowanie aplikacji.

 

W następnej części opowiem czym są midlety, rozpoczniemy edytować kod źródłowy naszych aplikacji, a także wprowadzę pierwsze kontrolki wysokiego poziomu :)

Dziękuję wszystkim za uwagę, proszę o wybaczenie jakichkolwiek nieścisłości, niedopowiedzeń, itp. Wszelkie komentarze będą jak najbardziej mile widziane i z chęcią na nie odpowiem.

Pozdrawiam i do usłyszenia ;D

(link do plików z projektem)

paź
18

Kolejny rok, kolejne zmarszczki :)

Dodano [Październik 18, 2011]

Eee, wcale nie :)

Witam Was wszystkich serdecznie, ponownie na moim blogu (zagląda tu ktoś jeszcze? :) ). Miałem ogromną przerwę, nawet nie próbuję się usprawiedliwiać, ale głównie dlatego że w moim życiu zaszły ciekawe zmiany i byłem skupiony na czymś innym (po prostu). Teraz rozpoczynam kolejny rok studiów co wiążę się z napływem świeżej, niczym nie zmąconej ochoty do robienia wszystkiego co tylko dusza zapragnie – w tym – dzielenia się swoim wnętrzem ze światem.

 

Jako że wszystko powoli się ustatkowywuje (nie wiem czy istnieje takie słowo, ale co tam) – wracam do regularności w zamieszczaniu swoich przemyśleń na tej stronie – mam nadzieję że będzie ciekawie, może czegoś nowego się dowiecie, może inaczej spojrzycie na niektóre sprawy. Mam też małą niespodziankę dla wszystkich, którzy trafili tu (najpewniej przez przypadek :) ) wpisując w swojej ukochanej wyszukiwarce cokolwiek związanego z słowem „programowanie” – ale to musicie śledzić kolejne wpisy.

 

 

Pozdrawiam Was wszystkich, gorąco ściskam i życzę uśmiechu i sił na zmagania z życiem :D

 

lip
07

W natłoku spraw…

Dodano [Lipiec 7, 2011]

…zgubiłem w zasadzie rachubę czasu :) Dzieje/działo się tak dużo ostatnio/wcześniej/jeszcze wcześniej u mnie że nie będę odgrzebywał starych kotletów a za to postaram się o częstsze wpisy.

 

 

Żyj pełnią życia; inaczej popełniasz błąd.
Nie jest szczególnie ważne, czym się zajmujesz,
jeśli tylko masz życie w swoich rękach.
Bo jeżeli nie miałeś życia, to co miałeś?
– Co się raz straci, już jest stracone, nie zapominaj o tym.
Właściwa chwila to jest każda chwila, którą człowiek będzie miał szczęście przeżyć…
a więc żyj!

 

 

 

P.S: Spełniło się jedno, a w zasadzie dwa z moich maleńkich marzeń – „pracuję”, a w zasadzie praktykuję jako programista oraz mieszkam sam :) Co jeszcze dobrego los przyniesie…

cze
06

Święto bardzo przyjemne…zupełnie nieprzyziemne :)

Dodano [Czerwiec 6, 2011]

Wiecie jaki dzień się dziś kończy? Czy jest wśród Was ktoś, kto dzisiejszego dnia świętował bez opamiętania? Otóż, formalnie bądź nie, obchodziliśmy dziś Światowy Dzień…Całowania :) Czyż może być coś piękniejszego?

 

 

 

Dwie najpiękniejsze rzeczy do jakich mogą posłużyć nasze usta, to według mnie w ogóle – uśmiech i pocałunek – kolejność do tej pory nieustalona. Aha – gdyby tego było mało, pamiętajcie, że podczas całowania spala się średnio 100 kalorii (jeśli całus trwa około minuty) – więc zawsze to jakiś argument, gdyby partner/ka miał/a obiekcje – o linię trzeba przecież dbać ;)

 

 

 

A czy Ty pamiętał(e/a)ś aby obdarzyć tym szczególnym gestem osobę na której Ci zależy?

stat4u