Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
laboratoare:laborator07 [2016/04/15 00:16]
Andrei Roșu-Cojocaru
laboratoare:laborator07 [2017/02/20 20:54] (current)
Line 2: Line 2:
  
 ===== Protocolul HTTP ===== ===== Protocolul HTTP =====
- 
-===== Comunicația prin 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, al căror rezultat este de cele mai multe ori oferit în format JSON sau XML. De asemenea, descărcarea unor resurse se poate face prin inspectarea codului sursă al unor pagini Internet (documente HTML), în urma acestei operații detectându-se locația la care acestea sunt disponibile. 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, al căror rezultat este de cele mai multe ori oferit în format JSON sau XML. De asemenea, descărcarea unor resurse se poate face prin inspectarea codului sursă al unor pagini Internet (documente HTML), în urma acestei operații detectându-se locația la care acestea sunt disponibile.
Line 91: Line 89:
   * ''​Set-Cookie''​ - transmiterea unui cookie de la serverul web la client, acesta trebuind să fie inclus în antetele ulterioare ale mesajelor schimbate între cele două entități   * ''​Set-Cookie''​ - transmiterea unui cookie de la serverul web la client, acesta trebuind să fie inclus în antetele ulterioare ale mesajelor schimbate între cele două entități
  
 +===== Mecanisme pentru Comunicația prin HTTP în Android =====
  
-==== Mecanisme pentru Comunicația prin HTTP în Android ==== +==== Clasa HttpURLConnection ​====
- +
-=== Clasa HttpURLConnection ===+
  
 În Android, comunicația dintre un server web si un client poate fi gestionată prin intermediul clasei [[http://​developer.android.com/​reference/​java/​net/​HttpURLConnection.html|HttpURLConnection]],​ care pune la dispoziție aceleași funcționalități ca în cazul Java SE. În Android, comunicația dintre un server web si un client poate fi gestionată prin intermediul clasei [[http://​developer.android.com/​reference/​java/​net/​HttpURLConnection.html|HttpURLConnection]],​ care pune la dispoziție aceleași funcționalități ca în cazul Java SE.
Line 124: Line 121:
  
 <code java> <code java>
-new Thread(new Runnable() ​{+private class WebPageKeywordSearchAsyncTask extends AsyncTask<​String,​ Void, String> ​{ 
   @Override   @Override
-  ​public void run() { +  ​protected String doInBackground(String... params) {
-    URL url = null;+
     HttpURLConnection httpURLConnection = null;     HttpURLConnection httpURLConnection = null;
 +    StringBuilder result = new StringBuilder();​
 +    String error = null;
     try {     try {
-      ​url = new URL(Constants.LOGIN_WEB_SERVICE_ADDRESS); +      ​String webPageAddress ​= params[0]; 
-      ​httpURLConnection ​= (HttpURLConnection)url.openConnection(); +      ​String keyword ​= params[1]; 
-      ​httpURLConnection.setRequestMethod(Constants.POST_REQUEST_METHOD);​ +      ​if (webPageAddress == null || webPageAddress.isEmpty()) { 
-      httpURLConnection.setDoInput(true); +        error = "Web Page address cannot be empty"; 
-      ​httpURLConnection.setDoOutput(true);​ +      ​} 
-      ​OutputStream outputStream ​= httpURLConnection.getOutputStream(); +      ​if (keyword ​== null || keyword.isEmpty()) { 
-      ​BufferedWriter bufferedWriter ​= new BufferedWriter(new OutputStreamWriter(outputStream, ​"UTF-8")); +        ​error ​= "Keyword cannot be empty"; 
-      ​StringBuilder parameters ​= new StringBuilder(); +      } 
-      ​parameters.append(URLEncoder.encode(Constants.USERNAME_ATTRIBUTE, ​"UTF-8") + "​="​ + URLEncoder.encode(username, ​"UTF-8")); +      if (error != null) { 
-      ​parameters.append("​&"); +        return error; 
-      ​parameters.append(URLEncoder.encode(Constants.PASSWORD_ATTRIBUTE, ​"UTF-8") + "​="​ + URLEncoder.encode(password, ​"UTF-8")); +      ​} 
-      ​bufferedWriter.write(parameters.toString()); +      URL url = new URL(webPageAddress); 
-      ​bufferedWriter.flush(); +      ​result.append("​Protocol: ​" + url.getProtocol() + "\n"); 
-      bufferedWriter.close(); +      ​result.append("​Host: " + url.getHost() + "\n"); 
-      outputStream.close(); +      ​result.append("​Port: " + url.getPort() + "\n"); 
-      ​int responseCode = httpURLConnection.getResponseCode(); +      ​result.append("File: " + url.getFile() + "​\n"​); 
-      ​StringBuilder response ​= new StringBuilder(); +      ​result.append("​Reference:​ " + url.getRef() + "​\n"​); 
-      if (responseCode == HttpURLConnection.HTTP_OK) { +      ​result.append("​==========\n"​); 
-        ​InputStream inputStream ​= httpURLConnection.getInputStream(); +      ​URLConnection urlConnection ​= url.openConnection(); 
-        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); +      if (urlConnection instanceof ​HttpURLConnection) { 
-        String ​line; +        ​httpURLConnection ​= (HttpURLConnection)urlConnection; 
-        while ((line = bufferedReader.readLine()) != null) { +        BufferedReader bufferedReader = Utilities.getReader(httpURLConnection); 
-          ​response.append(line);​+        int currentLineNumber = 0, numberOfOccurrencies = 0; 
 +        String ​currentLineContent; 
 +        while ((currentLineContent ​= bufferedReader.readLine()) != null) { 
 +          ​currentLineNumber++;​ 
 +          if (currentLineContent.contains(keyword)) { 
 +            result.append("line: " + currentLineNumber + " / " + currentLineContent+"​\n"​); 
 +            numberOfOccurrencies++;​ 
 +          }
         }         }
-        ​bufferedReader.close(); +        ​result.append("​Number of occurrencies:​ " + numberOfOccurrencies+"​\n"​); 
-        ​inputStream.close();+        ​return result.toString();​ 
 +      } 
 +    } catch (MalformedURLException malformedURLException) { 
 +      Log.e(Constants.TAG,​ malformedURLException.getMessage());​ 
 +      if (Constants.DEBUG) { 
 +        malformedURLException.printStackTrace();
       }       }
     } catch (IOException ioException) {     } catch (IOException ioException) {
Line 167: Line 178:
       }       }
     }     }
 +    return null;
   }   }
-}).start();+ 
 +  @Override 
 +  public void onPostExecute(String result) { 
 +    resultsTextView.setText(result); 
 +  } 
 + 
 +}
 </​code>​ </​code>​
  
