Taula de continguts

Comunicacions en Android

Referències:

, , , , , , , , , , , , ,

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 biblioteca de codi Java WebSockets en Android caldrà afegir algunes línies als arxius:

build.gradle.kts
dependencies {
    ...
    implementation(libs.websocket)
    ...
}
libs.versions.toml
[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:

AndroidManifest.xml
<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:

Versió Kotlin

MainActivity.kt
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()
    }
}

Versió Java

MainActivity.java
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.