programmazione mobile: android

28

Click here to load reader

Upload: paolo-tosato

Post on 11-Apr-2017

69 views

Category:

Education


0 download

TRANSCRIPT

Page 1: Programmazione mobile: ANDROID

ITIS Max Planck di Lancenigo di Villorba (TV) A.S. 2013-2014

Prof. PAOLO TOSATO

Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

Programmazione mobile: ANDROID Quarta lezione: file system, parsing file XML e networking

Page 2: Programmazione mobile: ANDROID

09/07/2016 2

• Accesso al file system

• Storage interno • Storage esterno

• Parse XML data • XML • Parser XML

• Networking

Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

Indice

Page 3: Programmazione mobile: ANDROID

09/07/2016 3 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

Accesso al file system

Storage interno

• Porzione di file system esclusivamente assegnata all’applicazione: altri pacchetti installati nel dispositivo non possono farvi accesso.

Storage esterno

• Solitamente una scheda che può all’occorrenza essere rimossa e sostituita, ma non è detto.

Page 4: Programmazione mobile: ANDROID

Accesso al file system

09/07/2016 4 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

Storage interno Per scoprire quale sia la directory radice dello spazio riservato ad un’applicazione: getFilesDir(), che restituisce un java.io.File. Metodo di android.content.Context, classe da cui derivano Activity e gli altri mattoni fondamentali di Android. protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.mylayout); /* Dov'è lo storage interno dell'applicazione? (In Eclipse: DDMS File Explorer) /data/data/<package applicazione>/files */ Log.i("FileDemo", "Directory: " + getFilesDir().getAbsolutePath()); }

Page 5: Programmazione mobile: ANDROID

09/07/2016 5 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

Accesso al file system

Storage esterno • Prima cosa da fare: controllare se disponibile! public static String getExternalStorageState(), metodo di android.os.Environment

• Environment.MEDIA_MOUNTED disponibile in lettura e scrittura • Environment.MEDIA_MOUNTED_READ_ONLY disponibile solo in lettura • Environment.XXX …

• Per ottenere la radice dello storage esterno public static File getExternalStorageDirectory(), metodo di android.os.Environment

• Si sconsiglia di creare file direttamente nella radice dello storage. Android infatti organizza il suo storage esterno con una serie di directory standard (Music per la musica, Download per i file scaricati, ecc.).

Page 6: Programmazione mobile: ANDROID

09/07/2016 6 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

Parse XML data

XML Oggigiorno difficilmente un’applicazione lavora in modo isolato e possiede tutti i dati che deve elaborare. Problema: raramente si deve interagire con applicazioni che possiedono la stessa tecnologia. Soluzione: scambiare informazioni attraverso un formato aperto come Extensible Markup language (XML)

Page 7: Programmazione mobile: ANDROID

09/07/2016 7 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

Parse XML data

XML

Metalinguaggio per la rappresentazione dei dati a struttura gerarchica in forma di testo. Consente di definire in modo semplice nuovi linguaggi di markup da usare in ambito web.

<?xml version="1.0" encoding="UTF-8"?> <products> <product> <productname>Pantaloni</productname> <productcolor>nero</productcolor> <productquantity>5</productquantity> </product> <product> <productname>T-Shirt</productname> <productcolor>blu</productcolor> <productquantity>3</productquantity> </product> </products>

Page 8: Programmazione mobile: ANDROID

09/07/2016 8 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

Parse XML data

XML

Un documento XML è: • un documento di testo • “human readable” • contiene tag (di apertura e chiusura) che possono avere attributi e dati al loro interno • case sensitive • deve essere ben formattato, cioè avere:

• un prologo: <?xml version="1.0" encoding="UTF-8"?> • un unico elemento radice: <products> • tutti i tag devono essere bilanciati (corretto annidamento)

Se il documento XML non contiene errori si dice Well Formed (ben formato). Se il documento è well formed e in più rispetta i requisiti strutturali definiti nel file DTD (Document Type Definition ) o schema XML associato viene chiamato Valid (valido)

Page 9: Programmazione mobile: ANDROID

09/07/2016 9 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

Parse XML data

Parser XML

DOM (Document Object Model): è un'interfaccia di programmazione per la manipolazione di file XML. DOM, partendo dal file XML, costruisce un albero dove ogni nodo dell'albero corrisponde ad un elemento del file; per questo motivo è detto tree based o object based

• Consuma molta memoria

• Permette di fare il parse e creare un file XML

• Effettuare il parse di tutto il documento

Page 10: Programmazione mobile: ANDROID

09/07/2016 10 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

Parse XML data

Parser XML

SAX (Simple API for XML): è un'interfaccia di programmazione che permette di leggere e modificare i documenti XML. SAX è event based, al contrario di DOM, e reagisce agli eventi di parsing facendo rapporto all'applicazione. È compito del programmatore implementare i metodi per reagire agli eventi di parsing ().

• Consuma molta meno memoria del DOM (ottimo per grandi documenti) • Non può creare file XML, ma solo effettuare il parse • Effettuare il parse di tutto il documento

