Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
laboratoare:laborator07 [2016/04/15 00:18] Andrei Roșu-Cojocaru |
laboratoare:laborator07 [2017/02/20 20:54] (current) |
||
|---|---|---|---|
| Line 88: | Line 88: | ||
| * ''Accept-Ranges'' - informație referitoare la transmiterea conținutului solicitat în mai multe părți, corespunzătoare unor intervale de octeți | * ''Accept-Ranges'' - informație referitoare la transmiterea conținutului solicitat în mai multe părți, corespunzătoare unor intervale de octeț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 | * ''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 ===== | ||
| Line 122: | 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 165: | 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 333: | 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 348: | 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 364: | 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 663: | 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 719: | 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 724: | 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 811: | 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 817: | 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 905: | 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 945: | 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 954: | 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 960: | 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 990: | 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 999: | 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 1013: | Line 1085: | ||
| <code java> | <code java> | ||
| - | new XkcdCartoonDisplayerAsyncTask().execute(Constants.XKCD_INTERNET_ADDRESS); | + | new XKCDCartoonDisplayerAsyncTask().execute(Constants.XKCD_INTERNET_ADDRESS); |
| </code> | </code> | ||
| Line 1020: | 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 1056: | 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: | ||
