Prezentace se nahrává, počkejte prosím

Prezentace se nahrává, počkejte prosím

Tvorba aplikací pro mobilní zařízení

Podobné prezentace


Prezentace na téma: "Tvorba aplikací pro mobilní zařízení"— Transkript prezentace:

1 Tvorba aplikací pro mobilní zařízení
Rudolf Pecinovský Amaio Technologies

2 Rozvrh dne Úvod 9:00 – 9:30 Mobilní zařízení a jejich vlastnosti
9:00 – 9:30 Mobilní zařízení a jejich vlastnosti 9:30 – 9:45 Java 2 Micro Edition, konfigurace, profily 9:45 – 10:30 Přestávka 10:30 – 10:45 MIDP, vývojová prostředí, první MIDlet 10:45 – 11:30 Low-level GUI 11:30 – 12:15 Oběd 12:30 – 13:30 Ukázka aplikací 13:30 – 14:00 High-level GUI 14:00 – 14:45 Uchování informací mezi spuštěními 14:45 – 15:30 15:30 – 15:45 Komunikace po síti 15:45 – 16:30 Závěr 16:30 – 17:00

3 Co od účastníků semináře očekáváme
Znalosti základů programování v jazyce Java Chuť dozvědět se něco nového Co se dnes naučíte Možnosti mobilních zařízení, zejména telefonů Základní charakteristiky Java ME Navrhovat aplikace pro Java ME

4 Co nás čeká Svět mobilních zařízení, Java ME, CLDC, MIDP
Mobilní zařízení a jejich vlastnosti Java Micro Edition – Java ME Konfigurace Profily Tvorba aplikací pro MIDP MIDlety a jejich suity Nízkoúrovňové uživatelské rozhraní Práce s grafikou Formulářové uživatelské rozhraní Vnitřní databáze Spolupráce po síti

5 Mobilní zařízení a jejich vlastnosti

6 Mobilní aplikace v současném světě
Počítače se prosazují v nových oblastech – mimo jiné v mobilních zařízeních Mobilních uživatelů internetu začíná být více než těcht „pevných“ Firmy chtějí umožnit pracovníkům připojení odkudkoliv Klasický počítač – nevhodný Notebook – pro řadu uživatelů stále ještě těžkopádný PDA – vhodný, ale často zbytečně drahý Mobilní telefon – horký kandidát

7 Mobilní telefon – výhodné vlastnosti
Většina lidí jej má u sebe Moderní telefony jsou programovatelné (lze pro ně vyvíjet programy a ty pak do nich nahrát) Obsahují jednoduchý operační systém Umí spouštět připravené aplikace Aplikaci můžete v případě potřeby nejprve nahrát „po telefonu“ Jsou z principu připojitelné do sítě Mohou sloužit jako „tenký klient“

8 Mobilní telefon – nevýhody
Menší operační paměť Bateriové napájení => Pomalejší procesor Malá obrazovka Těžkopádná klávesnice Většinou absence ukazovacího zařízení (myši) Relativně pomalé připojení k síti Absence velké paměti typu HD Výrobci se předhánějí ve vylepšeních Javy, takže vznikají problémy s kompatibilitou

9 Další programovatelná zařízení v síti
PDA (Personal Digital Assistant) Osobní databanky (Personal Organizers) Oboucestné pagery (two-way pagers) Automobilové počítače GPS systémy (Global Position System) Přídavná zařízení (set-top box) Internetové televize Čtečky čárových kódů Zařízení zabudovaná ve spotřební elektronice

10 Společné vlastnosti Velká variabilita Malá operační paměť
Absence velkokapacitní paměti Většinou méně výkonný procesor Nestandardní ovládání, svérázný UI Připojení k síti … ale většinou pomalé Většinou omezené na firmware výrobce Označována jako Pervasive devices (všudypřítomná zařízení)

11 Shrnutí Mobilní zařízení – výhodná platforma pro umístění řady důležitých aplikací Malý výkon, malá paměť Obrovská rozmanitost všech charakteristik Častá schopnost připojení do sítě

12 Java Micro Edition Java ME™
První seznámení

13 Historie Červen 1999 – JavaOneSM Developer Conference Ohlášeny 3 platformy J2ME – Java 2 Micro Edition J2SE – Java 2 Standard Edition J2EE – Java 2 Enterprise Edition Vyvíjena pod JCP – Java Community ProcessSM Červen 2000 – 500 firem se přihlásilo k podpoře Červen 2001 – Prodáno >3 mil. zařízení s J2ME Léto 2002 – objevilo se okolo 50 modelů mobilních telefonů podporujících J2ME

14 Současnost a budoucnost
V průběhu 5 let by měla být využívána asi 1 miliarda telefonů podporujících J2ME Počáteční boom zabily výrobci telefonů, protože každý implementoval specifikaci trochu jinak, takže vznikaly problémy s kompatibilitou Java ME je stále jedinou platformou dostupnou prakticky na všech mobilních zařízeních včetně těch nejlevnějších Android a Apple, Symbian i Windows mají jeno omezenou použitelnost

15 Platforma Programovou platformu definují tři komponenty
Možnosti programovacího jazyka Použitý virtuální stroj Použité knihovny Aplikace komunikuje se systémem prostřednictvím knihovny Celý program interpretuje virtuální stroj Použitelnost platformy je závislá na dostupném HW Aplikace Knihovna P L A T F O R M Java Virtuální stroj Operační systém Hardware

16 Java ME – základní cíle Umožnit použití programovacího jazyka Java
Použití v zařízeních s malou pamětí a pomalejším procesorem Respektovat velkou variabilitu zařízení Umožnit vývoj programů provozovatelných na všech zařízeních nezávisle na odlišnostech jejich hardwaru Umožnit připojení těchto zařízení k síti (wireless Java)

17 Konfigurace Java ME = Sada nástrojů, specifikací a technologií pro vývoj aplikací pro malá zařízení Značná variabilita zařízení si vynutila definici dvou konfigurací (podplatforem) CDC – Connected Device Configuration CLDC – Connected Limited Device Configuration Konfigurace specifikují minimální HW požadavky umožňující provoz příslušné (pod)platformy Všechny požadavky jsou povinné, neexistují volitelné možnosti (options)

18 Paměť a její rozlišení Požadavky na paměť patří mezi základní
Vzhledem k charakteru zařízení se rozlišují dva druhy pamětí: Pevná (non-volatile) – nemaže se po skončení programu (ROM, EEPROM, …) Proměnná (volatile) (většinou RAM)

