1. ITIS Max Planck di Lancenigo diVillorba (TV)
A.S. 2013-2014
Prof. PAOLOTOSATO
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
Programmazionemobile: ANDROID
Quarta lezione: file system, parsing file XML e networking
2. 09/07/2016 2
• Accesso al file system
• Storage interno
• Storage esterno
• Parse XML data
• XML
• ParserXML
• Networking
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
Indice
3. 09/07/2016 3
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 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.
4. Accesso al file system
09/07/2016 4
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 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.
protectedvoidonCreate(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());
}
5. 09/07/2016 5
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
Accesso al file system
Storage esterno
• Prima cosa da fare: controllare se disponibile!
publicstaticStringgetExternalStorageState(),metododi android.os.Environment
• Environment.MEDIA_MOUNTED disponibile in lettura e scrittura
• Environment.MEDIA_MOUNTED_READ_ONLYdisponibile solo in lettura
• Environment.XXX …
• Per ottenere la radice dello storage esterno
publicstatic FilegetExternalStorageDirectory(),metododi android.os.Environment
• Sisconsiglia 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.).
6. 09/07/2016 6
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 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)
7. 09/07/2016 7
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
Parse XML data
XML
Metalinguaggioper la rappresentazione dei dati a struttura gerarchica in forma di testo.
Consente di definire in modo semplice nuovi linguaggidi markup da usare in ambito web.
<?xmlversion="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>
8. 09/07/2016 8
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
Parse XML data
XML
Un documento XML è:
• undocumento di testo
• “humanreadable”
• contiene tag (di apertura e chiusura) che possono avere attributi e dati al loro interno
• case sensitive
• deve essere ben formattato, cioè avere:
• unprologo:<?xml version="1.0" encoding="UTF-8"?>
• ununico elemento radice: <products>
• tutti i tag devono essere bilanciati (corretto annidamento)
Seil documento XML non contiene errori si dice Well Formed (ben formato).
Seil documento è well formed e in più rispetta i requisiti strutturali definiti nel file DTD
(DocumentType Definition ) o schema XMLassociato viene chiamato Valid (valido)
9. 09/07/2016 9
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
Parse XML data
ParserXML
DOM (DocumentObject Model): è un'interfacciadi programmazione per la
manipolazionedi fileXML. 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
• Consumamolta memoria
• Permette di fare il parse e creare un fileXML
• Effettuareil parse di tutto il documento
10. 09/07/2016 10
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
Parse XML data
ParserXML
SAX (SimpleAPI forXML): è un'interfacciadi programmazione che permette di leggere e
modificarei documenti XML.SAX è event based, al contrario di DOM, e reagisce agli
eventi di parsing facendo rapporto all'applicazione.È compito del programmatore
implementarei metodi per reagire agli eventi di parsing ().
• Consumamolta meno memoria del DOM (ottimo per grandi documenti)
• Non può creare file XML,ma solo effettuare il parse
• Effettuareil parse di tutto il documento
PULL: simile a SAX, ma più semplice da implementare e più performante.
• Sipuò effettuare il parse solo di un nodo specifico (“pull only a particular node”)
• Consigliatoper piccoli documenti.
11. 09/07/2016 11
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
Parse XML data
XmlPullParser: esempio
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(new StringReader("<saluto>HelloWorld!</saluto>" ));
/*
* Restituisce lo stato corrente del parser
* Inizialmente 0 (START_DOCUMENT)
* Alla fine 1 (END_DOCUMENT)
*/
int eventType = xpp.getEventType();
12. Parse XML data
09/07/2016 12
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
XmlPullParser: esempio
while (eventType !=XmlPullParser.END_DOCUMENT){
if(eventType ==XmlPullParser.START_DOCUMENT){
Log.i("MYAPP","Startdocument");
} else if(eventType == XmlPullParser.START_TAG){ // 2
Log.i("MYAPP","Starttag:" + 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 |IOExceptione) {
Log.e("MYAPP","ParserException");
}
13. Parse XML data
09/07/2016 13
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
XmlPullParser: esempio
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xpp = factory.newPullParser();
Factory Design pattern
• Disaccoppiarele modalità di creazione degli oggetti dal loro utilizzo.
• Factory incapsula la logica di costruzione (connessioni EJB, DB, ecc): cambiamenti
nellacostruzione della classe comportano modifiche alla sola classe Factory.
• Lacreazione di un oggetto richiede l'accesso ad informazioni o risorse che non
dovrebbero essere contenute nella classe di composizione.
• Lagestione del ciclo di vita degli oggetti deve essere centralizzata in modo da
assicurareun comportamento consistente all'interno dell'applicazione.
14. Parse XML data
09/07/2016 14
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
XmlPullParser
• Ese 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);
15. Parse XML data
09/07/2016 15
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
XmlPullParser
• Ese 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;
16. Parse XML data
09/07/2016 16
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 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;
17. Parse XML data
09/07/2016 17
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 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
18. Parse XML data
09/07/2016 18
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
/*
* Stampa l’array list su LogCat
*/
StringBuffercontent = 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());
}
19. Net
09/07/2016 19
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 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
(UIThread).
• 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...)
20. 09/07/2016 20
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 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> { ... }
21. Net
09/07/2016 21
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
AsyncTask: 4 fasi
• onPreExecute(),invocato sul thread dell'interfaccia grafica prima che il task venga eseguito.
Questafase viene normalmente utilizzata per il setup del task, per esempio per mostrare una
progress bar nell'interfaccia utente.
• doInBackground(Params...),invocatoquando 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...) perpubblicaredelle unità di progressione. Questi
valorisono pubblicati nell'interfaccia utente tramite onProgressUpdate(Progress...).
• onProgressUpdate(Progress...),invocatoda publishProgress(Progress...).Questometodo è
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
diquesta elaborazione è passato al metodo come parametro.
22. Net
09/07/2016 22
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
Permessi
Settare l’app in modo che possa connettersi ad Internet
AndroidManifest Permission ADD Uses Permission android.permission.INTERNET
<uses-permissionandroid: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>
24. 09/07/2016 24
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
Net
protectedvoid onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btDownload = (Button) findViewById(R.id.btConnect);
btDownload.setOnClickListener(this);
}
publicvoid onClick(View v) {
TextView txtNumRec = (TextView) findViewById(R.id.txtNumRec);
txtNumRec.setText("0");
AsyncDownload downloader = new AsyncDownload(); // Chiamo il Thread
downloader.execute();
}
publicvoid printResult(intnumRecord) {
TextView txtNumRec = (TextView) findViewById(R.id.txtNumRec);
txtNumRec.setText(String.valueOf(numRecord));
}
25. Net
09/07/2016 25
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
privateclass AsyncDownload extends AsyncTask<Object, String,Integer> { // Inner classper fare il download in background
protected IntegerdoInBackground(Object... params) {
XmlPullParser datiRicevuti =downloadXmlData();
int numRecords=parsingXmlData(datiRicevuti);
return numRecords;
}
privateXmlPullParser downloadXmlData() {
Log.i(TAG,"Download avviato ...");
try {
URL xmlUrl = newURL(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;
}
26. Net
09/07/2016 26
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
privateint 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;
}
27. Net
09/07/2016 27
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
protected void onProgressUpdate(String... values){
super.onProgressUpdate(values);
if (values.length == 1) {
printResult(Integer.parseInt(values[0]));
}
}
}
}
28. 09/07/2016 28
Quest' opera è distribuitacon
licenzaCreative Commons Attribuzione - Non commerciale - Condividi allo stessomodo 3.0 Unported.
The end!