{"id":60,"date":"2013-04-13T03:25:29","date_gmt":"2013-04-13T02:25:29","guid":{"rendered":"http:\/\/android.wp.xpkode.com\/?p=60"},"modified":"2015-04-25T13:18:27","modified_gmt":"2015-04-25T12:18:27","slug":"ler-uma-imagem-via-http","status":"publish","type":"post","link":"http:\/\/android.w3.pt\/?p=60","title":{"rendered":"Ler uma imagem via HTTP"},"content":{"rendered":"<p>A comunica\u00e7\u00e3o HTTP no Android deve ser feita dentro de uma thread para evitar que a aplica\u00e7\u00e3o fique &#8220;presa&#8221; \u00e0 espera da resposta do servidor, n\u00e3o permitindo, durante esse tempo, que o utilizador interaja com a mesma. No entanto, neste artigo vamos solicitar uma imagem a um servidor Web dentro da thread principal. \u00c9 conveniente que a imagem seja pequena (tenha apenas alguns kb) para que a resposta do servidor n\u00e3o fa\u00e7a a aplica\u00e7\u00e3o terminar por inatividade. No <a href=\"http:\/\/android.w3.pt\/?p=105\">pr\u00f3ximo artigo sobre comunica\u00e7\u00e3o HTTP<\/a> falaremos da cria\u00e7\u00e3o de uma thread com a classe AsyncTask para implementar uma comunica\u00e7\u00e3o HTTP num ambiente mais seguro.<\/p>\n<p>Este exemplo destina-se a apresentar uma classe de comunica\u00e7\u00e3o HTTP que permite enviar pedidos via GET ou via POST a um servidor. Para o efeito, s\u00e3o usadas duas classes: HttpRequest e HttpData. A primeira implementa os m\u00e9todos de invoca\u00e7\u00e3o dos comandos GET e POST. A segunda gere a resposta do servidor que pode ser um bloco de texto ou um ficheiro bin\u00e1rio.<\/p>\n<p>Segue-se o c\u00f3digo da classe HttpRequest:<\/p>\n<pre style=\"border: 2px solid black; border-radius: 5px; box-shadow: 5px 5px 5px grey; background-color: lightyellow; margin: 10px; padding: 8px; font-family: monospace;\">\r\npackage com.se.login;\r\n\r\nimport java.net.URI;\r\nimport java.net.URISyntaxException;\r\nimport java.util.List;\r\n\r\nimport org.apache.http.HttpResponse;\r\nimport org.apache.http.HttpVersion;\r\nimport org.apache.http.NameValuePair;\r\nimport org.apache.http.client.ClientProtocolException;\r\nimport org.apache.http.client.HttpClient;\r\nimport org.apache.http.client.entity.UrlEncodedFormEntity;\r\nimport org.apache.http.client.methods.HttpGet;\r\nimport org.apache.http.client.methods.HttpPost;\r\nimport org.apache.http.impl.client.DefaultHttpClient;\r\nimport org.apache.http.params.BasicHttpParams;\r\nimport org.apache.http.params.CoreProtocolPNames;\r\nimport org.apache.http.params.HttpConnectionParams;\r\nimport org.apache.http.params.HttpParams;\r\n\r\npublic class HttpRequest {\r\n    public HttpClient httpclient;\r\n\r\n    public HttpRequest() {\r\n        HttpParams httpParameters = new BasicHttpParams();\r\n        \/\/ Set the timeout in milliseconds until a connection is established.\r\n        \/\/ The default value is zero, that means the timeout is not used.\r\n        int timeoutConnection = 30000;\r\n        HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);\r\n        \/\/ Set the default socket timeout (SO_TIMEOUT)\r\n        \/\/ in milliseconds which is the timeout for waiting for data.\r\n        int timeoutSocket = 60000;\r\n        HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);\r\n\r\n        httpclient = new DefaultHttpClient(httpParameters);\r\n        httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);\r\n    }\r\n\r\n    \/\/ Faz um pedido GET\r\n    public HttpData get(String url){\r\n        HttpData dados = new HttpData();\r\n        HttpGet request = new HttpGet();\r\n        try {\r\n            request.setURI(new URI(url));\r\n            HttpResponse resp = httpclient.execute(request);\r\n            dados.set(resp);\r\n        } catch (URISyntaxException e1) {\r\n            e1.printStackTrace();\r\n        } catch (ClientProtocolException e1) {\r\n            e1.printStackTrace();\r\n        } catch (Exception e1) {\r\n            e1.printStackTrace();\r\n        }\r\n        return dados;\r\n    }\r\n    public HttpData getImage(String url, List&lt;NameValuePair&gt; vars) {\r\n        HttpData dados = new HttpData();\r\n        HttpPost request = new HttpPost(url);\r\n        try {\r\n            request.setEntity(new UrlEncodedFormEntity(vars));\r\n            HttpResponse resp = httpclient.execute(request);\r\n            dados.setImage(resp);\r\n        } catch (ClientProtocolException e) {\r\n            e.printStackTrace();\r\n        } catch (Exception e) {\r\n            e.printStackTrace();\r\n        }\r\n        return dados;\r\n    }\r\n\r\n    \/\/ Faz um pedido via POST, com vari\u00e1veis\r\n    public HttpData post(String url, List&lt;NameValuePair&gt; vars){\r\n        HttpData dados = new HttpData();\r\n        HttpPost request = new HttpPost(url);\r\n        try {\r\n            request.setEntity(new UrlEncodedFormEntity(vars));\r\n            HttpResponse resp = httpclient.execute(request);\r\n            dados.set(resp);\r\n        } catch (ClientProtocolException e) {\r\n            e.printStackTrace();\r\n        } catch (Exception e) {\r\n            e.printStackTrace();\r\n        }\r\n        return dados;\r\n    }\r\n}\r\n<\/pre>\n<p>A classe HttpData tem o seguinte conte\u00fado:<\/p>\n<pre style=\"border: 2px solid black; border-radius: 5px; box-shadow: 5px 5px 5px grey; background-color: lightyellow; margin: 10px; padding: 8px; font-family: monospace;\">\r\npackage com.se.login;\r\n\r\nimport java.io.BufferedReader;\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.io.InputStreamReader;\r\nimport java.util.Hashtable;\r\n\r\nimport org.apache.http.Header;\r\nimport org.apache.http.HttpResponse;\r\n\r\nimport android.graphics.Bitmap;\r\nimport android.graphics.BitmapFactory;\r\nimport android.util.Log;\r\n\r\npublic class HttpData {\r\n    public String content;\r\n    public Hashtable&lt;String,String&gt; cookies;\r\n    public Hashtable&lt;String,String&gt; headers;\r\n    public int statusCode;\r\n    public Bitmap imagem;\r\n\r\n    public HttpData() {\r\n        content = \"\";\r\n        imagem = null;\r\n        cookies = new Hashtable&lt;String,String&gt;();\r\n        headers = new Hashtable&lt;String,String&gt;();\r\n        statusCode = 0;\r\n    }\r\n\r\n    public void set(HttpResponse resp) {\r\n        if(resp == null) return;\r\n        BufferedReader in = null;\r\n        try {\r\n            in = new BufferedReader(new InputStreamReader(resp.getEntity().getContent()));\r\n            StringBuffer sb = new StringBuffer(\"\");\r\n            String line = \"\";\r\n            String NL = System.getProperty(\"line.separator\");\r\n            while ((line = in.readLine()) != null) {\r\n                if(sb.length() != 0) sb.append(NL);\r\n                sb.append(line);\r\n            }\r\n            in.close();\r\n            content = sb.toString();\r\n            if(content.startsWith(\"\u00ef\u00bb\u00bf\")) content = content.substring(3);\r\n            Log.d(\"LOG\", \"HttpData.set(), tamanho de content: \" + content.length());\r\n        } catch (IllegalStateException e) {\r\n            e.printStackTrace();\r\n        } catch (IOException e) {\r\n            e.printStackTrace();\r\n        } finally {\r\n            if (in != null) {\r\n                try {\r\n                    in.close();\r\n                } catch (IOException e) {\r\n                    e.printStackTrace();\r\n                }\r\n            }\r\n\r\n        }\r\n        Header[] hds = resp.getAllHeaders();\r\n        for(Header h: hds) {\r\n            headers.put(h.getName(), h.getValue());\r\n            if (h.getName().equals(\"set-cookie\"))\r\n                cookies.put(h.getName(), h.getValue());\r\n\r\n        }\r\n        statusCode = resp.getStatusLine().getStatusCode();\r\n        Log.d(\"NET\", \"statusCode = \" + statusCode);\r\n    }\r\n\r\n    public void setImage(HttpResponse resp) {\r\n        if(resp == null) return;\r\n        InputStream in = null;\r\n        try {\r\n            in = resp.getEntity().getContent();\r\n            imagem = BitmapFactory.decodeStream(in);\r\n            Log.d(\"LOG\", \"HttpData.setImage(), tamanho de content: \" + content.length());\r\n        } catch (IllegalStateException e) {\r\n            e.printStackTrace();\r\n        } catch (IOException e) {\r\n            e.printStackTrace();\r\n        } finally {\r\n            if (in != null) {\r\n                try {\r\n                    in.close();\r\n                } catch (IOException e) {\r\n                    e.printStackTrace();\r\n                }\r\n            }\r\n        }\r\n        Header[] hds = resp.getAllHeaders();\r\n        for(Header h: hds) {\r\n            headers.put(h.getName(), h.getValue());\r\n            if (h.getName().equals(\"set-cookie\"))\r\n                cookies.put(h.getName(), h.getValue());\r\n\r\n        }\r\n        statusCode = resp.getStatusLine().getStatusCode();\r\n        Log.d(\"NET\", \"statusCode = \" + statusCode);\r\n    }\r\n}\r\n<\/pre>\n<p>Esta aplica\u00e7\u00e3o tem um layout gr\u00e1fico relativamente simples:<\/p>\n<ul>\n<li>um campo de texto para se colocar o endere\u00e7o Web de uma imagem<\/li>\n<li>um bot\u00e3o para acionar o pedido<\/li>\n<li>um campo do tipo ImageView para apresentar a imagem lida da Net.<\/li>\n<\/ul>\n<p>Segue-se o layout gr\u00e1fico :<\/p>\n<pre style=\"border: 2px solid black; border-radius: 5px; box-shadow: 5px 5px 5px grey; background-color: lightyellow; margin: 10px; padding: 8px; font-family: monospace;\">\r\n&lt;LinearLayout xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"\r\n\txmlns:tools=\"http:\/\/schemas.android.com\/tools\"\r\n\tandroid:layout_width=\"match_parent\"\r\n\tandroid:layout_height=\"match_parent\"\r\n\ttools:context=\".MainActivity\"\r\n\tandroid:orientation=\"vertical\"\r\n\t&gt;\r\n\t&lt;TextView\r\n\t\tandroid:layout_width=\"fill_parent\"\r\n\t\tandroid:layout_height=\"wrap_content\"\r\n\t\tandroid:text=\"URL da imagem:\"\r\n\t\t\/&gt;\r\n\t&lt;EditText\r\n\t\tandroid:id=\"@+id\/url\"\r\n\t\tandroid:layout_width=\"fill_parent\"\r\n\t\tandroid:layout_height=\"wrap_content\"\r\n\t\tandroid:textSize=\"20sp\"\r\n\t\t\/&gt;\r\n\t&lt;Button\r\n\t\tandroid:id=\"@+id\/botao\"\r\n\t\tandroid:layout_width=\"fill_parent\"\r\n\t\tandroid:layout_height=\"wrap_content\"\r\n\t\tandroid:text=\"Ler Imagem\"\r\n\t\tandroid:textSize=\"20sp\"\r\n\t\t\/&gt;\r\n\t&lt;ImageView\r\n\t\tandroid:id=\"@+id\/imagem\"\r\n\t\tandroid:layout_width=\"wrap_content\"\r\n\t\tandroid:layout_height=\"wrap_content\"\r\n\t\t\/&gt;\r\n&lt;\/LinearLayout&gt;\r\n<\/pre>\n<p>Para que a aplica\u00e7\u00e3o possa comunicar via HTTP, \u00e9 necess\u00e1rio adicionar \u00e0 aplica\u00e7\u00e3o a permiss\u00e3o de acesso \u00e0 Web. No ficheiro Android Manifest adicionar o c\u00f3digo seguinte antes da marca &lt;application&#8230;&gt;:<\/p>\n<pre style=\"border: 2px solid black; border-radius: 5px; box-shadow: 5px 5px 5px grey; background-color: lightyellow; margin: 10px; padding: 8px; font-family: monospace;\">\r\n&lt;uses-permission android:name=\"android.permission.INTERNET\" \/&gt;\r\n<\/pre>\n<p>O layout fica com o aspeto seguinte:<br \/>\n<a href=\"http:\/\/android.w3.pt\/?attachment_id=74\" rel=\"attachment wp-att-74\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-74\" alt=\"imagem\" src=\"http:\/\/android.w3.pt\/wp-content\/uploads\/sites\/7\/2013\/04\/imagem-180x300.png\" width=\"180\" height=\"300\" srcset=\"http:\/\/android.wp.w3.pt\/wp-content\/uploads\/sites\/7\/2013\/04\/imagem-180x300.png 180w, http:\/\/android.wp.w3.pt\/wp-content\/uploads\/sites\/7\/2013\/04\/imagem.png 480w\" sizes=\"(max-width: 180px) 100vw, 180px\" \/><\/a><\/p>\n<p>Por fim, a aplica\u00e7\u00e3o principal tem o c\u00f3digo abaixo:<\/p>\n<pre style=\"border: 2px solid black; border-radius: 5px; box-shadow: 5px 5px 5px grey; background-color: lightyellow; margin: 10px; padding: 8px; font-family: monospace;\">\r\npackage com.example.imagem;\r\n\r\nimport android.os.Bundle;\r\nimport android.os.StrictMode;\r\nimport android.os.StrictMode.ThreadPolicy;\r\nimport android.app.Activity;\r\nimport android.view.Menu;\r\nimport android.view.View;\r\nimport android.widget.Button;\r\nimport android.widget.EditText;\r\nimport android.widget.ImageView;\r\n\r\npublic class MainActivity extends Activity {ImageView imagem;\r\n\tEditText url;\r\n\tButton botao;\r\n\r\n\t@Override\r\n\tprotected void onCreate(Bundle savedInstanceState) {\r\n\t\tThreadPolicy tp = ThreadPolicy.LAX;\r\n\t\tStrictMode.setThreadPolicy(tp);\r\n\t\tsuper.onCreate(savedInstanceState);\r\n\t\tsetContentView(R.layout.main);\r\n\r\n\t\timagem = (ImageView) findViewById(R.id.imagem);\r\n\t\turl = (EditText) findViewById(R.id.url);\r\n\t\tbotao = (Button) findViewById(R.id.botao);\r\n\r\n\t\tbotao.setOnClickListener( new View.OnClickListener() {\r\n\t\t\tpublic void onClick(View v) {\r\n\t\t\t\tString sUrl = url.getText().toString();\r\n\t\t\t\tHttpRequest req = new HttpRequest();\r\n\t\t\t\tHttpData dados = req.getImage(sUrl);\r\n\t\t\t\timagem.setImageBitmap(dados.imagem);\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n}\r\n<\/pre>\n<p>As duas primeiras linhas da fun\u00e7\u00e3o onCreate servem para permitir a comunica\u00e7\u00e3o HTTP dentro da thread principal. S\u00e3o as seguintes:<\/p>\n<p>ThreadPolicy tp = ThreadPolicy.LAX;<br \/>\nStrictMode.setThreadPolicy(tp);<\/p>\n<p>Nas primeiras vers\u00f5es do sistema operativo Android era poss\u00edvel executar um pedido HTTP dentro da thread principal. Atualmente isso gera uma exce\u00e7\u00e3o do tipo <em>android.os.NetworkOnMainThreadException<\/em>. Estas duas linhas permitem uma pol\u00edtica\u00a0 de utiliza\u00e7\u00e3o de threads mais permissiva e evitam a ocorr\u00eancia da exce\u00e7\u00e3o. Num artigo pr\u00f3ximo, esta situa\u00e7\u00e3o ser\u00e1 resolvida invocando o pedido HTTP dentro de uma nova thread com a classe AsyncTask.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A comunica\u00e7\u00e3o HTTP no Android deve ser feita dentro de uma thread para evitar que a aplica\u00e7\u00e3o fique &#8220;presa&#8221; \u00e0 espera da resposta do servidor, n\u00e3o permitindo, durante esse tempo, que o utilizador interaja com a mesma. No entanto, neste artigo vamos solicitar uma imagem a um servidor Web dentro da thread principal. \u00c9 conveniente [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"_links":{"self":[{"href":"http:\/\/android.w3.pt\/index.php?rest_route=\/wp\/v2\/posts\/60"}],"collection":[{"href":"http:\/\/android.w3.pt\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/android.w3.pt\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/android.w3.pt\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/android.w3.pt\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=60"}],"version-history":[{"count":24,"href":"http:\/\/android.w3.pt\/index.php?rest_route=\/wp\/v2\/posts\/60\/revisions"}],"predecessor-version":[{"id":135,"href":"http:\/\/android.w3.pt\/index.php?rest_route=\/wp\/v2\/posts\/60\/revisions\/135"}],"wp:attachment":[{"href":"http:\/\/android.w3.pt\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=60"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/android.w3.pt\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=60"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/android.w3.pt\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=60"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}