19 Java Card Je o něco starší, narodila se v roce 1997
Je určena pro čipové karty – nejmenší zařízení programovatelná v jazyku Java Typicky 32 – 64 KB EEPROM, 4 – 8 KB RAM, Používá se např. v kartách VISA

20 CLDC – Connected Limited Device Conf.
Požadavky verze 1.1: Minimálně 192, z toho: Min 160 KB pevné pro základní knihovnu a VM Min 32 KB proměnné pro běh programu a objekty 16bitový nebo 32bitový procesor Připojení do sítě Nízká spotřeba – často bateriový provoz Typičtí představitelé: Mobilní telefony a pagery Video a audio systémy Navigační systémy Mobilní čtečky čárových kódů

21 CDC – Connected Device Configuration
Požadavky: 32bitový procesor Min. 512 KB paměti pro vlastní Javu Min. 256 KB paměti pro alokaci paměti za běhu Plná funkcionalita virtuálního stroje Připojení k síti (často rychlé a trvalé) Oproti CLDC již podporuje náročnější funkce Serializace Reflexe Weak refernce JNI (Java Native Interface)

22 J2SE × J2ME J2SE CDC CLDC

23 CVM – Compact Virtual Machine
Určen pro konfiguraci CDC Plná podpora Java 2 verze 1.3 Specifika Přenositelný Optimalizovaný na využití ROM Upravený správce paměti (Garbage Collector) Minimalizuje průměrný čas zdržení (real-time) Optimalizovaný na menší paměť Malá režie se správou tříd Zpočátku neimplementoval hot-spot ani JIT compiler Poskytuje rozhraní a podporu pro RTOS (Real Time Operating System)

24 KVM – Kilobyte Virtual Machine
Navržen pro méně výkonné procesory 16bitové nebo 32bitové Od 25 MHz Malé požadavky na paměť (50 – 80 KB) Vysoce přenositelný, modulární a přizpůsobitelný Maximálně rychlý a kompletní Napsaný v jazyku C ( řádek kódu) => snadno přenositelný na jakoukoliv platformu, pro níž existuje překladač jazyka C (prakticky všechny)

25 KVM – Verifikace Standardní přístup: zkontrolovat korektnost třídy při jejím zavedení (class loader) Časově a paměťově náročné (samotná verifikace spotřebuje 25 – 110 KB) CLDC nechává většinu práce vykonat při překladu Využívá omezený přístup k zařízení Využívá absenci některých konstrukcí (reflexe, rmi) Po překladu se nejprve provede preverifikace – při ní se do souboru .class doplní informace usnadňující verifikaci za běhu programu KVM pak provede jen nejnutnější verifikaci navíc usnadněnou dodatečnými informacemi

26 KVM – Omezení KVM neimplementuje následující rysy:
Datové typy double a float (v příští verzi budou) Finalizace (Třída Object neobsahuje metodu finalize) Většinu výjimek typu Error (ponechává pouze 3) JNI (Java Native Interface – tj. neumožňuje zavádět za běhu programy napsané v nativním kódu) Reflexi, serializaci a RMI (Remote Method Invocation) Skupiny vláken (thread groups) a démony Slabé odkazy (weak references) Uživatelsky definované zavaděče tříd (class loaders)

27 Profily Doplňují konfigurace
Umožňují horizontální oslovení trhu (různé možnosti stejného zařízení) Přidávají další třídy – jimi je profil definován Cíl: zpřístupnit nadstavbové funkce Specifické pro daný typ zařízení Oslovující speciální trh Profil může být nadstavbou nad jiným profilem Je možné implementovat několik profilů zároveň

28 Profily pro CDC Foundation Profile – základ ostatních profilů
Zahrnuje většinu tříd jádra Java 2 verze 1.3 RMI Profile Přidává knihovnu J2SE RMI Personal Basis Profile – specifikace se dotahuje Přidává základní GUI V jednom okamžiku lze mít otevřené jediné okno Personal Profile – specifikace se dotahuje Umožňuje současné zobrazení několika oken Game Profile – specifikace ještě nejasná Neví se ani, zda bude založen na Foundation Profile

29 Profily pro CLDC Mobile Information Device Profile (MIDP)
Nejznámější profil J2ME Primárně je zaměřen na mobilní telefony Přidává jednoduché UI respektující jejich omezení Přidává práci v síti založenou na HTTP 1.1 Přidává schopnost pracovat s lokální trvalou pamětí (lokální databáze pro uchování dat mezi zapnutími) PDA Profile (PDAP) Oproti MIDP počítá s větší obrazovka a větší pamětí Nabízí propracovanější UI Umožní lépe využívat možnosti operačního systému Hlavní profil pro menší (=méně výkonné) kapesní počítače

30 Historie MIDP Původní verze 1.0 byla velmi omezená
Pracovala pouze s celými čísly Pracovala s velmi omezenou obrazovkou a ovládáním Verze 2.0 vyžaduje CLDC 1.1 Přidávala čísla v plovoucí čárce Přidávala řadu grafických možností pro hry Přidala možnost využití multimédií Verze 3.0 Zaměřená spíše na praktické aplikace Umožňuje sdílení knihoven mezi jednotlivými programy Aplikace mohou běžet souběžně a vzájemně spolu komunikovat

31 Přehled platforem Javy

32 Konfigurace a profily J2ME
Toto nás nyní zajímá Personal Profile MIDP Mobile Information Device Profile PDAP Personal Digital Assistant Profile Personal Basis Profile RMI Profile Game Profile Foundation Profile ? CLDC Library Connected Limited Device Configuration CDC Library Connected Device Configuration KVM Kilobyte Virtual Machine CVM Compact Virtual Machine

33 Shrnutí Platformu definuje J2ME má dvě podplatformy: CDC a CLDC
Jazyk Virtuální stroj Knihovna J2ME má dvě podplatformy: CDC a CLDC Každá má svůj virtuální stroj: CVM a KVM Pro každou je definována řada profilů Nejpropracovanější a v současné době nejpoužívanější je MIDP pro platformu CLDC

34 Java ME – MIDP Mobile Information Devices Profile

35 Základní požadavky na HW a OS 1/2
Obrazovka minimálně 96×54 bodů, stačí 1 bit Klávesnice (jednoruční či dvouruční) či touch screen Paměť: 160 KB pevné pro MIDP komponenty 32 KB proměnné pro Java runtime 8 KB pevné pro trvale uchovávaná data Obousměrné připojení k síti