PULL: simile a SAX, ma più semplice da implementare e più performante.

• Si può effettuare il parse solo di un nodo specifico (“pull only a particular node”) • Consigliato per piccoli documenti.

Page 11: Programmazione mobile: ANDROID

09/07/2016 11 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

Parse XML data

XmlPullParser: esempio try { XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser xpp = factory.newPullParser(); xpp.setInput(new StringReader( "<saluto>Hello World!</saluto>" )); /* * Restituisce lo stato corrente del parser * Inizialmente 0 (START_DOCUMENT) * Alla fine 1 (END_DOCUMENT) */ int eventType = xpp.getEventType();

Page 12: Programmazione mobile: ANDROID

Parse XML data

09/07/2016 12 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

XmlPullParser: esempio while (eventType != XmlPullParser.END_DOCUMENT) { if(eventType == XmlPullParser.START_DOCUMENT) { Log.i("MYAPP", "Start document"); } else if(eventType == XmlPullParser.START_TAG) { // 2 Log.i("MYAPP", "Start tag: " + xpp.getName()); } else if(eventType == XmlPullParser.END_TAG) { // 3 Log.i("MYAPP", "End tag: " + xpp.getName()); } else if(eventType == XmlPullParser.TEXT) { // 4 Log.i("MYAPP", "Testo: " + xpp.getText()); } eventType = xpp.next(); } Log.i("MYAPP", "End document"); } catch(XmlPullParserException | IOException e) { Log.e("MYAPP", "Parser Exception"); }

Page 13: Programmazione mobile: ANDROID

Parse XML data

09/07/2016 13 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

XmlPullParser: esempio XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser xpp = factory.newPullParser(); Factory Design pattern

• Disaccoppiare le modalità di creazione degli oggetti dal loro utilizzo.

• Factory incapsula la logica di costruzione (connessioni EJB, DB, ecc): cambiamenti nella costruzione della classe comportano modifiche alla sola classe Factory.

• La creazione di un oggetto richiede l'accesso ad informazioni o risorse che non dovrebbero essere contenute nella classe di composizione.

• La gestione del ciclo di vita degli oggetti deve essere centralizzata in modo da assicurare un comportamento consistente all'interno dell'applicazione.

Page 14: Programmazione mobile: ANDROID

Parse XML data

09/07/2016 14 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

XmlPullParser

• E se volessimo accedere a una risorsa presente nel file system?

/* * getAssets() restituisce un AssetManager, che permette di accedere * alle risorse della directory assets (non hanno un riferimento in R) */ InputStream file = getApplicationContext().getAssets().open("data.xml"); xpp.setInput(file, null);

Page 15: Programmazione mobile: ANDROID

Parse XML data

09/07/2016 15 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

XmlPullParser

• E se volessimo memorizzare le informazione in un oggetto ad hoc? ArrayList<Prodotto> prodotti = null; Prodotto currentProduct = null; int eventType = xpp.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) { String name = null; switch (eventType) { case XmlPullParser.START_DOCUMENT: prodotti = new ArrayList<Prodotto>(); break;

Page 16: Programmazione mobile: ANDROID

Parse XML data

09/07/2016 16 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

case XmlPullParser.START_TAG: name = xpp.getName(); if (name.equals("product")) { currentProduct = new Prodotto(); } else if (currentProduct != null) { if (name.equals("productname")) { currentProduct.setNome(xpp.nextText()); } else if (name.equals("productcolor")) { currentProduct.setColore(xpp.nextText()); } else if (name.equals("productquantity")) { currentProduct.setQuantita(Integer.parseInt(xpp.nextText())); } } break;

Page 17: Programmazione mobile: ANDROID

Parse XML data

09/07/2016 17 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

case XmlPullParser.END_TAG: name = xpp.getName(); if (name.equals("product") && currentProduct != null){ prodotti.add(currentProduct); } } // chiude lo switch eventType = xpp.next(); } // chiude il ciclo while

Page 18: Programmazione mobile: ANDROID

Parse XML data

09/07/2016 18 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

/* * Stampa l’array list su LogCat */ StringBuffer content = new StringBuffer(); Iterator<Prodotto> iterator = prodotti.iterator(); while(iterator.hasNext()) { Prodotto prodotto = iterator.next(); content.append("Nome: " + prodotto.getNome() + " "); content.append("Colore: " + prodotto.getColore() + " "); content.append("Quantita': " + prodotto.getQuantita()); Log.i("MYAPP", content.toString()); content.delete(0, content.length()); }

Page 19: Programmazione mobile: ANDROID

Net

09/07/2016 19 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

AsyncTask

• Questa classe consente di eseguire operazioni in background e di pubblicarne in modo semplice i risultati nel Thread dell'interfaccia grafica (UI Thread).

• Dovrebbe essere utilizzato per operazioni di breve durata (pochi secondi al massimo).

• E' definito da 3 tipi generici: Params, Progress e Result e da 4 fasi: OnPreExecute, doInBackground, onProgressUpdate e OnPostExecute.

• Per essere implementato è necessario estendere la classe AsyncTask e sovrascrivere il metodo doInBackground(Params...)

Page 20: Programmazione mobile: ANDROID

09/07/2016 20 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

Net

AsyncTask: tipi generici • Params, il tipo dei parametri inviati al task al momento dell'esecuzione.

• Progress, il tipo delle progress unit pubblicate durante le operazioni in background.

• Result, il tipo di risultato dell'elaborazione in background.

Non tutti i tipi devono essere utilizzati da un task asincrono. Per indicare che un tipo non è utilizzato si utilizza Void: private class MyTask extends AsyncTask<Void, Void, Void> { ... }

Page 21: Programmazione mobile: ANDROID

Net

09/07/2016 21 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

AsyncTask: 4 fasi

• onPreExecute(), invocato sul thread dell'interfaccia grafica prima che il task venga eseguito. Questa fase viene normalmente utilizzata per il setup del task, per esempio per mostrare una progress bar nell'interfaccia utente.

• doInBackground(Params...), invocato quando termina onPreExcecute() e serve per avviare il task asincrono. Il risultato dell'elaborazione deve essere restituito a questo metodo. Questa fase può utilizzare publishProgress(Progress...) per pubblicare delle unità di progressione. Questi valori sono pubblicati nell'interfaccia utente tramite onProgressUpdate(Progress...).

• onProgressUpdate(Progress...), invocato da publishProgress(Progress...). Questo metodo è utilizzato per visualizzare qualsiasi forma di progresso nell'interfaccia utente mentre il task è in esecuzione in background. Per esempio, può essere utilizzato per animare una progress bar.

• onPostExecute(Result), invocato dopo che l'elaborazione in backgroud è terminata. Il risultato di questa elaborazione è passato al metodo come parametro.

Page 22: Programmazione mobile: ANDROID

Net

09/07/2016 22 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

Permessi

Settare l’app in modo che possa connettersi ad Internet AndroidManifest Permission ADD Uses Permission android.permission.INTERNET

<uses-permission android:name="android.permission.INTERNET"/>

<application <activity android:name="esempi.android.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>

Page 23: Programmazione mobile: ANDROID

Net

09/07/2016 23 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

private static final String TAG = "MYAPP"; // Parametri della richiesta HTTP private static final String VERB = "ListRecords"; private static final String METADATA_PREFIX = "oai_lom"; // QUERY URL private static final String SERVER_URL = "http://cird.unive.it/"; private static final String QUERY_FILE = "oai/request"; private static final String QUERY_OPTIONS = "?verb=" + VERB + "&metadataPrefix=" + METADATA_PREFIX; private static final String QUERY_URL = SERVER_URL + QUERY_FILE + QUERY_OPTIONS;

Page 24: Programmazione mobile: ANDROID

09/07/2016 24 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

Net

protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btDownload = (Button) findViewById(R.id.btConnect); btDownload.setOnClickListener(this); } public void onClick(View v) { TextView txtNumRec = (TextView) findViewById(R.id.txtNumRec); txtNumRec.setText("0"); AsyncDownload downloader = new AsyncDownload(); // Chiamo il Thread downloader.execute(); } public void printResult(int numRecord) { TextView txtNumRec = (TextView) findViewById(R.id.txtNumRec); txtNumRec.setText(String.valueOf(numRecord)); }

Page 25: Programmazione mobile: ANDROID

Net

09/07/2016 25 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

private class AsyncDownload extends AsyncTask<Object, String, Integer> { // Inner class per fare il download in background protected Integer doInBackground(Object... params) { XmlPullParser datiRicevuti = downloadXmlData(); int numRecords = parsingXmlData(datiRicevuti); return numRecords; } private XmlPullParser downloadXmlData() { Log.i(TAG, "Download avviato ..."); try { URL xmlUrl = new URL(QUERY_URL); XmlPullParser datiRicevuti = XmlPullParserFactory.newInstance().newPullParser(); datiRicevuti.setInput(xmlUrl.openStream(), null); return datiRicevuti; } catch (MalformedURLException e) { Log.e(TAG, "URL errato", e); } catch (XmlPullParserException e) { Log.e(TAG, "Factory error", e); } catch (IOException e) { Log.e(TAG, "Errore di connessione", e); } return null; }

Page 26: Programmazione mobile: ANDROID

Net

09/07/2016 26 Quest' opera è distribuita con licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Unported.

private int parsingXmlData(XmlPullParser datiRicevuti) { int numRecord = 0; if (datiRicevuti != null) { try { int eventType = datiRicevuti.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) { String nome = null; switch(eventType) { case XmlPullParser.START_TAG: nome = datiRicevuti.getName(); if (nome.equals("record")) { numRecord++; publishProgress(String.valueOf(numRecord)); // Chiama onProgressUpdate } break; } eventType = datiRicevuti.next(); } } catch (XmlPullParserException e) { Log.e(TAG, "PullParser error", e); } catch (IOException e) { Log.e(TAG, "PullParser error", e); } } return numRecord; }