{"id":332,"date":"2013-06-23T16:02:03","date_gmt":"2013-06-23T15:02:03","guid":{"rendered":"http:\/\/chezdom.net\/etu\/?p=332"},"modified":"2013-06-25T13:49:24","modified_gmt":"2013-06-25T12:49:24","slug":"tp-android-des-sockets","status":"publish","type":"post","link":"https:\/\/chezdom.net\/etu\/2013\/06\/23\/tp-android-des-sockets\/","title":{"rendered":"TP 4 : Android et les sockets"},"content":{"rendered":"<p>On veut interroger le serveur de date r\u00e9alis\u00e9 plus t\u00f4t.<\/p>\n<p>1. Cr\u00e9ez un projet appropri\u00e9 dans eclipse, puis une interface comportant un TextView dans lequel on \u00e9crira le r\u00e9sultat &#8211; la date envoy\u00e9e par le serveur (ou un message d&rsquo;erreur), et un bouton permettant de lancer une requ\u00eate sur le serveur.<\/p>\n<p>Attention, le syst\u00e8me Android n\u00e9cessite dispose d&rsquo;un m\u00e9canisme de permission, cens\u00e9 pr\u00e9venir l&rsquo;utilisateur lorsque des op\u00e9rations sensibles, telles que l&rsquo;acc\u00e8s au r\u00e9seau ou \u00e0 la m\u00e9moire de masse, ou l&rsquo;acc\u00e8s aux capteurs, sont r\u00e9alis\u00e9es. Notre application doit utiliser un service r\u00e9seau, il faut donc lui en donner la permission dans le fichier AndroidManifest.xml (\u00e0 trouvez dans le projet). Ins\u00e9rez la ligne suivante apr\u00e8s celle qui d\u00e9finit les sdk utilis\u00e9s.<\/p>\n<pre class=\"brush: xml; gutter: true; first-line: 1; highlight: []; html-script: false\">    &lt;uses-permission android:name=&quot;android.permission.INTERNET&quot;\/&gt;<\/pre>\n<p>2. Impl\u00e9mentez le traitement du bouton de requ\u00eate (reprenez le code du client r\u00e9alis\u00e9 lors du TP 2).<br \/>\n<strong>Que se passe-t-il ?<\/strong><\/p>\n<p>3. Si cela n&rsquo;a pas march\u00e9, c&rsquo;est parce que le syst\u00e8me Android impose que les appels r\u00e9seau soient pass\u00e9s dans un thread s\u00e9par\u00e9 du thread principal. Modifiez votre code pour d\u00e9placer l&rsquo;ouverture du socket, la lecture et sa fermeture dans un thread s\u00e9par\u00e9. <strong>Que se passe-t-il maintenant ?<\/strong><\/p>\n<p>4. Vous devez trouver une exception de type \u00ab\u00a0<strong>android.view.ViewRoot$CalledFromWrongThreadException<\/strong>\u00a0\u00bb avec le message \u00ab\u00a0<em>Only the original thread that created a view hierarchy can touch its views.<\/em>\u00ab\u00a0. Cela signifie que le thread qui g\u00e8re le socket ne peut pas \u00e9crire dans l&rsquo;interface graphique, qui est g\u00e9r\u00e9e par un autre Thread. On va devoir utiliser un syst\u00e8me d&rsquo;envoi de message. Le principe est de cr\u00e9er un objet de type handle qui va faire l&rsquo;interm\u00e9diaire entre les 2. Le thread qui g\u00e8re les socket va envoyer un message par l&rsquo;interm\u00e9diaire de ce handle, et celui ci va le renvoyer au thread qui g\u00e8re l&rsquo;interface graphique.<\/p>\n<p>Pour cela on va d\u00e9clare un objet handler, en surchargeant la m\u00e9thode handleMessage de la classe Handler afin de lui faire r\u00e9aliser le traitement voulu (ici afficheur.setText(text);).<\/p>\n<pre class=\"brush: java; gutter: false; first-line: 1; highlight: []; html-script: false\">mHandler = new Handler() {\r\n    @Override\r\n    public void handleMessage(Message msg) {\r\n        String text = (String)msg.obj;\r\n        afficheur.setText(text);\r\n    }\r\n};<\/pre>\n<p>Ensuite lorsque dans le thread qui g\u00e8re le socket on va utiliser :<\/p>\n<pre class=\"brush: java; gutter: false; first-line: 1; highlight: []; html-script: false\">Message msg = new Message();\r\nmsg.obj = answer;\r\nmHandler.sendMessage(msg);<\/pre>\n<p>On cr\u00e9e ici un message, on y copie la cha\u00eene \u00e0 transmettre, et on envoie le message au handler.<\/p>\n<p>Voici le code complet de la classe :<\/p>\n<pre class=\"brush: java; gutter: true; first-line: 1; highlight: []; html-script: false\">import java.io.BufferedReader;\r\nimport java.io.IOException;\r\nimport java.io.InputStreamReader;\r\nimport java.net.Socket;\r\n\r\nimport android.os.Bundle;\r\nimport android.os.Handler;\r\nimport android.os.Message;\r\nimport android.app.Activity;\r\nimport android.graphics.Color;\r\nimport android.view.Menu;\r\nimport android.view.View;\r\nimport android.view.View.OnClickListener;\r\nimport android.widget.Button;\r\nimport android.widget.EditText;\r\nimport android.widget.TextView;\r\n\r\npublic class GetDateAppActivity extends Activity implements OnClickListener, Runnable {\r\n\r\n\tprivate static int DEFAULTPORT = 9090;\r\n\tprivate static String DEFAULTSERVER = &quot;ouessant.univ-paris8.fr&quot;;\r\n\t\r\n\tprivate int portNumber; \r\n\tprivate String serverName;\r\n\t\r\n\tprivate TextView afficheur;\r\n\tprivate Handler mHandler;\r\n\tprivate EditText serverField, portField;\r\n\t\r\n\t@Override\r\n\tprotected void onCreate(Bundle savedInstanceState) {\r\n\t\tsuper.onCreate(savedInstanceState);\r\n\t\tsetContentView(R.layout.getdateapp_activity);\r\n\t\t\r\n\t\tportNumber=DEFAULTPORT;\r\n\t\tserverName=DEFAULTSERVER;\r\n\t\t\r\n\t\tButton t=(Button) this.findViewById(R.id.button1);\r\n\t\tt.setTextColor(Color.RED);\r\n\t\tt.setOnClickListener(this);\r\n\t\t\r\n\t\tafficheur=(TextView) this.findViewById(R.id.textView1);\r\n\t\tserverField=(EditText)this.findViewById(R.id.editText1);\r\n\t\tportField=(EditText)this.findViewById(R.id.editText2);\r\n\t\t\t\t\r\n\t\tmHandler = new Handler() {\r\n\t\t\t@Override\r\n\t        public void handleMessage(Message msg) {\r\n\t\t\t\tString text = (String)msg.obj;\r\n\t\t\t\tafficheur.setText(text);\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\t@Override\r\n\tpublic boolean onCreateOptionsMenu(Menu menu) {\r\n\t\t\/\/ Inflate the menu; this adds items to the action bar if it is present.\r\n\t\tgetMenuInflater().inflate(R.menu.activity_main, menu);\r\n\t\treturn true;\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void onClick(View v) {\r\n\t\tif (v.getId()==R.id.button1) {\r\n\t\t\tthis.serverName=this.serverField.getText().toString();\r\n\t\t\tthis.portNumber=Integer.parseInt(this.portField.getText().toString());\r\n\t\t\tnew Thread(this).start();\r\n\t\t\t\t\t\t\r\n\t\t}\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void run() {\r\n\t\tSocket s=null;\r\n\t\ttry {\r\n\t\t\ts = new Socket(serverName, portNumber);\r\n\t\t} catch (IOException e) {\r\n\t\t\t\r\n\t\t\t\/\/afficheur.setText(&quot;Cannot connect to &quot;+server+&quot; on port &quot;+port);\r\n\t\t\tMessage msg = new Message();\r\n\t\t\tmsg.obj = &quot;Cannot connect to &quot;+serverName+&quot; on port &quot;+portNumber;\r\n\t\t\tmHandler.sendMessage(msg);\r\n\t\t}\r\n\r\n\t\tif (s!=null) {\r\n\t\t\tBufferedReader input;\r\n\t\t\ttry {\r\n\t\t\t\tinput = new BufferedReader(new InputStreamReader(s.getInputStream()));\r\n\t\t\t\tString answer = input.readLine();\r\n\t\r\n\t\t\t\t\/\/afficheur.setText(answer);\r\n\t\t\t\tMessage msg = new Message();\r\n\t\t\t\tmsg.obj = answer;\r\n\t\t\t\tmHandler.sendMessage(msg);\r\n\t\t\t\t\r\n\t\t\t\tinput.close();\r\n\t\t\t\ts.close();\r\n\t\t\t} catch (IOException e) {\r\n\t\t\t\te.printStackTrace();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\r\n}<\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>On veut interroger le serveur de date r\u00e9alis\u00e9 plus t\u00f4t. 1. Cr\u00e9ez un projet appropri\u00e9 dans eclipse, puis une interface comportant un TextView dans lequel on \u00e9crira le r\u00e9sultat &#8211; la date envoy\u00e9e par le serveur (ou un message d&rsquo;erreur),<span class=\"ellipsis\">&hellip;<\/span> <span class=\"read-more\"><a href=\"https:\/\/chezdom.net\/etu\/2013\/06\/23\/tp-android-des-sockets\/\">Lire la suite &#8250;<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"footnotes":""},"categories":[10],"tags":[],"class_list":["post-332","post","type-post","status-publish","format-standard","hentry","category-nouakchott"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p9qu1A-5m","_links":{"self":[{"href":"https:\/\/chezdom.net\/etu\/wp-json\/wp\/v2\/posts\/332","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/chezdom.net\/etu\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/chezdom.net\/etu\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/chezdom.net\/etu\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/chezdom.net\/etu\/wp-json\/wp\/v2\/comments?post=332"}],"version-history":[{"count":5,"href":"https:\/\/chezdom.net\/etu\/wp-json\/wp\/v2\/posts\/332\/revisions"}],"predecessor-version":[{"id":347,"href":"https:\/\/chezdom.net\/etu\/wp-json\/wp\/v2\/posts\/332\/revisions\/347"}],"wp:attachment":[{"href":"https:\/\/chezdom.net\/etu\/wp-json\/wp\/v2\/media?parent=332"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/chezdom.net\/etu\/wp-json\/wp\/v2\/categories?post=332"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/chezdom.net\/etu\/wp-json\/wp\/v2\/tags?post=332"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}