36 Základní požadavky na HW a OS 2/2
Další požadavky na operační systém: Umožnit plánování procesů Umožnit ošetření výjimek Umožnit zpracovat přerušení Schopnost provozovat JVM (přesněji KVM) Umožnit na displeji bitmapovou grafiku

37 CLDC zahrnuje: java.lang java.util java.io javax.microedition.io
Chybí podpora reflexe a plovoucí čárky java.util Třídy Calendar, Date, Enumeration, HashTable, Random, Stack, Vector a potřebné výjimky java.io Základní proudové vstupně výstupní operace bez souborů, vyrovnávacích pamětí (buffer) a práce s objekty. javax.microedition.io Třídy a rozhraní z Generic Connection Framework, jenž poskytuje jednodušší a jednotnější prostředí pro komunikaci s externími zařízeními.

38 Aplikace nad profilem MIDP
Jednotlivé aplikace jsou označovány jako MIDlety Přeložené třídy lze sbalit (package) do souboru JAR doprovázeného textovým souborem JAD (Java Application Descriptor) Jedna dvojice JAR&JAD může obsahovat několik midletů – skupina bývá označována jako suita Aplikace z jedné suity spolu mohou sdílet některé prostředky a vyměňovat si data

39 MIDP řeší: Správu životního cyklu aplikace
Balíček javax.microedition.midlet Umí aplikaci spustit, pozastavit, oživit a ukončit Uživatelské rozhraní a události Balíček javax.microedition.lcdui Obsahuje třídy a rozhraní pro komponenty GUI rozhraní Ukládání dat v zařízení Balíček javax.microedition.rms Správa záznamově orientované databáze Připojení k síti Doplňuje javax.microedition.io o HTTP protokol

40 Použité balíčky //Společný balík všech dnešních programů
package workshop; //Užitečné pomocné třídy z J2SE (zestručněné) import java.util.*; //Vstup a výstup prostřednictvím datových proudů import java.io.*; //MIDP aplikace a její interakce s prostředím import javax.microedition.midlet.*; //API pro tvorbu UI v MIDP aplikacích import javax.microedition.lcdui.*; //Record Management Systém – trvalé uložení dat //mezi jednotlivými spuštěními aplikace import javax.microedition.rms.*; //Rozšíření podpory sítí pro MIDP import javax.microedition.io.*;

41 Vývojová prostředí Java Platform Micro Edition Software Development Kit 3.0 NetBeans + Mobility Pack

42 Různé emulátory /2 Všechny mají spuštěn tentýž program

43 Různé emulátory /2 Textový program vyměněn za grafický

44 Sun ONE Studio 4 ME (ukázka) 3/3

45 MIDlet

46 Životní cyklus aplikace – MIDletu
Start Aplikace v profilu MIDP – MIDlet Po vytvoření svého objektu MIDlet čeká, až jej systém aktivuje Aktivní může být pouze jeden MIDlet Aktivní MIDlet může skončit nebo se opět vrátit do čekajícího stavu Ukončit je možno i čekající MIDlet Změnu stavu může MIDlet vyvolat sám Může ji vyvolat i jiný program zavoláním příslušné metody Čekající Aktivní Ukončený

47 Konstrukce MIDletu Potomek javax.microedition.midlet.MIDlet
Třída MIDlet definuje metody, jejichž voláním je MIDlet upozorněn, že je převáděn do jiného stavu Metody slouží hlavně k alokaci a opětnému uvolnění systémových prostředků Metody jsou abstraktní => je nutno překrýt startApp() ® byl převeden do stavu aktivní pauseApp() ® bude převeden do stavu čekající destroyApp(boolean u) ® bude přev. do st. ukončený Je-li v destroyApp parametr u==false, může si MIDlet vybrat, zda bude opravdu končit

48 Přechody mezi stavy Start Program je řízený událostmi => z metod se musí program rychle vrátit, aby systém mohl opět převzít řízení Do příslušného stavu se program dostane až po opuštění metody Voláním uvedených metod umožní systém MIDletu optimálně alokovat a uvolňovat prostředky konstruktor startApp Čekající startApp pauseApp Aktivní destroyApp destroyApp destroyApp Ukončený

49 Přechodové metody 1/3 protected abstract void startApp() throws MIDletStateChangeException Alokuje prostředky pro aplikaci. Často přitom rozlišuje mezi prvním a následujícím spuštěním (tj. spuštěním po odchodu mezi čekající) Není-li v danou chvíli MIDlet schopen spuštění, vyvolá výjimku

50 Přechodové metody 2/3 protected abstract void pauseApp()
Definuje chování MIDletu při odchodu mezi čekající Uvolňuje prostředky neobsahující informace nutné pro pokračování po opětném oživení Jednodušší aplikace mívají tuto metodu definovánu jako prázdnou

51 Přechodové metody 3/3 protected abstract void destroyApp(boolean unconditional) throws MIDletStateChangeException Uvolňuje všechny prostředky používané aplikací Parametr specifikuje, může-li aplikace požadavek na své ukončení odmítnout (=false) Odmítnutí požadavku na ukončení realizuje aplikace vyhozením výjimky

52 Přechody vyvolané MIDletem 1/2
Každá z přechodových metod má svého partnera, který slouží k tomu, aby MIDlet mohl požádat OS o převedení do požadovaného stavu sám Přechod do stavu Čekající public final void notifyPaused() Přechod do stavu Aktivní public final void notifyResume() Přechod do stavu Ukončená public final void notifyDestroyed() Při reakci na tato volání OS předpokládá, že MIDlet je pro přechod připraven, a proto již překryté abstraktní metody nevolá

53 Přechody vyvolané MIDletem 2/2
Metody žádající o převedení do jiného stavu je možno volat i z jiných balíčků, protože jsou deklarovány jako public Volání notifyResume nemůže MIDlet iniciovat sám (nepracuje, čeká), může jej však o to požádat jiný, aktivní MIDlet a aktivovat jej samotným zasláním zprávy Start Ukončený Aktivní Čekající notifyResume notifyPaused notifyDestroyed

54 Náš PrvniMIDlet Má implementované jen povinné metody překrývající abstraktní metody rodiče + konstruktor Metody pouze vypisují zprávy na standardní výstup MIDlet slouží jen k ověření funkce jednotlivých metod překrývajících abstraktní metody rodiče Lze z něj odvodit kdy je která metoda volána, kdy se vytváří nová instance a částečně i kdy se instance ruší

