Referències:
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.
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 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 activar el permís Android d'accés a Internet:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
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<TextView>(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.