Introduzione a Java 2 Micro Edition Dr. Francesca Martelli [email protected] http://www.di.unipi.it/~f.martel/ Stanza: 382 DB Tel: 050 2212 754 1 Cosa sappiamo e cosa faremo Conoscenza di java? Conoscenza di HTML? Java 2 MicroEdition Introduzione alla programmazione J2ME J2ME Wireless Toolkit Il linguaggio XHTML 2 Cosa Serve (1) Documentazione J2ME MIDP 2.0, CLDC 1.1 http://java.sun.com/javame/reference/apis.jsp Qualsiasi tutorial che trovate su internet Queste slide che troverete sulla mia home page Libri (opzionali): James Keogh, J2ME: The Complete Reference, McGrawHill R. Riggs, A. Taivalsaari, J. Van Peursem, J. Huopaniemi, M. Patel, A. Uotila, Programming Wireless Devices with the Java 2 Platform, Micro Edition, Second Edition, Addison Wesley 3 L’Architettura Java Compilatore Java: trasforma il linguaggio di programmazione Java in un insieme di bytecode Java Java Virtual Machine (JVM): interpreta il bytecodes Java per eseguire il programma Java Vantaggi di Java: Portabilità: “write once, run anywhere” Sicurezza: scaricando applicazioni da un ambiente potenzialmente inaffidabile, le chiamate di sistema vengono controllate dalla Java Native Interface (JNI) possibilità di sfruttare le applicazioni in locale, residenti e funzionanti anche off-line interfacciamento con le piattaforme web che lavorano con JAVA (Servlet o JSP) è immediato 4 Le versioni di Java 5 Java 2 Java 1.2 diventa semplicemente Java 2, anche se le versioni di JDK e JRE rimangono 1.2. La piattaforma Java viene divisa in 3 edizioni: Java 2 Standard Edition (J2SE): per lo sviluppo di applicazioni convenzionali da desktop Java 2 Enterprise Edition (J2EE): sovrainsieme di J2SE, rivolto alla programmazione di impresa, con particolare enfasi sullo sviluppo dal lato server, tramite l’uso di Enterprise JavaBeans, applicazioni web (servlets e JavaServer Pages), CORBA, e XML Java 2 Micro Edition (J2ME): sottoinsieme di J2SE, orientato ai dispositivi portatili che non possono supportare un’implementazione totale di J2SE Nonostante la sovrapposizione, questa divisione agevola l’evolvere di Java in differenti direzioni mantenendo intatto lo spirito del linguaggio 6 Java 2 Micro Edition La mancanza di uniformità delle configurazioni hardware fra i vari piccoli dispositivi ha posto una grossa sfida per la comunità Java J2ME è nato per superare questo limite, ed è uno standard che serve molti dispositivi a capacità limitate (telefoni cellulari, PDA e dispositivi plug-in), che hanno configurazioni hardware non standard La JCP ha usato un duplice approccio: La definizione di due CONFIGURAZIONI: Una per i dispositivi portatili Una per i dispositivi plug-in La definizione di PROFILI, per ogni categoria di dispositivo 7 Configurazioni Una configurazione definisce l’ambiente base di esecuzione: Il punto chiave è che ogni configurazione è specifica per una famiglia di dispositivi con capacità simili Ad oggi, sono definite 2 configurazioni, entrambe prevedono connettività alla rete, fissa o wireless: Limitata JVM, nucleo di classi derivate da J2SE Connected Device Configuration (CDC): box TV, sistemi di navigazione per auto,... Connected Limited Device Configuration (CLDC):cellulari,PDA Non c’è netta linea di confine fra le due configurazioni: CDC è un sovrainsieme del CLDC, con in più alcune classi di J2SE e altre nuove 8 Profili Un profilo estende una configurazione, aggiungendo classi per specifici usi dei dispositivi, omesse nella configurazione di base (per esempio, classi per l’interfaccia utente) Il Mobile Information Device Profile (MIDP) è basato su CLDC Classi per la memorizzazione locale, una user interface, funzionalità per il networking 9 Profili (2) Altri profili sono: Personal Digital Assistant Profile (PDAP): estende CLDC per sfruttare le maggiori capacità dei PDA rispetto ai semplici dispositivi MIDP, (migliori display e maggiore memoria Foundation Profile: aggiunge classi J2SE al CDC, ma non per l’interfaccia utente; è la base per costruire altri profili Personal Profile (con configurazione CDC): ridefinisce PersonalJava come profilo J2ME; estende il Foundation Profile per implementare una user interface sofisticata Personal Basis Profile: simile al Personal Profile (con configurazione CDC e Foundation Profile), ma implementa user interface più semplice Game Profile (con configurazione CDC): contiene le classi specifiche per sviluppare giochi ...J2ME è in evoluzione... In una configurazione possono coesistere più profili 10 Connected Limited Device Configuration Per capire MIDP bisogna prima conoscere la configurazione CLDC 1.1, definita nel JSR-139 Per dispositivi “things that you hold in your hand”, caratterizzati da connettività wireless, banda ridotta, accesso discontinuo, batterie limitate e bassa potenza di calcolo e memoria http://java.sun.com/javame/reference/apis/jsr139/ Da 128KB a 512KB di memoria non-volatile (codice) 32KB di memoria volatile (runtime) Processori a 16-bit (o 32-bit) Possono non avere interfaccia utente I dispositivi CLDC usano la KJava Virtual Machine (KVM), versione molto ridotta della JVM 11 CLDC: Requisiti (1) No floating point: tipi e costanti floating-point, le classi di J2SE che trattano con valori floating-point non sono supportati (computazione pesante); i metodi che ritornano valori floating point sono rimossi; con opportune librerie è possibile utilizzare il calcolo in virgola mobile No object finalization: il metodo finalize è rimosso da java.lang.Object, per semplificare il compito del garbage collector, che semplicemente recupera tutti gli oggetti non referenziati (così si evita il “risorgere” degli oggetti); Errori a runtime: eccezioni sottoclassi di java.lang.Error lanciate dalla virtual machine. Solo 3 classi di errori: java.lang.Error, java.lang.OutOfMemoryError, java.lang.VirtualMachineError Ogni altra situazione di errore è trattata in modo dipendente dall’implementazione della KVM, tipicamente la terminazione 12 CLDC: Requisiti (2) Interfaccia Nativa Java (JNI) non supportata: non è possibile chiamare funzioni native del sistema operativo ospitante No reflection: non si possono usare le classi Reflection per ottenere informazioni sulla JVM in esecuzione No object serialization No gruppi di thread: la VM non supporta la classe ThreadGroup quindi non si possono lanciare (o fermare) più thread insieme Le classi “ereditate” da J2SE devono essere un sottoinsieme delle classi di J2SE 1.3. I metodi possono essere omessi, ma nessun nuovo metodo public può essere aggiunto, per ovvie ragioni di compatibilità Le classi definite dal CLDC e i suoi profili stanno nel package o nei sottopackage di javax.microedition, per identificare facilmente le specifiche classi del CLDC Supporto minimo per internazionalizzazioni: il CLDC fornisce un supporto di base per convertire le codifiche dei caratteri da/per Unicode. Tuttavia, non ha capacità di “localizzazione”, per la visualizzazione di data, ora, valuta, ecc. 13 Connected Device Configuration Per dispositivi “things that you plug into a wall”, cioè collegati in rete, possibilmente always on, ad alta banda e con buona potenza di calcolo e memoria I dispositivi CDC usano un’architettura a 32-bit, Hanno almeno 2MB di memoria disponibile Implementano la JVM di J2SE con tutte le sue funzionalità, incluso il debugging a basso livello e le interfacce native, o meglio, una nuova virtual machine chiamata Compact VM, sviluppata appositamente Dispositivi CDC: Box TV digitali Apparecchi per la domotica Sistemi di navigazione Terminali del pagamento fai-da-te ... 14 Struttura a livelli dell’Architettura J2ME Livello Configurazione: La JVM interagisce con il sistema operativo Lo strato configurazione gestisce le interazioni tra il profilo e la JVM 15 Struttura a livelli dell’Architettura J2ME Livello Profilo: Insieme minimo di APIs 16 Struttura a livelli dell’Architettura J2ME Livello MIDP: APIs per le connessioni di rete, memorizzazione e interfaccia utente Interazione con l’utente tramite la visualizzazione di comandi, sostanzialmente di tre tipi: Richiesta di elaborazione Richiesta di connessione alla rete Visualizzazione di un’altra schermata 17 Struttura a livelli dell’Architettura J2ME Applicazioni e classi “original equipment manufacturer” (OEM): Le classi sono usate da MIDP per usi specifici del dispositivo (spedire/ricevere un messaggio), o accedere a dati Le applicazioni sono programmi forniti dal produttore, come un address book 18 Le applicazioni per MIDP Sono dette MIDlet e devo essere realizzate per funzionare su qualsiasi dispositivo senza alcuna modifica Ciò è particolarmente difficile soprattutto per le interfacce utente I dispositivi hanno schermi di varie dimensioni, a toni di grigio ed a colori Inoltre i dispositivi di input sono molteplici: tastiere numeriche ed alfa-numeriche, soft key, mini joystick ed anche touch screen 19 Applicazioni multi-device Data la grande varietà di dispositivi, ci sono due modi per creare applicazioni multi-device astrazione: specificare una UI astratta, relegando alla MIDP di crearla in concreto (ad esempio invece di dire “visualizza la parola 'Avanti' sullo schermo sopra il soft key”, si dice “dammi il comando 'Avanti' da qualche parte in questa UI” scoperta: l'applicazione “scopre” le caratteristiche del dispositivo a run-time e adatta la UI “al volo” (per esempio si scoprono le dimensioni dello schermo e si scala l'applicazione) 20 Applicazioni multi-device (2) L'API MIDP supporta entrambi i sistemi l'astrazione è il metodo preferito poiché permette di scrivere meno codice e delega tutto alla MIDP in alcuni casi (ad esempio i videogame) è invece necessario un approccio di tipo “scoperta” per conoscere con certezza le caratteristiche del dispositivo ed adattare il comportamento in modo adeguato L'API MIDP è progettata in modo tale da permettere facilmente anche il mix di queste due tecniche nella stessa applicazione 21 MIDlet e MIDlet Suite (1) Comunemente, MIDlets correlate sono raggruppate in una MIDlet suite (package), e verranno considerate come un gruppo unico in fase di installazione/disinstallazione Vantaggio: i membri di una MIDlet suite condividono Le risorse dell’ambiente ospitante Le classi Java istanziate La VM Svantaggio: condividere espone ad errori causati da accessi concorrenti nella lettura/scrittura dei dati Rischio ridotto dalle primitive di sincronizzazione per l’accesso ai dati volatili e persistenti Se la MIDlet usa multi-threading, è responsabile per il coordinamento degli accessi ai dati 22 MIDlet e MIDlet Suite (2) I dati non possono essere condivisi tra MIDlets che non appartengono alla stessa MIDlet suite, perché il nome della MIDlet suite è usato per identificare i dati associati alla suite. Una MIDlet di una diversa MIDlet suite è considerata una sorgente non attendibile Una MIDlet suite è installata, eseguita e rimossa dall’Application Manager (AM) che gira sul dispositivo, fornito dal produttore. L’AM è responsabile degli accessi alle classi della JVM e CLDC da parte delle MIDlets. L’AM inoltre mette il file Java ARchive (JAR) e il file Java Application Descriptor (JAD) a disposizione dei 23 membri della MIDlet suite JAD & JAR Le MIDlet Suite sono distribuite dalla coppia di file JAD & JAR: JAD, Java Application Description: contiene tutte le informazioni che descrivono le applicazioni, i requisiti per l'installazione, le proprietà e gli eventuali parametri per l'esecuzione, permessi richiesti sulle API JAR, Java ARchive: contiene le classi dell'applicazione, le eventuali librerie di terze parti, risorse (file di testo, immagini, suoni, dati binari) necessari all'esecuzione dell'applicazione La coppia è generata automaticamente dal tool di sviluppo 24 JAR File Svolge lo stesso ruolo che ha in J2SE, con alcune differenze: deve contenere l'indispensabile per l'esecuzione dell'applicazione: il dispositivo potrebbe non essere in grado di salvare l'archivio e il costo di trasferimento potrebbe essere troppo oneroso non è possibile caricare classi e risorse da JAR file diverso da quello di avvio Specificità dei dispositivi: i terminali possono avere una limitazione sulla dimensione massima del JAR (ad esempio: 64K) alcuni terminali richiedono esplicitamente che il file JAR sia compresso 25 JAR File Tutti i file necessari per implementare una MIDlet suite devono essere contenuti nell’archivio JAR, e sono: Classi delle MIDlet Immagini grafiche (se richieste) Il file Manifesto Il Manifest file contiene una lista degli attributi e relative definizioni usate dall’AMS per installare i file contenuti nel JAR nel dispositivo Gli attributi sono nove, di cui tre opzionali; non includere i sei obbligatori nel manifest file induce l’AM a interrompere l’installazione del JAR file. Il manifest file è un semplice documento di testo 26 Attributi del Manifest File 27 Esempio di Manifest File MIDlet-Name: Mia MIDlet MIDlet-Version: 2.0 MIDlet-Vendor: MiaSocietà MIDlet-1: MiaMIDlet, /images/MiaMIDlet.png, Mia.MiaMIDlet MicroEdition-Profile: MIDP-2.0 MicroEdition-Configuration: CLDC-1.0 L’ordine di comparsa degli attributi non è importante Ogni coppia deve terminare con un ritorno carrello 28 JAD File Contiene le informazioni sull'applicazione, mostrate all'utente prima che si proceda con il download e l'installazione del software Il JAD file fornisce all’application manager maggiori informazioni sul contenuto del JAR file, per decidere se la MIDlet suite può essere implementata sul dispositivo (configurazione, profilo...) e se il bytecode proviene da un dominio autorizzato ad utilizzare certe funzionalità Può essere un modo per passare parametri a una MIDlet senza modificare il JAR file (il web service, ad esempio, potrebbe inserire dinamicamente delle informazioni nel JAD) Il JAD file è simile al manifest file come coppie attributovalore Cinque attributi sono obbligatori: MIDlet-Name, MIDletVersion, MIDlet-Vendor, MIDlet-n e MIDlet-Jar-URL 29 Attributi del JAD File 30 Esempio file JAD MIDlet-Version: 1.0.2 MIDlet-Vendor: Francesca Martelli MIDlet-Jar-URL: http://www.di.unipi.it/~fmartel/labjavame.jar MicroEdition-Configuration: CLDC-1.1 MicroEdition-Profile: MIDP-2.0 MIDlet-1: Demo1, /image/img1.png , it.unipi.di.fmartel.labjavame.HelloWorld MIDlet-Jar-Size: 10819 MIDlet-Name: HelloWorld Attenzione! i valori degli attributi MIDlet-Name, MIDlet-Version e MIDlet-Vendor nel JAD file devono essere identici a quelli nel manifest. Se così non è, il JAR file non viene installato l'indicazione della dimensione del file JAR deve essere esatta, altrimenti alcuni dispositivi non caricano l'archivio E' consigliabile che l'URL del JAR sia assoluto 31 Rilascio delle MIDlet suite Il rilascio dell'applicazione per l'installazione su dispositivo può avvenire in tre modalità principali: Over-The-Air: l'applicazione è resa disponibile su un server WAP o WEB pubblico, attraverso il quale il terminale J2ME può scaricarla e procedere con l'installazione PC-based: si procede all'installazione attraverso software dedicato fornito dal produttore del dispositivo OBEX: il terminale J2ME riceve il file jar attraverso trasferimento OBEX (Push o FTP a seconda delle funzionalità del terminale e del PC di appoggio) e provvedere all'installazione in maniera autonoma 32 Processo di sviluppo di un MIDlet 33 MIDlet Scrivere una MIDlet è simile a creare un’applicazione J2SE (applet), solo che è meno “robusta” Il nome deve essere conforme alla convenzione di nominazione delle classi Java Deve estendere la classe javax.microedition.midlet.MIDlet È un’interfaccia tra i comandi dell’applicazione e l’ambiente run-time, controllato dall’application manager 34 Struttura della MIDlet L’AM gestisce il ciclo di vita della MIDlet chiamando i metodi startApp(), pauseApp(), and destroyApp(), dichiarati abstract nella classe MIDlet: startApp(): comandi per l’inizio dell’esecuzione pauseApp(): comandi per la sospensione dell’applicazione; per ripartire si richiama il metodo startApp destroyApp(): comandi per la terminazione I metodi startApp() e pauseApp() sono public e non hanno né valore di ritorno, né parametri Il metodo destroyApp() è pubblico e non ritorna valore, ma ha un parametro booleano settato a true se la terminazione della MIDlet è incondizionata, e false se la MIDlet può lanciare una MIDletStateChangeException, per dire all’AM che non vuole essere distrutta in quel momento 35 Ciclo di vita di una MIDlet 36 MIDlet skeleton import javax.microedition.midlet.*; public class MyMIDlet extends MIDlet { //costruttore public MyMIDlet() { } //metodi base: public void startApp() { } public void pauseApp() { } public void destroyApp(boolean unconditional) { } } 37 Inizializzazione e avvio Una MIDlet è un’applicazione event-based. L'inizializzazione della MIDlet deve avvenire nel costruttore: Tutte le routine eseguite nella MIDlet sono invocate in risposta a un evento riportato dall’AM. L’evento iniziale occorre quando la MIDlet è lanciata e l’AM invoca il metodo startApp() creazione dell'interfaccia grafica allocazione delle strutture dati principali lettura parametri di piattaforma Il metodo startApp() può essere invocato più volte: esso, dunque, non inizializza alcun oggetto ma si occupa di: visualizzare l'interfaccia grafica: tipicamente schermata di dati e invito all’utente a scegliere fra una o più opzioni avviare eventuali Thread 38 Sospensione Il metodo pauseApp() è invocato al sopraggiungere di una chiamata o altro evento per il quale è richiesto di sospendere l'applicazione Sospendere non significa andare in background! L'applicazione deve congelare il proprio stato (così da riprendere l'esecuzione alla successiva invocazione di startApp()), fermare i thread e chiudere eventuali connessioni di rete. Per sicurezza meglio salvare qualche dato sulla flash del dispositivo! :-( 39 Interazione con l'Application Manager L'applicazione notifica all'Application Manager eventuali variazioni nel suo stato, attraverso i metodi definiti nella classe MIDlet: notifyPaused(): l'applicazione ha rilasciato le risorse ed è in stand-by resumeRequest(): l'applicazione chiede all'Application Manager di essere riavviata 40 Chiusura di una applicazione Il ciclo di vita di una MIDlet è gestito dall'Application Manager: per questo motivo, l'applicazione non conclude la sua esecuzione con il classico System.exit(EXIT_CODE) bensì notificando all'Application Manager che tutte le risorse sono state deallocate e l'applicazione è pronta per essere terminata: notifyDestroyed() 41 J2ME Software Development Kits Gratis: Sun Java Wireless Toolkit (http://java.sun.com/javame/downloads/index.jsp) Third-party: Borland JBuilder Mobile Set, Sun One Studio 4 (ex Forte for Java) WebGain VisualCafe Enterprise Suite. Bisogna scaricare 3 software da java.sun.com: Java Development Kit (1.3 o successivo) http://java.sun.com/j2se/downloads.html Connected Limited Device Configuration (CLDC) http://java.sun.com/products/cldc/ Mobile Information Device Profile (MIDP) http://java.sun.com/products/midp/ Gli ultimi due software sono già inclusi nel WTK 42 Creare un MIDlet con J2ME Wireless Toolkit Aprire la Ktoolbar Cliccare su New Project e specificare: Nome del progetto Nome del MIDlet iniziale Nella schermata successiva, specificare le metainformazioni sul JAR file: Da notare il tab MIDlets per aggiungere ulteriori MIDlet nello stesso JAR 43 Creazione del progetto (2) Nella cartella apps, apriamo la cartella HelloWorldProject bin: contiene il file JAR e il relativo descrittore res: cartella generica di risorse, tipo le immagini src: cartella di lavoro project.properties è il descrittore Alla prima compilazione verrà creata la cartella classes 44 Contenitori Il contenitore principale è il Display Manager implementato nella classe javax.microedition.lcdui.Display Ad un Display è associato un oggetto Displayable che è un contenitore di oggetti grafici 45 HelloWorld.java import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class HelloWorld extends MIDlet{ Display display; Form form; public void startApp(){ //ottengo il display display=Display.getDisplay(this); //creo il contenitore form=new Form("Hello World Program"); //creo il componente StringItem sItem=new StringItem(null,"Hello World!"); //aggiungo il componente al contenitore form.append(sItem); //imposto come displayable corrente display.setCurrent(form); } public void pauseApp(){} public void destroyApp(boolean unconditional){ notifyDestroyed(); } 46 } Lanciamo il nostro primo progetto! Torniamo su Ktoolbar e clicchiamo su Build Se non ci sono errori, clicchiamo su Run che caricherà l'applicazione sull'emulatore selezionato La prima schermata sull'emulatore, è la lista delle MIDlet presenti nel progetto Selezionando la MIDlet e premendo il tasto Launch vediamo l'esecuzione vera e propria della MIDlet HelloWorld 47 Qualche consiglio pratico Sviluppare applicazioni per piccoli dispositivi è una bella sfida: bisogna “rivedere” l’approccio, con qualche accorgimento per fronteggiare il problema delle risorse Differenze tra i dispositivi tradizionali e piccoli: Alimentazione: i primi sono continuamente alimentati, i secondi si affidano a batterie Connessione di rete: i dispositivi mobili sono connessi via radio o infrarossi, la qualità varia con la distanza dal ricevitore e la potenza del segnale generato dal dispositivo Inconsistenza nella connessione di rete, tipicamente richiede all’utente di sincronizzare spesso dati e applicazioni con un computer o un server Programmi e dati sono memorizzati nella memoria del dispositivo e vengono persi se cade l’alimentazione, quindi devono essere ricaricati nel dispositivo: dati memorizzati 48 offline, piuttosto che sulla memoria primaria del dispositivo Qualche consiglio pratico (2) Mantenere l’applicazione semplice: Pianificare l’applicazione dividendola in oggetti con dati e metodi associati Pianificare l’applicazione dividendola in piccoli pezzi Limitare l’applicazione alle minime funzionalità richieste, mettendo ogni componente funzionale in una MIDlet (se possibile), e impacchettare le varie MIDlet nella stessa MIDlet suite. Questo facilita l’AM del dispositivo nel gestire meglio le MIDlets e le risorse che usano Mantenere l’applicazione piccola La dimensione di un’applicazione J2ME è un punto critico per svilupparla efficientemente. Rimuovere tutte le componenti non necessarie (tipo i suoni) 49 Qualche consiglio pratico (3) Limitare l’uso della memoria Gestione globale della memoria: riduce la memoria totale necessaria all’applicazione Per ridurre il fabbisogno evitare di usare i tipi oggetto; meglio i tipi scalari. In ogni caso, usare sempre il tipo di dato minimo per memorizzare un certo dato (per i flag, meglio i boolean che gli int...) Gestione della memoria in un picco temporale: minimizzare la quantità di memoria usata negli istanti di maggior uso del dispositivo. Dipende dal garbage collector, per facilitarlo: Allocare un oggetto subito prima di usarlo Settare tutte le referenze agli oggetti a null quando non servono più all’applicazione Riusare gli oggetti piuttosto che crearne di nuovi Ridurre la probabilità di eccezione, rilasciando tutte le risorse 50 subito dopo il loro uso Qualche consiglio pratico (4) Computazioni pesanti sui Server L’applicazione deve fare il minimo calcolo possibile, ma se è necessaria una computazione pesante l’alternativa è costruire l’applicazione di tipo client-server: il calcolo pesante lo fa il server che poi invia i risultati al client web-services: tre livelli Livello client (presentazione): è dove l’utente interagisce facendo la richiesta Livello della logica del servizio: è dove viene chiamato il software appropriato Livello del processamento Esempio: corriere insicuro di un indirizzo, interroga il database della sua azienda 51 Qualche consiglio pratico (5) Gestire l’uso della connessione alla rete Fare trasmissioni brevi, trasferendo il minimo indispensabile per completare un compito Considerare l’uso della tecnologia store-forwarding e un server-side agent che gira su un server che raccoglie la richiesta dal dispositivo mobile, va a prendere l’informazione da una data sorgente, la tiene memorizzata finché il dispositivo mobile non ne fa richiesta, e quindi viene forwardata Es: e-mail, invece di scaricare i messaggi, visualizzare prima i campi “Da”, “Oggetto”,... per poi decidere quale leggere, quale cancellare Esempio: corriere che non sa la strada per raggiungere un indirizzo, e vuole interrogare il sistema di tracking Prevedere sempre un meccanismo per ripristinare una connessione caduta Per esempio, tenere a disposizione le informazioni chiave sulla richiesta, in modo da ritrasmetterle automaticamente 52 Qualche consiglio pratico (6) Fare un’interfaccia utente semplice Grande varietà di forme e configurazioni hardware fra i piccoli dispositivi, impossibile fare un’interfaccia standard per tutti. Nel realizzare la propria user interface: Dove possibile, sfruttare l’interfaccia utente fornita dal dispositivo, piuttosto che disegnarla ex-novo Se creata, considerare i meccanismi di input disponibili (icone vs testo) Controllare le disponibilità dei caratteri della tastiera Limitare la quantità di input da parte dell’utente, in modo da semplificare la selezione dal menu (regola del pollice) Non concatenare le stringhe (al limite usare StringBuffer) Evitare il più possibile le sincronizzazioni 53