-{{ :​laboratoare:​laborator07:​webpagekeywordsearch.png?​nolink&​400 }}+{{ :​laboratoare:​laborator07:​01webpagekeywordsearch.png?​nolink&​400 }}
  
 <note warning>​Comunicația dintre serverul web și client trebuie să se realizeze pe un fir de execuție separat, în caz contrar fiind generată excepția ''​android.os.NetworkOnMainThreadException''​.</​note>​ <note warning>​Comunicația dintre serverul web și client trebuie să se realizeze pe un fir de execuție separat, în caz contrar fiind generată excepția ''​android.os.NetworkOnMainThreadException''​.</​note>​
Line 179: Line 197:
 O practică curentă este de a verifica codul de răspuns transmis de a accesa fluxul de intrare asociat resursei respective. Astfel, numai în situația în care valoarea întoarsă de metoda ''​getResponseCode()''​ este ''​HttpURLConnection.HTTP_OK''​ se poate continua procesarea conținutului stocat la URL-ul accesat. O practică curentă este de a verifica codul de răspuns transmis de a accesa fluxul de intrare asociat resursei respective. Astfel, numai în situația în care valoarea întoarsă de metoda ''​getResponseCode()''​ este ''​HttpURLConnection.HTTP_OK''​ se poate continua procesarea conținutului stocat la URL-ul accesat.
  
