Scaricare la presentazione
La presentazione è in caricamento. Aspetta per favore
1
Primi esempi di interfacce grafiche con Android
Docente: Gabriele Lombardi © CEFRIEL
2
The present original document was produced by CEFRIEL and the Teacher for the benefit and internal use of this course, and nobody else may claim any right or paternity on it. No right to use the document for any purpose other than the Intended purpose and no right to distribute, disclose, release, furnish or disseminate it or a part of it in any way or form to anyone without the prior express written consent of CEFRIEL and the Teacher. © copyright Cefriel and the Teacher-Milan-Italy-23/06/2008. All rights reserved in accordance with rule of law and international agreements. © CEFRIEL
3
Sommario MVC pattern Tutto in XML Widget e container
SLIDE CONTENUTO MVC pattern Perché preoccuparsene, come implementarlo Tutto in XML Come descrivere interfacce grafiche in XML: basi Widget e container Esempi di utilizzo di widget e container in XML Interagire con l’utente Esempi di eventi e accesso ai dati della UI Logging & Debugging Loggare per sapere, debuggare le proprie app © CEFRIEL
4
I design pattern (GRASP, GoF, altri)
Cosa sono i design pattern? Soluzioni efficaci a problemi frequenti; le trovate «preconfezionate» in libri (GoF), su forum; operano a diversi livelli (classe, collaborazione, framework, componenti). GRASP: sono più linee guida che design pattern; low copuling & high coesion sono i più importanti. GoF: dal libro «Design patterns» della gang of four; si dividono in strutturali, creazionali, comportamentali; descrivono soluzioni a livello di collaborazione. MVC (Model View Control), MVP (Model View Presenter): definiscono una architettura astratta in vengono separati: il modello dei dati su cui l’applicazione opera; la/le viste dei dati da mostrare all’utente; le operazioni da svolgere in risposta agli eventi. Non comprende la logica di business!!! © CEFRIEL
5
MVC e MVP A programmare seguendo l’istinto:
si finisce per ottenere l’anti-pattern SmartGUI; l’applicazione cresce attorno all’interfaccia grafica; alla fine non saremo più in grado di staccare le funzionalità dall’interfaccia (se non con molto sforzo). Model e logica di business: l’applicazione dovrebbe nascere sulla carta in UML; il modello concettuale (dei dati) dovrebbe guidarci; ("Model Driven Design", Evans) la logica di business dovrebbe venir realizzata PRIMA dell’interfaccia di interazione con l’utente; realizzare sia una GUI che una CLI aiuta a separare. MVC e MVP vengono dopo: sono pattern da applicare quando il core esiste già; servono per costruire l’interfaccia (grafica); © CEFRIEL
6
MVC e MVP MVC: MVP (view attiva/passiva):
Model DB Controller View Logica di business MVC: il modello rappresenta i dati, eventualmente da DB; le viste mostrano dati e strumenti di interazione; i controller interagiscono con le viste e i dati per richiamare la logica di business. MVP (view attiva/passiva): riguarda la presentazione dei dati (non l’interazione); arricchisce l’interazione tra modello e vista; il presenter manipola i dati perché possano essere presentati correttamente; Model View Presenter © CEFRIEL
7
MVC in Android DB Meglio se generata da file XML in /res/layout Model
View JavaBeans android.view.View Controller Contengono dati accessibili come property (vedi dopo) Activity © CEFRIEL
8
Un primo esempio con layout in XML
Scopo: realizzare una semplice calcolatrice che effettui i calcoli su espressioni contenenti solo interi relativi e frazioni, esprimendo il risultato come una frazione. Architettura: decidiamo di dividere in due parti il «progetto»: libreria core di calcolo (in grado di parsare una stringa, ed effettuare i calcoli); applicazione Android con una semplice interfaccia classica da calcolatrice. L’interfaccia comprenderà: un layout XML in cui vengono descritti i widget da includere nell’interfaccia; un’attività che esegue le azioni richieste dagli eventi (aggiungere caratteri, fare conti). © CEFRIEL
9
Un layout da calcolatrice
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <EditText android:text="0" android:textColor="#000000" android:maxLines="5" android:enabled="false" android:editable="false" android:layout_width="fill_parent" android:layout_height="wrap_content"/> <TableLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:stretchColumns="0,1,2,3"> <TableRow> <Button android:text="<="/> <Button android:text="C"/> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_span="2" android:text="="/> </TableRow> </TableLayout> </LinearLayout> © CEFRIEL
10
Ascoltare gli eventi @Override
public void onCreate(Bundle savedInstanceState) { // Initialization: super.onCreate(savedInstanceState); setContentView(R.layout.main); // Connecting the event listeners: ((Button)findViewById(R.id.compute)).setOnClickListener(onCompute); ((Button)findViewById(R.id.num_0)).setOnClickListener(onAddChar); … ((Button)findViewById(R.id.par_close)).setOnClickListener(onAddChar); ((Button)findViewById(R.id.canc)).setOnClickListener(onCanc); ((Button)findViewById(R.id.clear)).setOnClickListener(onClear); } Scelgo il layout XML da utilizzare in questa attività Si osservi come vengono reperiti i widget dalla vista Connetto gli eventi utilizzando dei miei listener (vedere dopo) © CEFRIEL
11
Un ascoltatore private OnClickListener onCompute = new OnClickListener() { public void onClick(View button) { try { // No errors up to now: ((EditText)findViewById(R.id.display)).setTextColor(Color.BLACK); // Obtaining the expression: CharSequence expr = ((EditText)findViewById(R.id.display)).getText(); // Computing: Fraction res = Calculator.compute(new StringBuilder(expr).toString()); // Setting the text result: ((EditText)findViewById(R.id.display)).setText(res.toString()); isInitial = true; // Done: } catch (Throwable t) { ((EditText)findViewById(R.id.display)).setTextColor(Color.RED); } }; Se non ci sono errori il testo è nero Se ci sono errori il testo è rosso © CEFRIEL
12
Per la soluzione vedere in FractionCalc2
Proviamola Provate a compilare ed installare (nell’emulatore o anche nel dispositivo reale); su emulatore provate il debuger; osservate cosa avviene sulla vista. Esercizio: provate a modificare gli attributi dei widgetper vedere che effetto hanno. aggiungete una checkbox con cui decidere se mostrare il risultato come frazione o decimale; per farlo dovete utilizzare: il widget CheckBox; OnCheckedChangeListener Per la soluzione vedere in FractionCalc2 © CEFRIEL
13
A grande successo.. nuova release!
Associare un’icona all’app: creare l’icona a risoluzioni diverse: in res/drawable 48x48 in res/drawable-ldpi 36x36 in res/drawable-hdpi 72x72 modificare AndroidManifest.xml: <application NOTA: nei nomi di risorse solo [a-z], [0-9], ‘_’ o ‘.’. Modificare versione mostrata ed effettiva (codice): <manifest … package="com.gab.tests.android.fractioncalc" android:versionCode="2" android:versionName="1.1"> 1.1 verrà mostrato (nel market), 2 è un intero incrementale © CEFRIEL
14
Ho i tasti sul telefono.. Perché non usarli?
Ogni attività può ricevere tanti eventi! Il tocco dello schermo viene usato di frequente… …ma se ci sono tasti VERI vengono usati volentieri! @Override public boolean onKeyUp(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_0: onAddChar.onClick(findViewById(R.id.num_0)); break; case KeyEvent.KEYCODE_9: onAddChar.onClick(findViewById(R.id.num_9)); break; case KeyEvent.KEYCODE_PLUS: onAddChar.onClick(findViewById(R.id.op_PLUS)); break; case KeyEvent.KEYCODE_EQUALS: onCompute.onClick(findViewById(R.id.compute)); break; case KeyEvent.KEYCODE_BACK: onCanc.onClick(findViewById(R.id.canc)); break; default: return super.onKeyUp(keyCode, event); } return true; © CEFRIEL
15
Inseriamo un’icona sul pulsante <=
Soluzione 1: su ogni widget possiamo definire la proprietà «background» con una risorsa «drawable»; <Button android:layout_width="fill_parent" android:layout_height="fill_parent" NOTA: invece che riferirci a un drawable “nostro” ci siamo riferiti a uno predefinito: @android:drawable/ic_input_delete per un elenco si vedano nell’SDK: android-sdk\platforms\android-10\data\res\drawable-ldpi android-sdk\platforms\android-10\data\res\drawable-hdpi Problemi con questa soluzione: immagine adattata alle dimensioni del pulsante (provate); noi vorremmo sovrapporre l’icona sul pulsante. © CEFRIEL
16
Inseriamo un’icona sul pulsante <=
Soluzione 2: al posto del pulsante inseriamo un layout relativo; all’interno del layout inseriamo: il pulsante (riempiendo tutto lo spazio); l’immagine (centrata ma non adattata). Ne risulta: <RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent"> <Button android:layout_width="fill_parent" android:layout_height="fill_parent"/> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true"/> </RelativeLayout> Soluzione 3: utilizzare un ImageButton (con src il drawable). © CEFRIEL
17
Ruotare il dispositivo e…
…il layout non va più bene! (nell’emulatore provare con CTRL+F12 (sinistro) Per orientazioni diverse: non serve cambiare controller; servono view differenti. Creiamo la cartella per i layout XML in versione landscape: res/layout-land Creiamoci dentro un layout alternativo per il landscape: tabella 5x4 Giochiamo con l’orientazione © CEFRIEL
18
Essendo noti sfruttiamo numero righe/colonne
Layout alternativo Altri strumenti esistono per livelli di API più alti: dalle API14 esiste il GridLayout: vedi in altriEsempi/xml/main_conGrid.xml occhio al range di dispositivi che volete supportare; L’esempio con GridLayout: <GridLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:columnCount="5" android:rowCount="4"> … <Button android:layout_rowSpan="2" android:layout_gravity="fill" android:text="="/> </GridLayout> Essendo noti sfruttiamo numero righe/colonne Usiamo rowSpan per riempire 2 righe, gravity fill per allargare il Button © CEFRIEL
19
Se sappiamo cos’è successo.. diciamolo!
Mostriamo una dialog di errore: se c’è una divisione per zero; negli altri casi (problema di sintassi); Più modi per mostrare una dialog: utilizzando l’XML per descriverne una, ed eseguendo showDialog; istanziandola ed invocando show; con DialogFragment. Il primo è deprecato (non usare); Vediamo il secondo: final AlertDialog dialog = new AlertDialog.Builder(this).create(); dialog.setButton("Chiudi", new android.content.DialogInterface.OnClickListener() { public void onClick(DialogInterface dlgInt, int button) { dialog.hide(); } }); dialog.setTitle(title); dialog.setMessage(message); dialog.show(); © CEFRIEL
20
Logging per sapere cosa succede
Come loggare: da specificare le seguenti informazioni: livello del log (verbose, debug, info, warning, error, wtf(!!!)…); CHI genera il log (classe? Package? Stringa a scelta); COSA è successo (messaggio di log). utilizzare la classe Log (metodi statici): se bastano i metodi v, d, i, w, e, wtf; println è il metodo «raw» per scrivere log; Come loggare in maniera furba: la generazione di log è fastidiosa e onerosa; centralizzandola la si può controllare! si veda la classe Logger in FractionCalc2. Il compilatore e l’ottimizzatore SANNO il fatto loro! E per leggere i log? adb logcat FractionCalc:i *:s (filtrato, livelli [v,d,i,w,e,f,s]) © CEFRIEL
21
Logging: cosa succede? © CEFRIEL
22
Debugging: step-by-step, monitor
Per poter eseguire il debug su dispositivo: abilitarlo sul dispositivo da impostazioniapplicazioni abilitarlo nell’applicazione (attributo del manifest): <application android:debuggable="true"> in NetBeans, build e debug: per l’emulatore se non abbiamo ancora provato… è l’ora di farlo! per il dispositivo fisico richiede la presenza del dispositivo, ma volte è più rapido. Un monitor con cui accedere al device: nell’sdk (dir tools, deve essere nel path) troviamo: DDMS (Dalvik Debug Monitor Service)… …proviamo a lanciarlo dalla linea di comando! © CEFRIEL
23
DDMS DDMS comunica col device tramite: DDMS permette di eseguire:
servizio demone adb-server; TCP/IP con forward su USB DDMS permette di eseguire: monitoring di ram, processi, thread, allocazione, gc, radio, gps, …; cattura di screen-shot; interazione con il FS. © CEFRIEL
24
Debug delle interfacce grafiche
Analizzare l’albero delle view: ci viene fornito lo strumento hierarchyviewer: cattura un’istantanea dello stato dell’albero; ci permette di vedere: come è strutturato l’albero delle view; per ogni nodo: posizione e dimensioni; uno sketch dell’interfaccia grafica; lo screen-shot nodo per nodo; Immagine del tutto. © CEFRIEL
25
Testing Lo unit testing serve a testare in automatico e ripetibilmente la propria applicazione: simulare dei casi d’uso dell’applicazione (scimmia); testare una porzione di applicazione (componenti). Facciamo correre la scimmia: in modalità pseudo-random: adb shell monkey -p com.gab.tests.android.fractioncalc 1000 ammaestrandone una col pitone: comando monkeyrunner per eseguire uno script python; un esempio di seguito, ma si può fare di tutto: from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice device = MonkeyRunner.waitForConnection() package = 'com.gab.tests.android.fractioncalc' activity = package + '.FractionCalc' device.startActivity(component=package + '/' + activity) device.touch(50,200,MonkeyDevice.DOWN_AND_UP) # 1 device.touch(50,300,MonkeyDevice.DOWN_AND_UP) # 7 … Ottengo il device Avvio l’applicazione Simulazione tocco © CEFRIEL
26
Come funziona l’Android Unit Testing
Nostra applicazione in esecuzione Tools per accedere agli internals Pacchetti di test che usano gli strumenti © CEFRIEL
27
Unit Testing Creazione di un progetto di test:
utilizziamo questa volta i tool da riga di comando: dalla directory radice del progetto da testare: android create test-project -m ../../FractionCalc2 -n FractionCalc2Test -p tests viene generata una dir tests con un progetto di testing: vengono creati per noi (tra il resto): AndoridManifest.xml vediamo cosa contiene FractionCalcTest.java vediamo cosa contiene Esecuzione dei test: prima di poter eseguire con successo dei test: dobbiamo strumentare i test…; … e scrivere le unità di testing automatico. per strumentare ed eseguire i nostri test: ant/bin deve essere nel PATH © CEFRIEL
28
Preparare ed eseguire i test:
Unit Testing Preparare ed eseguire i test: dobbiamo prima strumentare l’applicazione di test: ant instrument install poi possiamo eseguire una prima prova: adb shell am instrument -w -e class com.gab.tests.android.fractioncalc.FractionCalcTest com.gab.tests.android.fractioncalc.tests/android.test.InstrumentationTestRunner NOTA: fallisce perché non ci sono unità. Unità di testing: Android testing framework estende JUnit; esistono unità di test (foglie) e suite di test (rami); è possibile definire una vera e propria foresta di test; ogni unità di test comprende più test più le fixtures. © CEFRIEL
29
Preparare le unità di test
Ci è stata preparata la classe FractionCalcTest: implementato per Android, eredita da JUnit: ActivityInstrumentationTestCase2<FractionCalc> ActivityTestCase InstrumentationTestCase TestCase si prepara per lavorare con la nostra attività main: public FractionCalcTest() { super("com.gab.tests.android.fractioncalc", FractionCalc.class); } dobbiamo aggiungere i test e ciò che ci sta attorno: Activity frac; public void setUp() { frac = getActivity(); } public void tearDown() { frac.finish(); } public void testExample() { sendKeys("1 7 SLASH 2 MINUS 2 SLASH 4 EQUALS"); CharSequence text = ((EditText)frac.findViewById(R.id.display)).getText(); assertEquals("Result of 17/2-2/4=", "8", new StringBuilder(text).toString()); } © CEFRIEL
30
L’esecuzione dei test Vanno installati ogni volta:
ant instrument install ant test … -test-project-check: test: [echo] Running tests ... [exec] [exec] com.gab.tests.android.fractioncalc.FractionCalcTest:. [exec] Test results for InstrumentationTestRunner=. [exec] Time: 3.263 [exec] OK (1 test) BUILD SUCCESSFUL Total time: 8 seconds Provate ad osservare l’emulatore durante il test!!! © CEFRIEL
31
Cosa abbiamo visto sino ad ora?
Da qui dove si va? Cosa abbiamo visto sino ad ora? Abbiamo «giocato» con una prima applicazione; abbiamo costruito una GUI e ascoltato degli eventi; abbiamo provato ad estenderla (versione 2); abbiamo scoperto come fare testing automatico e debugging della nostra applicazione (strumenti). Cosa manca? Non abbiamo formalizzato COSA una attività sia; non abbiamo esplorato l’universo dei widget; in Android non esistono mica solo le GUI!!! Continuiamo a giocare! © CEFRIEL
Presentazioni simili
© 2024 SlidePlayer.it Inc.
All rights reserved.