55 Aplikace DieMIDlet_1 Postupně vytvoříme program na házení kostkou
Budeme simulovat běžnou hrací kostku Program bude ovládán dvěma příkazy: Next – realizuj další hod Quit – ukonči program V první etapě žádnou další funkcionalitu přidávat nebudeme

56 Struktura programu DieMIDlet_1

57 DieMIDlet_1 – realizace
import javax.microedition.midlet.*; public class DieMIDlet_1 extends MIDlet { private static int m = 0; public DieMIDlet_1() { System.out.println("Midlet_1 Nr. "+ ++m +" constructed"); }// DieMIDlet_1() public void startApp() { System.out.println("Midlet_1 Nr. " + m + " activated"); new DieCast_1(this); //DieCast starts another thread }//startApp() public void pauseApp() {} public void destroyApp( boolean unconditional ) throws MIDletStateChangeException { System.out.println("Midlet_1 Nr. " + m + " destroyed"); notifyDestroyed(); }//public void destroyApp( boolean unconditional ) }//class DieMIDlet_1 extends MIDlet

58 Cvičení: Vlastní MIDlet
Vytvořte prázdný MIDlet Do metod překrývajících abstraktní metody rodičovské třídy vložte příkazy k tisku do standardního výstupu Na konci těla metody startUp() vytvořte instanci třídy DieCast, která bude mít prozatím na starosti vlastní běh aplikace Upravte třídu podle vlastního uvážení

59 Cvičení: Zadání MIDletů pro JAR&JAD
Otevřete okno pro nastavování vlastností projektu Ve stromu vlevo zadejte ve složce Application Descriptor položku MIDlets Stiskem Add otevřete okno pro přidání MIDletu Zadejte jako název MIDletu text, kterým chcete MIDlet označovat na obrazovce Ze seznamu vyberte třídu příslušného MIDletu.

60 Cvičení: Testování MIDletu
Stiskem Shift+F11 sestavte (build) projekt Stiskem F6 svoji aplikaci spusťte Prověřte funkci MIDletu v emulátoru Zkuste si nastavit zarážky (breakpoints) a spustit program pod debuggerem Nechte si v okně Debugger Window nechat zobrazit hodnoty proměnných Zkuste program krokovat

61 Cvičení: Změna emulátoru
Program je vhodné vyzkoušet pro různé konfigurace Změna emulátoru: Ve vlastnostech projektu zadejte nastavování platformy V textovém okně Device zadejte požadovaný emulátor Spusťte znovu svůj program

62 Suity

63 Koncepce MIDlety se mohou sdružovat do suit
Zařízení nenahrává jednotlivé MIDlety, ale může nahrát celou jejich skupinu – suitu Při spuštění suity zařízení zobrazí nabídku MIDletů ve suitě, z níž uživatel vybere ten, jenž se spustí MIDlety ve suitě mohou sdílet třídy i paměť Bezpečnostní opatření: Permanentní paměť mohou sdílet POUZE MIDlety v rámci jedné suity; pro jiné je nepřístupná (ochrana proti virům)

64 MIDlet Suites Suita je reprezentována dvojicí souborů:
JAR (Java Archive) obsahuje potřebný kód a data JAD (Java Application Descriptor) obsahuje pomocné informace JAD – textový soubor s řádky typu: název_atributu: hodnota_atributu Některé atributy jsou povinné (např. velikost JAR), jiné volitelné (povinné atributy dodává IDE samo) Tvůrce může definovat i své vlastní atributy MIDlet může hodnoty atributů zjišťovat za běhu

65 Parametry v JAD Vedle povinných a volitelných parametrů mohou být v souboru JAD i parametry uživatelské MIDlet je může přečíst a upravit dle nich své chování (lze je tak modifikovat bez nutnosti nového překladu) Parametry JAD zjišťuje metoda public final String getAppProperty(String key) Názvy parametrů jsou citlivé na velikost písmen Hodnoty parametrů mohou být i několikaslovné Nelze do nich vkládat Escape sekvence (např. "\n") přesněji: vkládat je lze, ale nereaguje na ně

66 Přidání parametru do JAD
Otevřete okno s vlastnostmi projektu Ve stromu vlevo zadejte ve složce Application Descriptor položku Attributes Zadejte své jméno v atributu MIDlet-Vendor Stiskem Add otevřete okno, v němž zadáte vlastní atribut Potvrďte zadání stiskem OK

67 Přečtení parametru z JAD
Vytvořte nový MIDlet jako kopii původního a nazvěte jej DieCast_1b Upravte metodu startApp tak, aby na standardní výstup vypisovala i vás jako dodavatele – např.: public void startApp() { String author = getAppProperty( "Author" ); System.out.println("Midlet_1b Nr. " + m + " from " + author + " started"); new DieCast_1(this); }//startApp() Přeložte a spusťte suitu Zkontrolujte standardní výstup druhého MIDletu

68 Low Level User Interface
Nízkoúrovňové uživatelské rozhraní

69 Základní charakteristika
Pod Low-Level rozhraním rozumíme skupinu tříd, jež mají na starosti přímé ovládání klávesnice a kreslení na obrazovku Tyto třídy jsou schopny kreslit Jednoduché grafické tvary (plné i obrysy) Čáry (obrysy a čáry umí plné či čárkované) Obdélníky (i se zakulacenými rohy) Elipsy a jejich výseče Text Obrázky Všechny jsou součástí balíku javax.microedition.lcdui

70 Získání displeje Vlákno, které chce, aby se jeho výstup zobrazoval, se musí vnutit na displej – požádá jej voláním void setCurrent( Displayable d ) Třída Displayable je (uměle) abstraktní – parametr je proto instancí některého jejího potomka Canvas (plátno) pro kreslení a low-level GUI Screen pro high-level GUI Screen se přímo nepoužívá – používají se potomci: Form pro formuláře s možností zadání čísel, textů a voleb Textbox pro zadání delších textů List pro výběr ze seznamu možností Alert pro asynchronní zprávu či upozornění

71 Třída Displayable Abstraktní třída, avšak bez abstraktních metod
Definuje čtyři metody: boolean isShown() zjišťuje, jestli je objekt opravdu zobrazován void addCommand( Command cmd ) přidává další příkaz do seznamu void removeCommand( Command cmd ) vyjímá příkaz ze seznamu void setCommandListener( CommandListener l ) nastavuje posluchače, jenž definuje reakci na příkazy (nepřidává, nastavuje!) Na rozdíl od AWT či Swingu je posluchač společný pro všechny příkazy

72 Ovládání příkazy Protože naše třída kreslí, využijeme Canvas
Canvas je abstraktní třída => musíme použít potomka Příkazy jsou objekty typu Command – konstruktor: Command(String label, int comType, int prior) label je návěští, které pojmenovává sadu příkazů comType je typ příkazu prior je relativní priorita příkazu vůči kolegům (0=max) Příkazy se postupně přidávají do seznamu Nejdůležitější (dle názoru systému) většinou systém umístí tak, aby byly co nejsnáze dostupné

73 void commandAction(Command c, Displayable d)
Posluchači Posluchač musí implementovat rozhraní CommandListener Posluchač nemusí být v samostatné třídě, třída může zároveň fungovat jako posluchač CommandListener vyžaduje implementaci metody void commandAction(Command c, Displayable d) Vzhledem k parametrům metody může jeden posluchač sloužit několika pánům

74 DieCast_1 1/2 package workshop; import java.util.*;
import javax.microedition.lcdui.*; import javax.microedition.midlet.*; class DieCast_1 extends ShowDie_1 //extends Canvas implements CommandListener { private static Command cmdQuit; private static Command cmdNext; private static MIDlet midlet; DieCast_1( MIDlet midlet ) { Display.getDisplay( midlet ).setCurrent( this ); this.midlet = midlet; cmdQuit = new Command( "Quit", Command.EXIT, 1); addCommand( cmdQuit ); cmdNext = new Command( "Next", Command.OK, 0); addCommand( cmdNext ); setCommandListener( this ); }//DieCast_1( MIDlet midlet )

75 DieCast_1 2/2 public void commandAction(Command c, Displayable d){
if( c == cmdQuit ) { //Leaving the program try{ midlet.destroyApplication( true ); } catch( Exception e ) { e.printStackTrace(); } } else if( c == cmdNext ) { //Next die cast cast(); }//protected void keypressed( int code ) private static final int MaxN = 9; private static Random rnd = new Random(); int cast() {//Uses inherited n for the just casted number n = (rnd.nextInt()&0X7fffffff) % MaxN + 1; repaint(); //Show the new cast ... return n; //... and return it }//int cast() }//class DieCast_1 extends ShowDie_1

76 Třída Canvas – vstup z klávesnice
Canvas umí reagovat i na jednotlivé klávesy. K tomu použijeme metody: Po stisku klávesy vyvolá systém metodu protected void keyPressed(int keyCode) Po puštění klávesy vyvolá systém metodu protected void keyReleased(int keyCode) Při zadání kódu funkcí autorepeat vyvolá systém metodu protected void keyRepeated(int keyCode) Klávesnice jednotlivých zařízení se velmi liší Povinné jsou jen klávesy "0" – "9", "*" a "#" (chybí "clear") Některé klávesnice mají "joystick" Definováno 9 akcí, které výrobce namapuje Můžete reagovat na kód klávesy nebo na přiřazenou akci

77 Třída Canvas – kódy × akce
Kódum odpovídají konstanty KEY_NUM0 – KEY_NUM9, KEY_POUND (#) a KEY_STAR (*) Akcím odpovídají konstanty UP, DOWN, LEFT, RIGHT FIRE GAME_A, GAME_B, GAME_C, GAME_D Akci přiřazenou klávese s daným kódem zjistíme pomocí int getGameAction(int keyCode) Kód klávesy, jíž je přiřazena akce, zjistíme pomocí int getKeyCode(int gameAction)

78 DieMIDlet_2 – rozšíření
Umožní "hodit kostkou" prostřednictvím stisku klávesy FIRE Vytvoříme kostku jež umožní podvádět – na stisk předem definované klávesy umožní: 0 – povolí, resp. zakáže hození nuly 2–9 – nastaví dané číslo jako nejvyšší hoditelné číslo šipka nahoru – zadá házení pouze horní poloviny čísel šipka dolů – zadá házení pouze spodní poloviny čísel * (hvězdička) – padají čísla 1 – 9

79 DieCast_2 – startCast public class DieCast_2 extends ShowDie_1
implements CommandListener { private static DieCast_2 me; private static DieMIDlet_2 midlet; private static Command cmdQuit; private static Command cmdNext; private DieCast_2() { cmdQuit = new Command( "Quit", Command.EXIT, 1); cmdNext = new Command( "Next", Command.OK, 0); addCommand( cmdQuit ); addCommand( cmdNext ); setCommandListener( this ); }//DieCast_2( MIDlet midlet ) static void startCast( DieMIDlet_2 midlet ) { if( me == null ) me = new DieCast_2(); super( Display.getDisplay( midlet ) ); this.midlet = midlet; Display.getDisplay( midlet ).setCurrent( me ); }//static void startCast( DieMIDlet_2 midlet )

80 DieCast_2 – cast private static Random rnd = new Random();
private static int MinN = 1; //Initioal minimum private static int MaxN = 6; //Initioal maximum private static int min = MinN; //Actual minimum private static int max = MaxN; //Actual maximum private static int mmm = max - min + 1 //Interval int cast() { n = (rnd.nextInt()&0X7fffffff) % mmm + min; repaint(); //Repaint the canvas by new die return n; }//int cast()

81 DieCast_2 – keyPressed protected void keyPressed( int keyCode ) {
switch( getGameAction(keyCode) ) { case FIRE: cast(); break; case UP: min = MaxN/2; max = MaxN; break; //High # case DOWN: min = MinN; max = MaxN/2; break; //Low # default: switch( keyCode ) { case KEY_NUM0: //Switch permission of the value 0 min = MinN ^= 1; break; case KEY_NUM2: //Set the max allowed value case KEY_NUM3: case KEY_NUM4: case KEY_NUM5: case KEY_NUM6: case KEY_NUM7: case KEY_NUM8: case KEY_NUM9: min = MinN; max = MaxN = (keyCode - KEY_NUM0); }//switch( keyCode ) }//switch action mmm = max – min + 1; }//protected void keyPressed( int keyCode )

82 Třída Canvas – překreslování
Abstraktní – potomci musí překrýt abstraktní metodu void paint( Graphics g ) Metodu paint volá systém, když se rozhodne překreslit obrazovku Program žádá o překreslení plátna voláním metody final void repaint() O překreslení části plátna žádáme voláním metody final void repaint(int x, int y, int w, int h) Okamžité překreslení (tj. provedení všech čekajících příkazů repaint) zařídíte voláním final void serviceRepaints()

83 Canvas – další užitečné metody
int getHeight() Vrací výšku obrazovky v bodech int getWidth() Vrací šířku obrazovky v bodech protected void hideNotify() Je volána systémem po odebrání displeje (můžeme zde např. zastavit animaci) protected void showNotify() Je volána systémem před předáním displeje (můžeme zde např. opět spustit animaci)

84 Třída Graphics – kreslení a psaní
Abychom mohli na plátno kreslit, potřebujeme nějaké kreslítko (grafický kontext) – k tomu slouží instance třídy Graphics Umožňuje: Kreslit základní geometrické tvary Úsečky Vyplněné a nevyplněné obdélníky Vyplněné a nevyplněné eliptické výseče Volit typ kreslené čáry Vykreslovat obrázky Psát texty s možností volby písem, jejich velikostí a řezů

85 Graphics – kreslení void drawLine(int x1, int y1, int x2, int y2) Nakreslí čáru mezi body [x1;y1] a [x2;y2] void drawRect(int x, int y, int w, int h) void fillRect(int x, int y, int w, int h) Nakreslí (draw), resp. vyplní(fill) obdélník s levým horním rohem v [x;y], široký w bodů a vysoký h bodů void drawArc(int x, int y, int w, int h, int s, int u) void fillArc(int x, int y, int w, int h, int s, int u) Nakreslí, resp. vyplní část elipsy vepsané do obdélníku {x;y;w;h} s počátkem v úhlu s a středovým úhlem u l

86 Graphics – barvy Nerozlišuje se barva popředí a pozadí – pracuje se pouze s barvou, kterou se kreslí int getColor() Vrátí barvu kreslení ve formátu 0xRRGGBB void setColor( int RGB ) Nastaví barvu zadanou ve formátu 0xRRGGBB Barvy je možno zadávat i zjišťovat po komponentách int getGrayScale() void setGrayScale( int level ) Zjistí, resp. nastaví úroveň šedi jako číslo 0–255 (funguje i u barevných displejů)

87 ShowDie_1 1/3 public class ShowDie_1 extends Canvas {
private static final int CMASK = 0xFFFFFF; //Color mask protected static int n; //Casted number //maxX,maxY = size of display; max = size of die private int maxX, xr, x0, dx; //[xr;yr] top left corner of die private int maxY, yr, y0, dy; //[x0;y0] pos.of top left point private int dd, max; //dx,dy = offset of next point //dd = diameter of point private Graphics g; private int color = 0xFFFF00; //Initial color ShowDie_1( Display display ) { System.out.println("ShowDie_1"); maxX = getWidth(); maxY = getHeight(); max = Math.min( maxX, maxY ) - 4; xr = (maxX - max) / 2; yr = (maxY - max) / 2; x0 = xr + max / 10; y0 = yr + max / 10; dx = 3 * max / 10; dy = 3 * max / 10; dd = 2*max/10; }//ShowDie_1( Display display )

88 ShowDie_1 2/3 public void paint( Graphics g ) {
g.setColor( color ^= CMASK ); //Clear last cast g.fillRect( 0, 0, maxX, maxY ); // ... by inverted color g.setColor( color ^= CMASK ); //Prepare color for die side g.fillRect( xr, yr, max, max ); //Paint the empty die side g.setColor( color ^= CMASK ); //Prepare color for points this.g = g; //Remember the Graphics object for L_# methods switch( n ) { //Paint the points case 1: L_0(y0); L_2(y0+dy); L_0(y0+dy+dy); break; case 2: L_4(y0); L_0(y0+dy); L_1(y0+dy+dy); break; case 3: L_4(y0); L_2(y0+dy); L_1(y0+dy+dy); break; case 4: L_5(y0); L_0(y0+dy); L_5(y0+dy+dy); break; case 5: L_5(y0); L_2(y0+dy); L_5(y0+dy+dy); break; case 6: L_5(y0); L_5(y0+dy); L_5(y0+dy+dy); break; case 7: L_5(y0); L_7(y0+dy); L_5(y0+dy+dy); break; case 8: L_7(y0); L_7(y0+dy); L_5(y0+dy+dy); break; case 9: L_7(y0); L_7(y0+dy); L_7(y0+dy+dy); break; }//switch }//public void paint( Graphics g )

89 ShowDie_1 3/3 private void L_0( int y ) { } //L_0 = . . .
g.fillArc( x0+dx+dx, y, dd, dd, 0, 360 ); } //L_1 = . . O private void L_2( int y ) { g.fillArc( x0+dx, y, dd, dd, 0, 360 ); } //L_2 = . O . private void L_4( int y ) { g.fillArc( x0, y, dd, dd, 0, 360 ); } //L_4 = O . . private void L_5( int y ) { g.fillArc( x0, y, dd, dd, 0, 360 ); g.fillArc( x0+dx+dx, y, dd, dd, 0, 360 ); } //L_5 = O . O private void L_7( int y ) { g.fillArc( x0+dx, y, dd, dd, 0, 360 ); g.fillArc( x0+dx+dx, y, dd, dd, 0, 360 ); } //L_7 = O O O }//public class ShowDie_1 extends Canvas

90 High Level User Interface
Uživatelské rozhraní vyšších hladin

91 Základní charakteristika
Pod High-Level rozhraním rozumíme skupinu tříd, jež mají na starosti "formulářový vstup": Zadání hodnot textových, číselných, "datumových" Možnost výběru jedné z několika možností Možnost nastavení či zrušení dané volby Všechny jsou součástí balíku javax.microedition.lcdui

92 Třída Form – formulář Vedle nabídek realizovaných instancemi třídy Command používáme i jiné způsoby zadání dat Hlavním prostředkem jsou instance třídy Form – ty vedle příkazů umožňují: Přímé zadání textových, číselných a "datumových" hodnot Zadání číselných hodnot pomocí stupnic Nastavování voleb Nastavování hodnot přepínačů Dalšími třídami pro zadání a editaci dat jsou TextBox pro zadávání a editaci rozsáhlejších textů List pro výběr jedné či více možností ze seznamu Tyto třídy si však v tomto úvodu neukážeme

93 Objekty umístitelné do formuláře
Na formulář se umísťují položky = instance Item Item je abstraktní – používají se její potomci: TextField – zadání textových a/nebo číselných hodnot (umožňuje zadat typ vstupu: obecný text, číslo, heslo, telefon, URL adresa, ová adresa, vlastní maska) DateField – zadání dat ("datumů") – pro snazší zadání často nabízí kalendář Gauge – zadání číselných hodnot pomocí stupnice ImageItem – obrázková položka (jen informační, neumožňuje nic zadat) StringItem – řetězcová položka (jen informační) ChoiceGroup – nastavení přepínače, resp. voleb (jestli se jedná o přepínač či volby se zadá při volání konstruktoru)

94 Vložení položek do formuláře
Položky se vkládají pomocí metod : append( Item item ) vloží na konec položku item append( String str) vloží na konec řetězec str append( Image image ) vloží na konec obrázek image insert(int itemNum, Item item) vloží položku item před položku s indexem itemNum Položku je možno vyjmout příkazem: delete(int itemNum)vyjme položku číslo itemNum Položku je nahradíme příkazem: set(int itemNum, Item item) nahradí položku s indexem itemNum položku item

95 Zadání a aktualizace dat
Zajímavé události zachytává posluchač změn, který se nastavuje příkazem: void setItemStateListener( ItemStateListener itemStateListener ) Objekt typu ItemStateListener musí implementovat metodu: itemStateChanged(Item item) která obdrží odkaz na položku, u níž došlo k nějaké změně Metoda nejenom zjišťuje obsah položky item, ale může přitom nastavovat i parametry jiných položek

96 DieMIDlet_3 – rozšíření
Umožní uživateli zadávat parametry kostky s využitím High-Level rozhraní Bude možno nastavit: Barvu kostky zadáním barevných složek, z nichž se bude barva skládat Tvar obrazců na kostce – bude možno zvolit: Kruh Čtvercový blok Kružnici Čtverec Nejnižší hoditelné číslo s využitím stupnice Nejvyšší hoditelné číslo přímým zadáním hodnoty

97 Struktura programu

98 Setup_3 1/4 package workshop; import javax.microedition.lcdui.*;
class Setup_3 extends Form implements ItemStateListener { private static Setup_3 me = null; private static DieCast_3 dc; private ChoiceGroup cgrColor; private ChoiceGroup cgrShape; private Gauge gauMin; private TextField txfMax; private String[] cName = { "Red", "Green", "Blue" }; private String[] sName = { "Disk", "Block", "Rectangle", "Circle" };

99 Setup_3 2/4 private Setup_3(DieCast_3 dc) {
super("Setup"); //The only Form constructor has String param. this.dc = dc; addCommand( dc.cmdOK ); addCommand( dc.cmdQuit ); setCommandListener( dc ); cgrColor = new ChoiceGroup( "Color", Choice.MULTIPLE, cName, null ); cgrShape = new ChoiceGroup( "Shape", Choice.EXCLUSIVE, sName, null ); gauMin = new Gauge( gauMinLabel(), true, dc.max, dc.min ); txfMax = new TextField( txfMaxLabel(), ""+dc.max, 2, TextField.NUMERIC ); append( cgrColor ); append( cgrShape ); append( gauMin ); append( txfMax ); setItemStateListener( this ); }//private Setup_3()

100 Setup_3 3/4 public void itemStateChanged( Item item ) {
if( item == cgrColor ) { int color = 0; for( int i=0; i < 3; i++ ) { color <<= 8; color |= cgrColor.isSelected(i) ? 0xFF : 0; } ShowDie_3.color = color; }else if( item == cgrShape ) { int i; ShowDie_3.drawer = ShowDie_3.drawers[i=cgrShape.getSelectedIndex()]; }else if( item == gauMin ) { dc.min = gauMin.getValue(); gauMin.setLabel(gauMinLabel()); txfMax.setLabel(txfMaxLabel()); }else if( item == txfMax ) { dc.max = Integer.parseInt( txfMax.getString() ); }else throw new IllegalArgumentException(); }//void ItemStateChanged( Item item )

101 Setup_3 4/4 private String gauMinLabel() {
return "From [0-" + dc.max + "]: " + dc.min; }//private String gauMinLabel() private String txfMaxLabel() { return "To [" + dc.min + "-" + dc.MaxN + "]: " + dc.max; }//private String txfMaxLabel() static void setup(DieCast_3 dc) { if( me==null ) { me = new Setup_3( dc ); } Display.getDisplay( dc.midlet ).setCurrent( me ); }//static void setup() }//class Setup_3 extends Form implements ItemStateListener

102 ShowDie_3 1/4 package workshop; import java.util.*;
import javax.microedition.lcdui.*; public class ShowDie_3 extends Canvas { static int color = 0xFFFF00; final static int COLOR_0 = 0xFFFF00; private static final int CMASK = 0xFFFFFF; protected static int n; private int maxX, xr, x0, dx; private int maxY, yr, y0, dy; private int dd, max; private static Graphics g;

103 ShowDie_3 2/4 static interface Drawer {
void draw(int x, int y, int w, int h); }//private static interface Drawerdrawer static Drawer drawers[] = { new Drawer(){ //Disk public void draw(int x, int y, int w, int h){ g.fillArc(x, y, w, h, 0, 360); }}, new Drawer(){ //Block g.fillRect(x, y, w, h); }}, new Drawer(){ //Rectangle g.drawRect(x, y, w, h);}}, new Drawer(){ //Circle g.drawArc(x, y, w, h, 0, 360 ); }}, }//static Drawer drawers[] static Drawer drawer = drawers[0];

104 ShowDie_3 3/4 ShowDie_3() { System.out.println("ShowDie_1");
maxX = getWidth(); maxY = getHeight(); max = Math.min( maxX, maxY ) - 4; xr = (maxX - max) / 2; yr = (maxY - max) / 2; x0 = xr + max / 10; y0 = yr + max / 10; dx = 3 * max / 10; dy = 3 * max / 10; dd = 2*max/10; }//ShowDie_1() public void paint( Graphics g ) { g.setColor( color ^= CMASK ); g.fillRect( 0, 0, maxX, maxY ); g.fillRect( xr, yr, max, max ); this.g = g; switch( n ) { case 1: L_0(y0); L_2(y0+dy); L_0(y0+dy+dy); break; case 2: L_4(y0); L_0(y0+dy); L_1(y0+dy+dy); break; case 3: L_4(y0); L_2(y0+dy); L_1(y0+dy+dy); break; case 4: L_5(y0); L_0(y0+dy); L_5(y0+dy+dy); break; case 5: L_5(y0); L_2(y0+dy); L_5(y0+dy+dy); break; case 6: L_5(y0); L_5(y0+dy); L_5(y0+dy+dy); break; case 7: L_5(y0); L_7(y0+dy); L_5(y0+dy+dy); break; case 8: L_7(y0); L_7(y0+dy); L_5(y0+dy+dy); break; case 9: L_7(y0); L_7(y0+dy); L_7(y0+dy+dy); break; } }//public void paint( Graphics g )

105 ShowDie_3 4/4 private void L_0( int y ) {} //L_0 = . . .
private void L_1( int y ) { //L_1 = . . O drawer.draw( x0+dx+dx, y, dd, dd); }//private void L_1( int y ) private void L_2( int y ) { //L_2 = . O . drawer.draw( x0+dx, y, dd, dd); }//private void L_2( int y ) private void L_4( int y ) { //L_4 = O . . drawer.draw( x0, y, dd, dd); }//private void L_4( int y ) private void L_5( int y ) { //L_5 = O . O drawer.draw( x0, y, dd, dd); }//private void L_5( int y ) private void L_7( int y ) { //L_7 = O O O drawer.draw( x0+dx, y, dd, dd); }//private void L_7( int y )

106 Uchování hodnot mezi seancemi

107 Balík javax.microedition.rms
RMS (Record Management System) umožňuje uložit data do trvalé paměti a opět je odtud načíst Uložená data mohou MIDlety v rámci suity sdílet – je to jediná možnost, jak si předávat informace MIDletům mimo suitu je tato paměť nepřístupná Data zůstanou zachována i po vypnutí zařízení Instance třídy RecordStore jsou jednoduché, záznamově orientované, pojmenované databáze Záznamy jsou identifikovány dle svých ID Operace probíhají prostřednictvím pole bajtů

108 RecordStore – operace s databází
static String[] listRecordStores() vrátí seznam jmen databází, které jsou k dispozici static RecordStore openRecordStore(String recordStoreName, boolean createIfNecessary) Otevře (a případně vytvoří) databázi se zadaným názvem void closeRecordStore() – Uzavře danou databázi static void deleteRecordStore(String recordStoreName) Odstraní databázi se zadaným názvem String getName() – Vrátí název dané databáze int getVersion() Vrátí verzi dané databáze (verze se zvyšuje po každé změně obsahu) long getLastModified() – Vrátí systémový čas poslední modifikace int getSize() – Vrátí počet bajtů, které daná databáze zabírá int getSizeAvailable() Vrátí počet bajtů, o něž může databáze ještě narůst

109 RecordStore – operace se záznamy
int getNumRecords() – Vátí počet záznamů v databázi int addRecord(byte[] data, int offset, int numBytes) Přidá do databáze nový záznam a vrátí jeho ID (atomická operace) byte[] getRecord(int recordId) Vrátí vektor bajtů s daty ze záznamu recordId int getRecord(int recordId, byte[] buffer, int offset) Naplní vektor buffer od pozice offset daty ze záznamu recordId, Vrátí počet přenesených bajtů void setRecord(int ID, byte[] data, int off, int nb ) Nahradí záznam ID záznamem tvořeným nb bajty od pozice data[off] void deleteRecord(int recordId) – Odstraní záznam recordId int getRecordSize(int recordId) – Vrátí velikost záznamu RecordEnumeration enumerateRecords(RecordFilter filter, RecordComparator comparator, boolean keepUpdated) Vrátí iterátor pro procházení vybraných záznamů ve specifikovaném pořadí

110 Potřebné třídy z balíku java.io
Protože se s databází komunikuj prostřednictvím vektorů bajtů, je potřeba zprostředkovatel Používají se instance tříd z java.io Pro zápis se používá "cesta" DataOutputStream ® ByteArrayOutputStream ® RecordStore Pro čtení se používá naopak "cesta" RecordStore ® ByteArrayInputStream ® DataInputStream

111 DieMIDlet_4 – rozšíření
Bude si pamatovat nastavené hodnoty i po vypnutí

112 Metoda loadSetup 1/2 RecordStore rs; byte[] input;
static void loadSetup() { RecordStore rs; byte[] input; ByteArrayInputStream bais; DataInputStream dis; try { rs = RecordStore.openRecordStore( RS_NAME, false ); }catch( RecordStoreNotFoundException e ) { DieCast_4.reset(); saveSetup(); return; }catch( Exception e ) { DieCast_4.reset(); return; } try { if( (input = rs.getRecord( 1 )) == null ) throw new NullPointerException(); try { rs.closeRecordStore(); RecordStore.deleteRecordStore( RS_NAME ); }catch( Exception e2 ) { return;

113 Metoda loadSetup 2/2 bais = new ByteArrayInputStream( input );
dis = new DataInputStream( bais ); try { DieCast_4.min = dis.readInt(); DieCast_4.max = dis.readInt(); DieCast_4.drawer = DieCast_4.drawers[ Setup_4.drawerID = dis.readInt() ]; ShowDie_3.color = dis.readInt(); } catch( Exception e ) { DieCast_4.reset(); return; System.out.println("loaSetup: setup loaded"); }//static void loadSetup()

114 Metoda saveSetup 1/3 static void saveSetup() {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream daos = new DataOutputStream( baos ); byte[] output; RecordStore rs; try { daos.writeInt( DieCast_4.min ); daos.writeInt( DieCast_4.max ); daos.writeInt( Setup_4.drawerID ); daos.writeInt( ShowDie_3.color ); DieCast_4.drawer = DieCast_4.drawers[Setup_4.drawerID]; }catch( Exception e ) { return; } output = baos.toByteArray();

115 Metoda saveSetup 2/3 try {
rs = RecordStore.openRecordStore( RS_NAME, false ); }catch( RecordStoreNotFoundException e ) { rs = RecordStore.openRecordStore( RS_NAME, true ); }catch( Exception e2 ) { return; } //Create the first (and only) record try{ rs.addRecord( output, 0, output.length ); }catch( Exception e2 ) { }catch( Exception e ) {

116 Metoda saveSetup 3/3 try {
rs.setRecord( 1, output, 0, output.length ); }catch( Exception e ) { rs.closeRecordStore(); RecordStore.deleteRecordStore( RS_NAME ); }catch( Exception e2 ) { return; } System.out.println("saveSetup: setup saved, rs closed"); }//static void saveSetup()

117 K O N E C


Stáhnout ppt "Tvorba aplikací pro mobilní zařízení"

Podobné prezentace


Reklamy Google