-=== Apache HTTP Components ===+==== Apache HTTP Components ​====
  
 [[https://​hc.apache.org/​|Apache HTTP Components]] este un proiect open-source,​ dezvoltat sub licență Apache, punând la dispoziția utilizatorilor o bibliotecă Java pentru accesarea de resurse prin intermediul protocolului HTTP. Funcționalitatea poate fi utilizată în cadrul oricărei mașini virtuale Java și era inclusă și în platforma Android până în API Level 23 (Marshmellow) [[http://​developer.android.com/​about/​versions/​marshmallow/​android-6.0-changes.html#​behavior-apache-http-client|când a fost exclusă]], fiind invocate probleme legate de compatibilitate pentru anumite platforme precum și utilizarea excesivă a rețelei cu impact asupra consumului de energie. În schimb, se recomandă utilizarea clasei HttpURLConnection care asigură compresia datelor (în mod transparent pentru utilizator!) precum și folosirea unui cache. Cu toate acestea, proiectul Apache HTTP Components este în continuă dezvoltare și folosit pe scară largă. [[https://​hc.apache.org/​|Apache HTTP Components]] este un proiect open-source,​ dezvoltat sub licență Apache, punând la dispoziția utilizatorilor o bibliotecă Java pentru accesarea de resurse prin intermediul protocolului HTTP. Funcționalitatea poate fi utilizată în cadrul oricărei mașini virtuale Java și era inclusă și în platforma Android până în API Level 23 (Marshmellow) [[http://​developer.android.com/​about/​versions/​marshmallow/​android-6.0-changes.html#​behavior-apache-http-client|când a fost exclusă]], fiind invocate probleme legate de compatibilitate pentru anumite platforme precum și utilizarea excesivă a rețelei cu impact asupra consumului de energie. În schimb, se recomandă utilizarea clasei HttpURLConnection care asigură compresia datelor (în mod transparent pentru utilizator!) precum și folosirea unui cache. Cu toate acestea, proiectul Apache HTTP Components este în continuă dezvoltare și folosit pe scară largă.
Line 320: Line 338:
   * 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''​)
  
-=== Volley ===+==== Volley ​====
  
 [[http://​developer.android.com/​training/​volley/​index.html|Volley]] este o bibliotecă open-source (disponibilă prin intermediul Android Open-Source Project) ce oferă facilități pentru interogarea de resurse disponibile prin intermediul protocolului HTTP. [[http://​developer.android.com/​training/​volley/​index.html|Volley]] este o bibliotecă open-source (disponibilă prin intermediul Android Open-Source Project) ce oferă facilități pentru interogarea de resurse disponibile prin intermediul protocolului HTTP.
Line 335: Line 353:
 Pentru utilizarea bibliotecii Volley este necesar să se realizeze următoarele operații: Pentru utilizarea bibliotecii Volley este necesar să se realizeze următoarele operații:
   - descărcarea codului sursă de la depozitul unde este întreținută <​code>​   - descărcarea codului sursă de la depozitul unde este întreținută <​code>​
-student@dandroid2015:~$ git clone https://​android.googlesource.com/​platform/​frameworks/​volley+student@eim2016:~$ git clone https://​android.googlesource.com/​platform/​frameworks/​volley
 </​code>​ </​code>​
   - referirea proiectului ca bibliotecă în Android Studio   - referirea proiectului ca bibliotecă în Android Studio
     * //File// -> //New// -> //Import Module...// {{ :​laboratoare:​laborator05:​volley_androidstudio01.png?​nolink }}     * //File// -> //New// -> //Import Module...// {{ :​laboratoare:​laborator05:​volley_androidstudio01.png?​nolink }}
-    * indicarea locației la care au fost descărcate sursele în prelabil și o denumire a proiectului (tipic, '':​volley''​) sub care va fi referit {{ :​laboratoare:​laborator05:volley_androidstudio02.png?nolink }}+    * indicarea locației la care au fost descărcate sursele în prelabil și o denumire a proiectului (tipic, '':​volley''​) sub care va fi referit {{ :​laboratoare:​laborator07:02volleyandroidstudio.png?nolink }}
     * specificarea dependenței față de acest proiect precum și faptul că este necesar ca acesta să fie compilat <file gradle build.gradle>​     * specificarea dependenței față de acest proiect precum și faptul că este necesar ca acesta să fie compilat <file gradle build.gradle>​
 ... ...
Line 350: Line 368:
 } }
 </​file>​ </​file>​
-    * dacă pentru Volley se folosește API Level 23, este necesar să se utilizeze biblioteca ''​org.apache.http.legacy''​ întrucât implementarea sa utilizează Apache HTTP Components.+    * dacă pentru Volley se folosește API Level 23, este necesar să se utilizeze biblioteca ''​org.apache.http.legacy''​ întrucât implementarea sa utilizează Apache HTTP Components. ​<file gradle build.gradle>​ 
 +android { 
 +  ... 
 +  useLibrary '​org.apache.http.legacy'​ 
 +  ... 
 +} 
 +</​file>​
  
 Volley gestionează o structură de date [[https://​android.googlesource.com/​platform/​frameworks/​volley/​+/​master/​src/​main/​java/​com/​android/​volley/​RequestQueue.java|RequestQueue]] care are rolul de a controla modul în care sunt tratate cererile. Aceasta distribuie cererile care trebuie procesate concurent către firele de execuție care se ocupă de comunicația prin rețea, realizând de asemenea interogarea informațiilor care se regăsest în cache. Există două moduri în care poate fi construit un obiect de tip ''​RequestQueue'':​ Volley gestionează o structură de date [[https://​android.googlesource.com/​platform/​frameworks/​volley/​+/​master/​src/​main/​java/​com/​android/​volley/​RequestQueue.java|RequestQueue]] care are rolul de a controla modul în care sunt tratate cererile. Aceasta distribuie cererile care trebuie procesate concurent către firele de execuție care se ocupă de comunicația prin rețea, realizând de asemenea interogarea informațiilor care se regăsest în cache. Există două moduri în care poate fi construit un obiect de tip ''​RequestQueue'':​
Line 366: Line 390:
  
 <file java VolleyController.java>​ <file java VolleyController.java>​
-package org.rosedu.dandroid.messageme.network;​ 
- 
 import android.content.Context;​ import android.content.Context;​
  
Line 665: Line 687:
  
 <code java> <code java>
-private class OcwCoursesDisplayerThread ​extends ​Thread ​{+private class OCWCoursesDisplayerAsyncTask ​extends ​AsyncTask<​Void,​ Void, List<​OCWCourseInformation>> ​{ 
   @Override   @Override
-  ​public void run() { +  ​protected List<OCWCourseInformation> doInBackground(Void... params) {
-    ArrayList<OcwCourseInformation>​ ocwCourseInformationList = new ArrayList<​OcwCourseInformation>(); +
-    ​+
     HttpClient httpClient = new DefaultHttpClient();​     HttpClient httpClient = new DefaultHttpClient();​
-    HttpGet ​httpWebPageGet ​= new HttpGet(Constants.OCW_BASE_INTERNET_ADDRESS + Constants.OCW_REFERRENCE_INTERNET_ADDRESS);+    HttpGet ​httpGet ​= new HttpGet(Constants.OCW_BASE_INTERNET_ADDRESS + Constants.OCW_REFFERRENCE_INTERNET_ADDRESS);
     ResponseHandler<​String>​ responseHandler = new BasicResponseHandler();​     ResponseHandler<​String>​ responseHandler = new BasicResponseHandler();​
 +    List<​String>​ logoAddressesList = new ArrayList<>​();​
 +    int logoAddressesListSize = -1;
 +    List<​String>​ coursesNameList = new ArrayList();​
 +    int coursesNameListSize = -1;
 +    List<​OCWCourseInformation>​ ocwCourseInformationList = new ArrayList<>​();​
 +    int courseInformationListSize = -1;
     try {     try {
-      String pageSourceCode = httpClient.execute(httpWebPageGet, responseHandler);​+      String pageSourceCode = httpClient.execute(httpGet, responseHandler);​
       Document document = Jsoup.parse(pageSourceCode);​       Document document = Jsoup.parse(pageSourceCode);​
       Element htmlTag = document.child(0);​       Element htmlTag = document.child(0);​
-      Elements ​imgTagsClassMediaright ​= htmlTag.getElementsByAttributeValue(Constants.CLASS_ATTRIBUTE,​ Constants.MEDIARIGHT_VALUE); +      Elements ​imgTagsClassMediaRight ​= htmlTag.getElementsByAttributeValue(Constants.CLASS_ATTRIBUTE,​ Constants.MEDIA_RIGHT_VALUE); 
-      Iterator<​Element>​ logoIterator = imgTagsClassMediaright.iterator();​+      Iterator<​Element>​ logoIterator = imgTagsClassMediaRight.iterator();​
       while (logoIterator.hasNext()) {       while (logoIterator.hasNext()) {
         Element imgTagClassMediaRight = logoIterator.next();​         Element imgTagClassMediaRight = logoIterator.next();​
-        ​String logoAddress = Constants.OCW_BASE_INTERNET_ADDRESS + imgTagClassMediaRight.attr(Constants.SRC_ATTRIBUTE); +        ​logoAddressesList.add(Constants.OCW_BASE_INTERNET_ADDRESS + imgTagClassMediaRight.attr(Constants.SRC_ATTRIBUTE));​
-        HttpGet httpLogoGet = new HttpGet(logoAddress);​ +
-        HttpResponse httpResponse = httpClient.execute(httpLogoGet);​ +
-        HttpEntity httpEntity = httpResponse.getEntity();​ +
-         +
-        OcwCourseInformation ocwCourseInformation = new OcwCourseInformation();​ +
-        Bitmap logo = Bitmap.createScaledBitmap(BitmapFactory.decodeStream(httpEntity.getContent()),​ +
-                                                Constants.LOGO_WIDTH,​ +
-                                                Constants.LOGO_HEIGHT,​ +
-                                                false);  +
-        ocwCourseInformation.setLogo(Utilities.makeTransparent(logo));​ +
-        ocwCourseInformationList.add(ocwCourseInformation);+
       }       }
       Elements strongTags = htmlTag.getElementsByTag(Constants.STRONG_TAG);​       Elements strongTags = htmlTag.getElementsByTag(Constants.STRONG_TAG);​
       Iterator<​Element>​ nameIterator = strongTags.iterator();​       Iterator<​Element>​ nameIterator = strongTags.iterator();​
-      int currentPosition = 0; 
       while (nameIterator.hasNext()) {       while (nameIterator.hasNext()) {
         Element strongTag = nameIterator.next();​         Element strongTag = nameIterator.next();​
-        ​String name = strongTag.ownText(); +        ​coursesNameList.add(strongTag.ownText());​
-         +
-        ocwCourseInformationList.get(currentPosition++).setName(name);+
       }       }
-       +      ​logoAddressesListSize = logoAddressesList.size();​ 
-      ​final OcwCourseInformationAdapter ocwCourseInformationAdapter ​= new OcwCourseInformationAdapter(OcwCoursesDisplayerActivity.this, ocwCourseInformationList); +      ​coursesNameListSize ​= coursesNameList.size(); 
-      ​ocwCoursesListView.post(new Runnable() { +      ​if (logoAddressesListSize == coursesNameListSize) { 
-        ​@Override +        ​courseInformationListSize = logoAddressesListSize;​ // = coursesNameListSize 
-        ​public void run() { +        ​for (int index = 0; index < courseInformationListSize;​ index++) { 
-          ​ocwCoursesListView.setAdapter(ocwCourseInformationAdapter);+          ​OCWCourseInformation ocwCourseInformation = new OCWCourseInformation(logoAddressesList.get(index),​ coursesNameList.get(index));​ 
 +          ocwCourseInformationList.add(ocwCourseInformation);
         }         }
-      });+        return ocwCourseInformationList; 
 +      }
     } catch (ClientProtocolException clientProtocolException) {     } catch (ClientProtocolException clientProtocolException) {
       Log.e(Constants.TAG,​ clientProtocolException.getMessage());​       Log.e(Constants.TAG,​ clientProtocolException.getMessage());​
Line 721: Line 736:
         ioException.printStackTrace();​         ioException.printStackTrace();​
       }       }
 +    }
 +    return null;
 +  }
 +
 +  @Override
 +  public void onPostExecute(List<​OCWCourseInformation>​ ocwCourseInformationList) {
 +    for (final OCWCourseInformation ocwCourseInformation:​ ocwCourseInformationList) {
 +      ImageRequest profilePhotoRequest = new ImageRequest(
 +        ocwCourseInformation.getLogoLocation(),​
 +        new Response.Listener<​Bitmap>​() {
 +          @Override
 +          public void onResponse(Bitmap bitmap) {
 +            ocwCourseContentList.add(new OCWCourseContent(bitmap,​ ocwCourseInformation.getName()));​
 +            ocwCourseListAdapter.notifyDataSetChanged();​
 +          }
 +        },
 +        Constants.LOGO_WIDTH,​
 +        Constants.LOGO_HEIGHT,​
 +        null,
 +        Bitmap.Config.RGB_565,​
 +        new Response.ErrorListener() {
 +          public void onErrorResponse(VolleyError volleyError) {
 +            Log.d(Constants.TAG,​ volleyError.toString());​
 +            if (Constants.DEBUG) {
 +              Toast.makeText(ocwCoursesListView.getContext(),​ ocwCoursesListView.getResources().getString(R.string.an_error_has_occurred),​ Toast.LENGTH_LONG)
 +                   ​.show();​
 +            }
 +          }
 +        }
 +      );
 +      VolleyController.getInstance(ocwCoursesListView.getContext()).addToRequestQueue(profilePhotoRequest);​
     }     }
   }   }
Line 726: Line 772:
 </​code>​ </​code>​
  
-{{ :​laboratoare:​laborator07:​ocwcoursesdisplayer.png?​nolink&​400 }}+{{ :​laboratoare:​laborator07:​03ocwcoursesdisplayer.png?​nolink&​400 }}
  
 ===== Prelucrare JSON (JavaScript Object Notation) - opțional ===== ===== Prelucrare JSON (JavaScript Object Notation) - opțional =====
Line 813: Line 859:
   * data și ora la care s-a înregistrat.   * data și ora la care s-a înregistrat.
  
-{{ :​laboratoare:​laborator07:​earthquakelister.png?​nolink&​400 }}+{{ :​laboratoare:​laborator07:​04earthquakelister.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: 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:
Line 819: Line 865:
   * ''​username''​ - denumirea utilizatorului care deține drepturi de acces asupra acestui serviciu web (în cazul de față, ''​pdsd''​).   * ''​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|]].+**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=eim2016|]].
  
 Rezultatele sunt furnizate în următorul format: Rezultatele sunt furnizate în următorul format:
Line 907: Line 953:
 Operația care se dorește a fi efectuată precum și metoda prin care vor fi transmise informațiile către serviciul web vor putea fi selectate prin intermediul unor liste. Operația care se dorește a fi efectuată precum și metoda prin care vor fi transmise informațiile către serviciul web vor putea fi selectate prin intermediul unor liste.
  
-{{ :​laboratoare:​laborator07:​calculatorwebservice.png?​nolink&​400 }}+{{ :​laboratoare:​laborator07:​05calculatorwebservice.png?​nolink&​400 }}
  
 Parametrii ce trebuie incluși în cadrul cererii HTTP sunt: Parametrii ce trebuie incluși în cadrul cererii HTTP sunt:
Line 947: Line 993:
 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ă). 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:​06xkcdcartoondisplayer.png?​nolink&​400 }}
  
 Pentru realizarea aplicației,​ vor trebui urmați următorii pași: Pentru realizarea aplicației,​ vor trebui urmați următorii pași:
Line 956: Line 1002:
   * obținerea titlului caricaturii (se poate realiza o căutare după eticheta ''<​div>''​ care deține un atribut ''​id''​ cu valoarea ''​ctitle'',​ folosind metoda [[http://​jsoup.org/​apidocs/​org/​jsoup/​nodes/​Element.html#​getElementsByAttributeValue%28java.lang.String,​%20java.lang.String%29|getElementsByAttributeValue()]]);​ ulterior, se va prelua conținutul acestei etichete prin intermediul metodei [[http://​jsoup.org/​apidocs/​org/​jsoup/​nodes/​Element.html#​ownText()|ownText()]]:​ <code java>   * obținerea titlului caricaturii (se poate realiza o căutare după eticheta ''<​div>''​ care deține un atribut ''​id''​ cu valoarea ''​ctitle'',​ folosind metoda [[http://​jsoup.org/​apidocs/​org/​jsoup/​nodes/​Element.html#​getElementsByAttributeValue%28java.lang.String,​%20java.lang.String%29|getElementsByAttributeValue()]]);​ ulterior, se va prelua conținutul acestei etichete prin intermediul metodei [[http://​jsoup.org/​apidocs/​org/​jsoup/​nodes/​Element.html#​ownText()|ownText()]]:​ <code java>
 Element divTagIdCtitle = htmlTag.getElementsByAttributeValue(Constants.ID_ATTRIBUTE,​ Constants.CTITLE_VALUE).first();​ Element divTagIdCtitle = htmlTag.getElementsByAttributeValue(Constants.ID_ATTRIBUTE,​ Constants.CTITLE_VALUE).first();​
-xkcdCartoonInfo.setCartoonTitle(divTagIdCtitle.ownText());​+xkcdCartoonInformation.setCartoonTitle(divTagIdCtitle.ownText());​
 </​code>​ </​code>​
   * obținerea URL-ului imaginii care trebuie afișată (se poate realiza o căutare după eticheta ''<​div>''​ care deține un atribut ''​id''​ cu valoarea ''​comic'',​ folosind metoda ''​getElementsByAttributeValue()''​);​ aceasta conține la rândul ei un element ''<​img>''​ care poate fi accesat prin intermediul metodei [[http://​jsoup.org/​apidocs/​org/​jsoup/​nodes/​Element.html#​getElementsByTag%28java.lang.String%29|getElementsByTag()]];​ adresa Internet a caricaturii este reprezentată de valoarea atributului ''​src'',​ furnizată de metoda [[http://​jsoup.org/​apidocs/​org/​jsoup/​nodes/​Element.html#​attr%28java.lang.String,​%20java.lang.String%29|attr()]]:​ <code java>   * obținerea URL-ului imaginii care trebuie afișată (se poate realiza o căutare după eticheta ''<​div>''​ care deține un atribut ''​id''​ cu valoarea ''​comic'',​ folosind metoda ''​getElementsByAttributeValue()''​);​ aceasta conține la rândul ei un element ''<​img>''​ care poate fi accesat prin intermediul metodei [[http://​jsoup.org/​apidocs/​org/​jsoup/​nodes/​Element.html#​getElementsByTag%28java.lang.String%29|getElementsByTag()]];​ adresa Internet a caricaturii este reprezentată de valoarea atributului ''​src'',​ furnizată de metoda [[http://​jsoup.org/​apidocs/​org/​jsoup/​nodes/​Element.html#​attr%28java.lang.String,​%20java.lang.String%29|attr()]]:​ <code java>
Line 962: Line 1008:
 String cartoonInternetAddress = divTagIdComic.getElementsByTag(Constants.IMG_TAG).attr(Constants.SRC_ATTRIBUTE);​ String cartoonInternetAddress = divTagIdComic.getElementsByTag(Constants.IMG_TAG).attr(Constants.SRC_ATTRIBUTE);​
 </​code> ​ </​code> ​
-  * obținerea caricaturii,​ pe baza adresei Internet la care este găzduită, se face prin fluxul de intrare corespunzător entității HTTP, care va fi decodificat prin intermediul metodei [[http://​developer.android.com/​reference/​android/​graphics/​BitmapFactory.html#​decodeStream(java.io.InputStream)|BitmapFactory.decodeStream()]],​ care întoarce un obiect de tip [[http://​developer.android.com/​reference/​android/​graphics/​Bitmap.html|Bitmap]];​ asocierea unui astfel de obiect ca sursă a unui control grafic ce tip ''​ImageView''​ se face prin intermediul metodei [[http://​developer.android.com/​reference/​android/​widget/​ImageView.html#​setImageBitmap(android.graphics.Bitmap)|setImageBitmap()]];​+  * obținerea caricaturii,​ pe baza adresei Internet la care este găzduită, se face prin fluxul de intrare corespunzător entității HTTP, care va fi decodificat prin intermediul metodei [[http://​developer.android.com/​reference/​android/​graphics/​BitmapFactory.html#​decodeStream(java.io.InputStream)|BitmapFactory.decodeStream()]],​ care întoarce un obiect de tip [[http://​developer.android.com/​reference/​android/​graphics/​Bitmap.html|Bitmap]];​ asocierea unui astfel de obiect ca sursă a unui control grafic ce tip ''​ImageView''​ se face prin intermediul metodei [[http://​developer.android.com/​reference/​android/​widget/​ImageView.html#​setImageBitmap(android.graphics.Bitmap)|setImageBitmap()]]; ​alternativ, se poate folosi biblioteca open-source Volley, care pune la dispoziție un obiect specializat pentru descărcarea de imagini și încărcarea acestora în controalele din cadrul interfeței grafice (''​ImageRequest''​):​ <code java> 
 +ImageRequest cartoonRequest = new ImageRequest( 
 +  cartoonUrl,​ 
 +  new Response.Listener<​Bitmap>​() { 
 +    @Override 
 +    public void onResponse(Bitmap bitmap) { 
 +      xkcdCartoonImageView.setImageBitmap(bitmap);​ 
 +    } 
 +  }, 
 +  0, 
 +  0, 
 +  null, 
 +  Bitmap.Config.RGB_565,​ 
 +  new Response.ErrorListener() { 
 +    public void onErrorResponse(VolleyError volleyError) { 
 +      Log.d(Constants.TAG,​ volleyError.toString());​ 
 +      if (Constants.DEBUG) { 
 +        Toast.makeText(xkcdCartoonTitleTextView.getContext(),​ xkcdCartoonTitleTextView.getResources().getString(R.string.an_error_has_occurred),​ Toast.LENGTH_LONG) 
 +             ​.show();​ 
 +      } 
 +    } 
 +  } 
 +); 
 +VolleyController.getInstance(xkcdCartoonImageView.getContext()).addToRequestQueue(cartoonRequest);​ 
 +</​code>​
   * obținerea adreselor Internet corespunzătoare caricaturilor anterioară,​ respectiv următoare, care vor fi asociate obiectului ascultător ce tratează evenimentul de tip apăsare al butonului aferent; se poate realiza o căutare după eticheta ''<​a>''​ care deține un atribut ''​rel''​ cu valoarea ''​prev'',​ respectiv ''​next'',​ folosind metoda ''​getElementsByAttributeValue()''​);​ URL-ul reprezintă valoarea atributului ''​href'',​ furnizată de metoda ''​attr'':​ <code java>   * obținerea adreselor Internet corespunzătoare caricaturilor anterioară,​ respectiv următoare, care vor fi asociate obiectului ascultător ce tratează evenimentul de tip apăsare al butonului aferent; se poate realiza o căutare după eticheta ''<​a>''​ care deține un atribut ''​rel''​ cu valoarea ''​prev'',​ respectiv ''​next'',​ folosind metoda ''​getElementsByAttributeValue()''​);​ URL-ul reprezintă valoarea atributului ''​href'',​ furnizată de metoda ''​attr'':​ <code java>
 Element aTagRelPrev = htmlTag.getElementsByAttributeValue(Constants.REL_ATTRIBUTE,​ Constants.PREVIOUS_VALUE).first();​ Element aTagRelPrev = htmlTag.getElementsByAttributeValue(Constants.REL_ATTRIBUTE,​ Constants.PREVIOUS_VALUE).first();​
Line 992: Line 1062:
  
 <code java> <code java>
-private class XkcdCartoonDisplayerAsyncTask ​extends AsyncTask<​String,​ Void, XkcdCartoonInfo> {+private class XKCDCartoonDisplayerAsyncTask ​extends AsyncTask<​String,​ Void, XKCDCartoonInformation> {
  
   @Override ​   ​   @Override ​   ​
-  protected ​XkcdCartoonInfo ​doInBackground(String... urls) {+  protected ​XKCDCartoonInformation ​doInBackground(String... urls) {
     // get the html document corresponding to the xkcd.com website     // get the html document corresponding to the xkcd.com website
     // parse the document in order to obtain the needed information     // parse the document in order to obtain the needed information
Line 1001: Line 1071:
  
   @Override   @Override
-  protected void onPostExecute(XkcdCartoonInfo xkcdCartoonInfo) {+  protected void onPostExecute(XKCDCartoonInformation xkcdCartoonInformation) {
     // get references to the needed information     // get references to the needed information
     // map the information to the corresponding widget ​     // map the information to the corresponding widget ​
Line 1015: Line 1085:
  
 <code java> <code java>
-new XkcdCartoonDisplayerAsyncTask().execute(Constants.XKCD_INTERNET_ADDRESS);​+new XKCDCartoonDisplayerAsyncTask().execute(Constants.XKCD_INTERNET_ADDRESS);​
 </​code>​ </​code>​
  
Line 1022: Line 1092:
 Se cere să se implementeze o aplicație Android care să realizeze o căutare folosind motorul [[http://​www.google.com|Google]],​ rezultatul fiind expus printr-un control grafic de tip [[http://​developer.android.com/​reference/​android/​webkit/​WebView.html|WebView]]. Se cere să se implementeze o aplicație Android care să realizeze o căutare folosind motorul [[http://​www.google.com|Google]],​ rezultatul fiind expus printr-un control grafic de tip [[http://​developer.android.com/​reference/​android/​webkit/​WebView.html|WebView]].
  
-{{ :​laboratoare:​laborator07:​googlesearcher.png?​nolink&​400 }}+{{ :​laboratoare:​laborator07:​07googlesearcher.png?​nolink&​400 }}
  
 În situația în care șirul de caractere după care se realizează căutarea conține mai multe cuvinte (având drept delimitator caracterul spațiu), acestea vor fi legate prin intermediul caracterului ''​+''​. În situația în care șirul de caractere după care se realizează căutarea conține mai multe cuvinte (având drept delimitator caracterul spațiu), acestea vor fi legate prin intermediul caracterului ''​+''​.
Line 1058: Line 1128:
   * codul de țară.   * codul de țară.
  
-{{ :​laboratoare:​laborator07:​landmarklister.png?​nolink&​400 }}+{{ :​laboratoare:​laborator07:​08landmarklister.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: 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:
laboratoare/laborator07.1460668592.txt.gz · Last modified: 2017/02/20 20:44 (external edit)
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0