Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
laboratoare:laborator07 [2015/04/20 01:46] Andrei Roșu-Cojocaru |
laboratoare:laborator07 [2015/04/22 17:34] (current) Andrei Roșu-Cojocaru |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ====== Laborator 07. Comunicația prin HTTP ====== | + | ====== Laborator 07. Invocarea de Servicii Web prin Protocolul HTTP ====== |
| De multe ori, funcționalitatea pe care o pun la dispoziție aplicațiile Android este preluată din alte surse, datorită limitărilor impuse de capacitatea de procesare și memorie disponibilă ale unui dispozitiv mobil. O strategie posibilă în acest sens este utilizarea HTTP, pentru interogarea unor servicii web. | De multe ori, funcționalitatea pe care o pun la dispoziție aplicațiile Android este preluată din alte surse, datorită limitărilor impuse de capacitatea de procesare și memorie disponibilă ale unui dispozitiv mobil. O strategie posibilă în acest sens este utilizarea HTTP, pentru interogarea unor servicii web. | ||
| Line 321: | Line 321: | ||
| * utilizând un obiect de tip ''ResponseHandler'', ce furnizează conținutul resursei solicitate, transmis ca parametru al metodei ''execute()'' a clasei ''HttpClient'' (pe lângă obiectul ''HttpGet|HttpPost'') | * utilizând un obiect de tip ''ResponseHandler'', ce furnizează conținutul resursei solicitate, transmis ca parametru al metodei ''execute()'' a clasei ''HttpClient'' (pe lângă obiectul ''HttpGet|HttpPost'') | ||
| - | ===== Parsare DOM (Document Object Model) ===== | + | ===== Prelucrare DOM (Document Object Model) ===== |
| Documentele HTML au o structură arborescentă, având drept rădăcină un document al cărui copil este o ierarhie de elemente, fiecare dintre acestea fiind reprezentate de o etichetă. | Documentele HTML au o structură arborescentă, având drept rădăcină un document al cărui copil este o ierarhie de elemente, fiecare dintre acestea fiind reprezentate de o etichetă. | ||
| Line 497: | Line 497: | ||
| {{ :laboratoare:laborator07:ocwcoursesdisplayer.png?nolink&400 }} | {{ :laboratoare:laborator07:ocwcoursesdisplayer.png?nolink&400 }} | ||
| + | |||
| + | ===== Prelucrare JSON (JavaScript Object Notation) - opțional ===== | ||
| + | |||
| + | Unele servicii web folosesc [[http://en.wikipedia.org/wiki/JSON|formatul JSON]] pentru transferul de date întrucât, spre diferență de XML care implică numeroase informații suplimentare, acesta optimizează cantitatea de date implicate. De asemenea, este foarte ușor pentru un utilizator uman să prelucreze informațiile reprezentate într-un astfel de format. | ||
| + | |||
| + | Acest mecanism de reprezentare a datelor a fost utilizat inițial în JavaScript, unde acesta descria literali sau obiecte anonime, folosite o singură dată (fără posibilitatea de a fi reutilizate), informațiile fiind transmise prin intermediul unor șiruri de caractere. Ulterior, a fost preliat pe scară largă. | ||
| + | |||
| + | În principiu, informațiile reprezentate în format JSON au structura unei colecții de perechi de tip (cheie, valoare), fiecare dintre acestea fiind grupate într-o listă de obiecte ordonate. Nu se folosesc denumiri de etichete, utilizându-se doar caracterele ''"'', '','', ''{'', ''}'', ''['' și '']''. | ||
| + | |||
| + | <code json> | ||
| + | [ | ||
| + | { | ||
| + | "attribute1": "value11", | ||
| + | "attribute2": "value12", | ||
| + | ..., | ||
| + | "attributen": "value1n" | ||
| + | }, | ||
| + | { | ||
| + | "attribute1": "value21", | ||
| + | "attribute2": "value22", | ||
| + | ..., | ||
| + | "attributen": "value2n" | ||
| + | }, | ||
| + | ... | ||
| + | { | ||
| + | "attribute1": "valuem1", | ||
| + | "attribute2": "valuem2", | ||
| + | ..., | ||
| + | "attributen": "valuemn" | ||
| + | } | ||
| + | ] | ||
| + | </code> | ||
| + | |||
| + | În Android este suportat formatul JSON strict, așa cum este descris pe [[http://json.org/|]]: | ||
| + | * denumirile de atribute trebuie să se găsească între ghilimele; | ||
| + | * valorile de tip șir de caractere trebuie să se găsească între ghilimele (nu sunt permise apostroafele în acest caz). | ||
| + | |||
| + | Potrivit [[https://www.ietf.org/rfc/rfc4627.txt|RFC 4627]], tipul MIME al documentelor reprezentate în format JSON treuie să fie în mod necesar ''application/json''. | ||
| + | |||
| + | Există [[http://www.programmableweb.com/category/all/apis?data_format=21173|numeroase servicii web]] care își expun funcționalitatea prin intermediul unor documente JSON: | ||
| + | * [[https://developers.google.com/custom-search/json-api/v1/overview?csw=1|Google]]; | ||
| + | * [[https://developer.yahoo.com/|Yahoo]]; | ||
| + | * [[http://www.geonames.org/export/web-services.html|Geonames]]; | ||
| + | * [[https://dev.twitter.com/|Twitter]]; | ||
| + | * [[https://www.flickr.com/services/api/|Flickr]]. | ||
| + | |||
| + | În Android, prelucrarea documentelor reprezentate în format JSON este realizată prin intermediul clasei [[http://developer.android.com/reference/org/json/JSONObject.html|JSONObject]] care a fost integrată parțial (cu unele funcționalități lipsă), fără a se specifica clar versiunea care este utilizată. | ||
| + | |||
| + | Un document JSON poate fi construit în mai multe moduri: | ||
| + | * [[http://developer.android.com/reference/org/json/JSONObject.html#JSONObject%28%29|JSONObject()]] - construiește un obiect JSON vid, care nu conține nici o asociere (atribut, valoare); | ||
| + | * [[http://developer.android.com/reference/org/json/JSONObject.html#JSONObject%28java.util.Map%29|JSONObject(Map copyFrom)]] - contruiește un obiect JSON pe baza unor asocieri prealabile; o astfel de metodă este utilizată mai ales în situația în care se dorește să se transmită informații către un serviciu web; | ||
| + | * [[http://developer.android.com/reference/org/json/JSONObject.html#JSONObject%28java.lang.String%29|JSONObject(String json)]] - construiește un obiect JSON prin parsarea unui șir de caractere; o astfel de metodă este utilizată mai ales în situația în care sunt primite informații de la un serviciu web, care trebuie să fie prelucrate; | ||
| + | * [[http://developer.android.com/reference/org/json/JSONObject.html#JSONObject%28org.json.JSONTokener%29|JSONObject(JSONTokener readFrom)]] - construiește un obiect JSON pe baza valorii următoare disponibile în cadrul unui obiect [[http://developer.android.com/reference/org/json/JSONTokener.html|JSONTokener]]; | ||
| + | * [[http://developer.android.com/reference/org/json/JSONObject.html#JSONObject%28org.json.JSONObject,%20java.lang.String[]%29|JSONObject(JSONObject copyFrom, String[] names)]] - construiește un obiect JSON prin filtrarea asocierilor existente într-un obiect ''JSONObject'', pe baza unor denumiri de atribute existente. | ||
| + | |||
| + | De regulă, metodele care operează cu obiecte JSON pot genera excepția [[http://developer.android.com/reference/org/json/JSONException.html|JSONException]] în situația în care sunt întâlnite documente care nu sunt bine formate. | ||
| + | |||
| + | <note warning>În Android nu este implementată metoda ''JSONObject(Bean bean)'' care permite construirea unui obiect JSON pe baza unei componente Java Bean.</note> | ||
| + | |||
| + | Gestiunea obiectelor JSON se face: | ||
| + | * pentru citire, prin intermediul metodelor de tip [[http://developer.android.com/reference/org/json/JSONObject.html#get%28java.lang.String%29|get(String name)]], care furnizează un obiect generic (de tip ''Object''), aceasta fiind supraîncărcată și pentru tipurile ''boolean'', ''double'', ''int'', ''long'', ''String'', ''JSONObject'', ''JSONArray''; | ||
| + | * pentru scriere, prin intermediul metodelor de tip [[http://developer.android.com/reference/org/json/JSONObject.html#put%28java.lang.String,%20java.lang.Object%29|put(String name, Object value)]], care furnizeză un rezultat de tip ''JSONObject'', existând și implementări specifice pentru tipurile ''boolean'', ''double'', ''int'', ''long''. | ||
| + | |||
| + | Verificarea faptului că un document JSON deține un anumit atribut se face prin invocarea metodei [[http://developer.android.com/reference/org/json/JSONObject.html#has%28java.lang.String%29|has(String name)]]. Funcționalitatea inversă este furnizată de metoda [[http://developer.android.com/reference/org/json/JSONObject.html#isNull%28java.lang.String%29|isNull(String name)]], aceasta verificând și dacă valoarea asociată atributului respectiv este ''null''. | ||
| + | |||
| + | Dimensiunea unui obiect ''JSONObject'', reprezentat sub forma numărului de asocieri de tip (cheie, valoare) este furnizat de metoda [[http://developer.android.com/reference/org/json/JSONObject.html#length%28%29|length()]]. | ||
| + | |||
| + | Reprezentarea unui obiect JSON sub forma unui șir de caractere poate fi obținută prin intermediul metodelor: | ||
| + | * [[http://developer.android.com/reference/org/json/JSONObject.html#toString%28%29|toString()]] - formă compactă; | ||
| + | * [[http://developer.android.com/reference/org/json/JSONObject.html#toString%28%29|toString(int indentSpaces)]] - formă utilizată în scop de depanare. | ||
| + | |||
| + | Unele metode furnizează vectori de obiecte JSON, reprezentate de clasa [[http://developer.android.com/reference/org/json/JSONArray.html|JSONArray]], în care accesul la obiecte se face indexat, începând cu 0: | ||
| + | * [[http://developer.android.com/reference/org/json/JSONObject.html#names%28%29|names()]] - lista numelor dintr-un obiect JSON; | ||
| + | * [[http://developer.android.com/reference/org/json/JSONObject.html#toJSONArray%28org.json.JSONArray%29|toJSONArray(JSONArray names)]] - lista valorilor asociate unor atribute dintr-un vector de obiecte JSON. | ||
| + | |||
| + | ==== Exemplu ==== | ||
| + | |||
| + | Se dorește să se implementeze o aplicație Android care să afișeze informații cu privire la cutremurele care s-au produs într-un anumit areal geografic (desemnat prin coordonatele nord, sud, est, vest) pe baza rezultatelor furnizate de serviciul web [[http://api.geonames.org/earthquakesJSON|Geonames Earthquakes]]. | ||
| + | |||
| + | Detaliile care se doresc a fi vizualizate pentru fiecare cutremur în parte sunt: | ||
| + | * așezarea geografică (latitudinea și longitudinea); | ||
| + | * magnitudinea; | ||
| + | * adâncimea la care a avut loc; | ||
| + | * sursa informației; | ||
| + | * data și ora la care s-a înregistrat. | ||
| + | |||
| + | {{ :laboratoare:laborator07:earthquakelister.png?nolink&400 }} | ||
| + | |||
| + | Adresa Internet la care este disponibil rezultatul în format JSON trebuie să specifice în mod necesar informațiile cu privire la coordonatele punctelor cardinale, precum și cu privire la numele de utilizator: | ||
| + | * ''north'', ''south'', ''east'', ''west'' - valoarea coordonatelor corespunzătoare punctelor cardinale, exprimate ca numere reale, cu semn; | ||
| + | * ''username'' - denumirea utilizatorului care deține drepturi de acces asupra acestui serviciu web (în cazul de față, ''pdsd''). | ||
| + | |||
| + | **Exemplu**. O adresă Internet de la care pot fi accesate rezultate în format JSON este: [[http://api.geonames.org/earthquakesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&username=pdsd|]]. | ||
| + | |||
| + | Rezultatele sunt furnizate în următorul format: | ||
| + | |||
| + | <code json> | ||
| + | { | ||
| + | "earthquakes":[ | ||
| + | { | ||
| + | "eqid":"c0001xgp", | ||
| + | "magnitude":8.8, | ||
| + | "lng":142.369, | ||
| + | "src":"us", | ||
| + | "datetime":"2011-03-11 04:46:23", | ||
| + | "depth":24.4, | ||
| + | "lat":38.322 | ||
| + | }, | ||
| + | { | ||
| + | "eqid":"c000905e", | ||
| + | "magnitude":8.6, | ||
| + | "lng":93.0632, | ||
| + | "src":"us", | ||
| + | "datetime":"2012-04-11 06:38:37", | ||
| + | "depth":22.9, | ||
| + | "lat":2.311 | ||
| + | }, | ||
| + | ... | ||
| + | ] | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Astfel, informațiile care trebuie preluate din rezultat sunt: | ||
| + | ^ atribut JSON ^ tip de date ^ detaliu ^ | ||
| + | | ''lat'' | ''double'' | latitudine | | ||
| + | | ''lng'' | ''double'' | longitudine | | ||
| + | | ''magnitude'' | ''double'' | magnitudinea | | ||
| + | | ''depth'' | ''double'' | adâncimea | | ||
| + | | ''src'' | ''String'' | sursa informației | | ||
| + | | ''datetime'' | ''String'' | data și ora la care s-au înregistrat datele | | ||
| + | |||
| + | Prin urmare, pașii care trebuie urmați pentru implementarea funcționalității sunt: | ||
| + | - construirea URL-ului, prin atașarea informațiilor preluate de la utilizator (coordonatele punctelor cardinale); | ||
| + | - execuția unei cereri HTTP; | ||
| + | - parsarea documentului JSON corespunzător răspunsului HTTP; <code java> | ||
| + | final ArrayList<EarthquakeInformation> earthquakeInformationList = new ArrayList<EarthquakeInformation>(); | ||
| + | JSONObject result = new JSONObject(content); | ||
| + | JSONArray jsonArray = result.getJSONArray(Constants.EARTHQUAKES); | ||
| + | for (int k = 0; k < jsonArray.length(); k++) { | ||
| + | JSONObject jsonObject = jsonArray.getJSONObject(k); | ||
| + | earthquakeInformationList.add(new EarthquakeInformation( | ||
| + | jsonObject.getDouble(Constants.LATITUDE), | ||
| + | jsonObject.getDouble(Constants.LONGITUDE), | ||
| + | jsonObject.getDouble(Constants.MAGNITUDE), | ||
| + | jsonObject.getDouble(Constants.DEPTH), | ||
| + | jsonObject.getString(Constants.SOURCE), | ||
| + | jsonObject.getString(Constants.DATETIME) | ||
| + | )); | ||
| + | } | ||
| + | </code> | ||
| + | - atașarea informațiilor obținute în cadrul unui control grafic de tip listă. | ||
| ===== Activitate de Laborator ===== | ===== Activitate de Laborator ===== | ||
| Line 532: | Line 683: | ||
| <code> | <code> | ||
| operation = addition|substraction|multiplication|division | operation = addition|substraction|multiplication|division | ||
| - | operation1 = număr real | + | operator1 = număr real |
| - | operation2 = număr real | + | operator2 = număr real |
| </code> | </code> | ||
| Line 564: | Line 715: | ||
| **5.** Să se importe în mediul integrat de dezvoltare Eclipse Luna SR1a (4.4.1) proiectul ''02-XkcdCartoonDisplayer'' din directorul ''labtasks''. | **5.** Să se importe în mediul integrat de dezvoltare Eclipse Luna SR1a (4.4.1) proiectul ''02-XkcdCartoonDisplayer'' din directorul ''labtasks''. | ||
| - | Se cere să se implementeze o aplicație Android care afișează, într-un control grafic de tip ''ImageView'', cea mai recentă caricatură de pe pagina Internet [[http://www.xkcd.com|xkcd]]. De asemenea, va putea fi vizualizat titlul acestei carticaturi, adresa Internet la care aceasta poate fi accesată precum și butoane de legătură către caricatura precedentă, respectiv caricatura următoare (în situația în care aceasta există). | + | Se cere să se implementeze o aplicație Android care afișează, într-un control grafic de tip ''ImageView'', cea mai recentă caricatură de pe pagina Internet [[http://www.xkcd.com|xkcd]]. De asemenea, va putea fi vizualizat titlul acestei caricaturi, adresa Internet la care aceasta poate fi accesată precum și butoane de legătură către caricatura precedentă, respectiv caricatura următoare (în situația în care aceasta există). |
| {{ :laboratoare:laborator07:xkcdcartoondisplayer.png?nolink&400 }} | {{ :laboratoare:laborator07:xkcdcartoondisplayer.png?nolink&400 }} | ||
| Line 664: | Line 815: | ||
| </code> | </code> | ||
| - | **7.** Să se încarce modificările realizate în cadrul depozitului 'Laborator07' de pe contul Github personal, folosind un mesaj sugestiv. <code> | + | **7.** (opțional) Să se importe în mediul integrat de dezvoltare Eclipse Luna SR1a (4.4.1) proiectul ''04-LandmarkLister'' din directorul ''labtasks''. |
| + | |||
| + | Se cere să se implementeze o aplicație Android care să afișeze informații cu privire la obiectivele turistice dintr-un areal geografic (desemnat prin coordonatele nord, sud, est, vest) pe baza rezultatelor furnizate de serviciul web [[http://http://api.geonames.org/citiesJSON|Geonames Paces]]. | ||
| + | |||
| + | Detaliile care se doresc a fi vizualizate pentru fiecare obiectiv turistic în parte sunt: | ||
| + | * așezarea geografică (latitudinea și longitudinea); | ||
| + | * denumirea toponimului (de regulă, localitatea în care se găsește); | ||
| + | * populația; | ||
| + | * descrierea localității în care poate fi vizitat; | ||
| + | * numele obiectivului; | ||
| + | * adresa paginii Internet la care pot fi consultate informații suplimentare, pe Wikipedia; | ||
| + | * codul de țară. | ||
| + | |||
| + | {{ :laboratoare:laborator07:landmarklister.png?nolink&400 }} | ||
| + | |||
| + | Adresa Internet la care este disponibil rezultatul în format JSON conține informații cu privire la coordonatele punctelor cardinale, precum și cu privire la numele de utilizator: | ||
| + | * ''north'', ''south'', ''east'', ''west'' - valoarea coordonatelor corespunzătoare punctelor cardinale, exprimate ca numere reale, cu semn; | ||
| + | * ''username'' - denumirea utilizatorului care deține drepturi de acces asupra acestui serviciu web (în cazul de față, ''pdsd''). | ||
| + | |||
| + | **Exemplu**. O adresă Internet de la care pot fi accesate rezultate în format JSON este: [[http://api.geonames.org/citiesJSON?north=44.1&south=-9.9&east=-22.4&west=55.2&username=pdsd|]]. | ||
| + | |||
| + | Rezultatele sunt furnizate în următorul format: | ||
| + | |||
| + | <code json> | ||
| + | { | ||
| + | "geonames":[ | ||
| + | { | ||
| + | "fcodeName":"capital of a political entity", | ||
| + | "toponymName":"Mexico City", | ||
| + | "countrycode":"MX", | ||
| + | "fcl":"P", | ||
| + | "fclName":"city, village,...", | ||
| + | "name":"Mexiko-Stadt", | ||
| + | "wikipedia":"en.wikipedia.org/wiki/Mexico_City", | ||
| + | "lng":-99.12766456604, | ||
| + | "fcode":"PPLC", | ||
| + | "geonameId":3530597, | ||
| + | "lat":19.428472427036, | ||
| + | "population":12294193 | ||
| + | }, | ||
| + | { | ||
| + | "fcodeName":"capital of a political entity", | ||
| + | "toponymName":"Beijing", | ||
| + | "countrycode":"CN", | ||
| + | "fcl":"P", | ||
| + | "fclName":"city, village,...", | ||
| + | "name":"Peking", | ||
| + | "wikipedia":"en.wikipedia.org/wiki/Beijing", | ||
| + | "lng":116.397228240967, | ||
| + | "fcode":"PPLC", | ||
| + | "geonameId":1816670, | ||
| + | "lat":39.9074977414405, | ||
| + | "population":1171662 | ||
| + | }, | ||
| + | ... | ||
| + | ] | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | Astfel, informațiile care trebuie preluate din rezultat sunt: | ||
| + | ^ atribut JSON ^ tip de date ^ detaliu ^ | ||
| + | | ''lat'' | ''double'' | latitudine | | ||
| + | | ''lng'' | ''double'' | longitudine | | ||
| + | | ''toponymName'' | ''String'' | denumirea toponimului | | ||
| + | | ''population'' | ''long'' | populație | | ||
| + | | ''fcodeName'' | ''String'' | descriere localitate | | ||
| + | | ''name'' | ''String'' | nume obiectiv turistic | | ||
| + | | ''wikipedia'' | ''String'' | adresa paginii Internet pe care pot fi regăsite informații suplimentare, pe Wikipedia | | ||
| + | | ''countrycode'' | ''String'' | codul de țară | | ||
| + | |||
| + | Prin urmare, pașii care trebuie urmați pentru implementarea funcționalității sunt: | ||
| + | - construirea URL-ului, prin atașarea informațiilor preluate de la utilizator (coordonatele punctelor cardinale); | ||
| + | - execuția unei cereri HTTP; | ||
| + | - parsarea documentului JSON corespunzător răspunsului HTTP; <code java> | ||
| + | final ArrayList<LandmarkInformation> landMarkInformationList = new ArrayList<LandmarkInformation>(); | ||
| + | JSONObject result = new JSONObject(content); | ||
| + | JSONArray jsonArray = result.getJSONArray(Constants.GEONAMES); | ||
| + | for (int k = 0; k < jsonArray.length(); k++) { | ||
| + | JSONObject jsonObject = jsonArray.getJSONObject(k); | ||
| + | landMarkInformationList.add(new LandmarkInformation( | ||
| + | jsonObject.getDouble(Constants.LATITUDE), | ||
| + | jsonObject.getDouble(Constants.LONGITUDE), | ||
| + | jsonObject.getString(Constants.TOPONYM_NAME), | ||
| + | jsonObject.getLong(Constants.POPULATION), | ||
| + | jsonObject.getString(Constants.FCODE_NAME), | ||
| + | jsonObject.getString(Constants.NAME), | ||
| + | jsonObject.getString(Constants.WIKIPEDIA_WEB_PAGE_ADDRESS), | ||
| + | jsonObject.getString(Constants.COUNTRY_CODE))); | ||
| + | } | ||
| + | </code> | ||
| + | - atașarea informațiilor obținute în cadrul unui control grafic de tip listă. | ||
| + | |||
| + | **8.** Să se încarce modificările realizate în cadrul depozitului 'Laborator07' de pe contul Github personal, folosind un mesaj sugestiv. <code> | ||
| student@pdsd2015:~/Laborator07$ git add * | student@pdsd2015:~/Laborator07$ git add * | ||
| student@pdsd2015:~/Laborator07$ git commit -m "implemented taks for laboratory 07" | student@pdsd2015:~/Laborator07$ git commit -m "implemented taks for laboratory 07" | ||
| Line 682: | Line 925: | ||
| [[http://developer.android.com/reference/java/net/HttpURLConnection.html|HttpURLConnection]]\\ | [[http://developer.android.com/reference/java/net/HttpURLConnection.html|HttpURLConnection]]\\ | ||
| [[http://hc.apache.org/httpcomponents-client-4.4.x/index.html|Apache Http Components]]\\ | [[http://hc.apache.org/httpcomponents-client-4.4.x/index.html|Apache Http Components]]\\ | ||
| - | [[http://jsoup.org/|Jsoup]] | + | [[http://developer.android.com/reference/org/apache/http/client/HttpClient.html|HttpClient]], [[http://developer.android.com/reference/org/apache/http/client/methods/HttpGet.html|HttpGet]], [[http://developer.android.com/reference/org/apache/http/client/methods/HttpPost.html|HttpPost]]\\ |
| + | [[http://jsoup.org/|Jsoup]]\\ | ||
| + | [[http://en.wikipedia.org/wiki/JSON|Formatul JSON]]\\ | ||
| + | [[http://developer.android.com/reference/org/json/JSONObject.html|JSONObject]] | ||
