====== Comunicacions en Android ====== {{ android:android-networking-intro.png?400 }} Referències: * [[Android]]: article general d'Android * [[Android Threads]]: s'hi treballa connexions REST HTTP * [[Android ListView]] {{tag> #Dam #DamMp08 #DamMp08Uf01 #DamMp08Uf1 #DamMp08Uf02 #DamMp08Uf2 #DamMp09 #DamMp09Uf02 #DamMp09Uf2 android threads mobile java kotlin }} ===== Comunicacions REST HTTP ===== Les comunicacions de les APIs habituals es solen fer amb HTTP/HTTPS. El problema habitual sol ser que aquestes crides de xarxa bloquegen el fil d'execució fins que es reben les dades. Això no es pot fer al fil d'execució principal, main o UI Thread. Serà imprescindible, doncs, emprar les llibreries de //threading// per executar les operacions de xarxa en un fil paral·lel. A l'article [[Android Threads]] s'explica com realitzar aquest tipus d'accés HTTP a APIs externes. \\ ===== Android i WebSockets ===== Per a WebSockets, la implementació de la llibreria ja és asíncrona, pel què podem cridar el mètode ''connect()'' i aquest ja gestiona l'execució d'un //thread// paral·lel que cridarà les //callbacks// en cas d'arribada de missatges ''onMessage()'' o finalització de la comunicació ''onClose()''. Per poder emprar la [[https://github.com/TooTallNate/Java-WebSocket|biblioteca de codi Java WebSockets]] en Android caldrà afegir algunes línies als arxius: dependencies { ... implementation(libs.websocket) ... } [versions] ... websocket = "1.5.7" [libraries] ... websocket = { group = 'org.java-websocket', name = "Java-WebSocket", version.ref = "websocket" } Recordem que per poder-se connectar a internet, cal [[https://developer.android.com/training/basics/network-ops/connecting|activar el permís Android d'accés a Internet]]: Un cop fet tot això podrem emprar les biblioteques WebSockets al nostre codi: class MainActivity : AppCompatActivity() { // "inner" és important per accedir als mètodes de MainActivity inner class MyWebSocketClient(serverUri: URI) : WebSocketClient(serverUri) { override fun onOpen(handshakedata: ServerHandshake?) { println("✅ Connectat al servidor") println("🔗 Codi d'estat: ${handshakedata?.httpStatus}") println("📝 Descripció: ${handshakedata?.httpStatusMessage}") } override fun onMessage(message: String?) { println("📥 Rebut: $message") // crides segures a la GUI (main thread) runOnUiThread { val tv = findViewById(R.id.textView) tv.text = "Nou missatge: $message" } } override fun onClose(code: Int, reason: String?, remote: Boolean) { println("🔌 Connexió tancada") println("📋 Codi: $code, Raó: $reason, Remote: $remote") } override fun onError(ex: Exception?) { println("❌ Error: ${ex?.message}") ex?.printStackTrace() } } fun connectaWS() { val uri = URI("ws://server.domini.tld") // utilitzeu wss:// si va sobre HTTPS var wsclient = MyWebSocketClient(uri) wsclient.connect() } } import org.java_websocket.client.WebSocketClient; import org.java_websocket.drafts.Draft_6455; import org.java_websocket.handshake.ServerHandshake; ... WebSocketClient client = null; URI location = "ws://mywsserver.com"; try { client = new WebSocketClient(new URI(location), (Draft) new Draft_6455()); client.connect(); } catch (URISyntaxException e) { e.printStackTrace(); System.out.println("Error: " + location + " no és una direcció URI de WebSocket vàlida"); } client.send("Hola! M'acabo de connectar"); ... **Main thread i network thread** Recordeu (com s'explica a [[Android Threads]]) que no es poden dur a terme accions de xarxa en el //main thread// que és el de la GUI. L'objecte ''WebSocketClient'' facilita la gestió del //thread// de comunicació alternatiu o //network thread// (no caldrà que el creem explícitament i podem emprar directament les //callbacks// com ''onMessage''). Per actuar, en canvi, sobre la GUI cal fer-ho des del //main thread// de nou. En aquest cas ho resolem amb la funció ''runOnUiThread''. Teniu més explicacions i exemples de WebSockets a la pàgina [[WebSockets Java]] d'aquesta wiki.