Ejemplos de WebSockets de Android
WebSocket es un protocolo que permite abrir una sesión de comunicación interactiva bidireccional entre el cliente y el servidor. Proporciona canales de comunicación full-duplex a través de una única conexión TCP.
Este protocolo define una API que establece una conexión de "socket" entre un navegador web y un servidor. En lugar de largos sondeos para obtener actualizaciones, por ejemplo, de una aplicación de puntuación en vivo, puede usar websockets para crear una conexión persistente entre el cliente y el servidor. Por lo tanto, la aplicación se actualiza automáticamente cada vez que hay actualizaciones disponibles.
Esto evita la sobrecarga de enviar una solicitud HTTP adicional para verificar si hay actualizaciones más recientes.
Por lo tanto, el cliente y el servidor solo necesitan completar un apretón de manos, y se puede crear una conexión persistente directamente entre los dos y realizar una transferencia de datos bidireccional.

Websocket usa el mismo puerto TCP que HTTP, que puede eludir la mayoría de las restricciones de firewall. De forma predeterminada, el protocolo Websocket utiliza el puerto 80; cuando se ejecuta sobre TLS, el puerto 443 se usa de manera predeterminada. Su identificador de protocolo es ws. Si se usa wss para el cifrado, la dirección web del servidor es una URL, como:
ws://www.example.com/
wss://www.example.com/
Ventajas de Websocket
- Menos sobrecarga de control: después de crear la conexión, cuando se intercambian datos entre el servidor y el cliente, el encabezado del paquete de datos utilizado para el control del protocolo es relativamente pequeño
- Mayor rendimiento en tiempo real: dado que el protocolo es full-duplex, el servidor puede enviar datos de forma activa al cliente en cualquier momento
- Mantener el estado de la conexión: a diferencia de HTTP, Websocket necesita crear una conexión primero, lo que lo convierte en un protocolo con estado, y luego se puede omitir parte de la información del estado al comunicarse. Es posible que la solicitud HTTP deba llevar información de estado en cada solicitud (como autenticación de identidad, etc.)
- Mejor soporte binario: Websocket define marcos binarios, que pueden manejar contenido binario más fácilmente que HTTP
- Mejor efecto de compresión: en comparación con la compresión HTTP, Websocket puede usar el contexto del contenido anterior con el soporte de extensión adecuado y puede mejorar significativamente la tasa de compresión al transferir datos similares.
Ejemplo 1: Ejemplo de WebSockets de Android
En este tutorial aprenderá a usar websockets usando OkHTTP. La url (ws://echo.websocket.org) se utiliza para configurar websockets.
Paso 1: Instalar Okhttp
En su build.gradle a nivel de aplicación, agregue la siguiente declaración de implementación:
implementation 'com.squareup.okhttp3:okhttp:3.6.0'
Paso 2: Agregar permiso de Internet
En su manifiesto de Android, agregue el permiso de Internet de la siguiente manera:
<uses-permission android:name="android.permission.INTERNET"/>
Paso 3: diseño de diseño
Cree un diseño con una vista de texto y un botón. La vista de texto mostrará el resultado del servidor. El botón por otro lado iniciará la conexión:
actividad_principal.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/buttonSend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="SEND"
android:layout_marginTop="60dp"
android:textSize="20sp"/>
<TextView
android:id="@+id/textResult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/buttonSend"
android:layout_centerHorizontal="true"
android:textSize="18sp"
android:layout_marginTop="40dp"/>
</RelativeLayout>
Paso 4: escribir código
Comience creando un método auxiliar para imprimir el resultado del servidor en una vista de texto. Esto se hace en el subproceso de la interfaz de usuario:
private void print(final String message) {
runOnUiThread(new Runnable() {
@Override
public void run() {
textResult.setText(textResult.getText().toString() + "\n" + message);
}
});
}
Cree un EchoWebListener como una clase interna. Esta clase extenderá el WebSocketListener:
private final class EchoWebSocketListener extends WebSocketListener {
private static final int CLOSE_STATUS = 1000;
@Override
public void onOpen(WebSocket webSocket, Response response) {
webSocket.send("What's up ?");
webSocket.send(ByteString.decodeHex("abcd"));
webSocket.close(CLOSE_STATUS, "Socket Closed !!");
}
@Override
public void onMessage(WebSocket webSocket, String message) {
print("Receive Message: " + message);
}
@Override
public void onMessage(WebSocket webSocket, ByteString bytes) {
print("Receive Bytes : " + bytes.hex());
}
@Override
public void onClosing(WebSocket webSocket, int code, String reason) {
webSocket.close(CLOSE_STATUS, null);
print("Closing Socket : " + code + " / " + reason);
}
@Override
public void onFailure(WebSocket webSocket, Throwable throwable, Response response) {
print("Error : " + throwable.getMessage());
}
}
El siguiente método iniciará la conexión websocket. Se crea una instancia de la clase de solicitud OkHTTP y la URL se pasa al método url(). Luego cree una instancia de EchoWebSocketListener y pase tanto el objeto Request como la instancia de EchoWebListener al método newWebSocket().
Aquí está el método completo:
private void start() {
Request request = new Request.Builder().url("ws://echo.websocket.org").build();
EchoWebSocketListener listener = new EchoWebSocketListener();
WebSocket webSocket = mClient.newWebSocket(request, listener);
mClient.dispatcher().executorService().shutdown();
}
Aquí está el código completo:
ActividadPrincipal.java
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;
public class MainActivity extends AppCompatActivity {
private Button buttonSend;
private TextView textResult;
private OkHttpClient mClient;
private final class EchoWebSocketListener extends WebSocketListener {
private static final int CLOSE_STATUS = 1000;
@Override
public void onOpen(WebSocket webSocket, Response response) {
webSocket.send("What's up ?");
webSocket.send(ByteString.decodeHex("abcd"));
webSocket.close(CLOSE_STATUS, "Socket Closed !!");
}
@Override
public void onMessage(WebSocket webSocket, String message) {
print("Receive Message: " + message);
}
@Override
public void onMessage(WebSocket webSocket, ByteString bytes) {
print("Receive Bytes : " + bytes.hex());
}
@Override
public void onClosing(WebSocket webSocket, int code, String reason) {
webSocket.close(CLOSE_STATUS, null);
print("Closing Socket : " + code + " / " + reason);
}
@Override
public void onFailure(WebSocket webSocket, Throwable throwable, Response response) {
print("Error : " + throwable.getMessage());
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonSend = (Button) findViewById(R.id.buttonSend);
textResult = (TextView) findViewById(R.id.textResult);
mClient = new OkHttpClient();
buttonSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
start();
}
});
}
private void start() {
Request request = new Request.Builder().url("ws://echo.websocket.org").build();
EchoWebSocketListener listener = new EchoWebSocketListener();
WebSocket webSocket = mClient.newWebSocket(request, listener);
mClient.dispatcher().executorService().shutdown();
}
private void print(final String message) {
runOnUiThread(new Runnable() {
@Override
public void run() {
textResult.setText(textResult.getText().toString() + "\n" + message);
}
});
}
}
Referencia
A continuación se muestra el enlace de descarga.
| nº | Enlace |
|---|---|
| 1. | Descargar código |
| 2. | Seguir autor del código |
Ejemplo 2: Ejemplo de Kotlin Android Websocket con Okhttp
Aquí hay otro ejemplo de websocket de Android, pero esta vez escrito en Kotlin. Todavía usa OkHttp como biblioteca de red.
Paso 1: Crear proyecto
Comience creando un proyecto Android Studio vacío.
Paso 2: Dependencias
Instalaremos dos bibliotecas OkHttp:
implementation 'com.squareup.okhttp3:okhttp:3.12.6'
implementation 'com.squareup.okhttp3:mockwebserver:3.12.1'
Agréguelos en su app/build.gradle y sincronice.
Paso 3: diseño de diseño
En el diseño de su 'MainActivity', agregue varios botones y un texto de edición como se muestra a continuación:
actividad_principal.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/connectBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginEnd="20dp"
android:layout_marginRight="20dp"
android : text = " Connect "
app:layout_constraintRight_toLeftOf="@+id/clientSendBtn"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/clientSendBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android : text = " Send from the client "
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/closeConnectionBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="10dp"
android : text = " Client is closed "
app:layout_constraintLeft_toRightOf="@+id/clientSendBtn"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/contentEt"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:background="@color/colorGray"
android:enabled="false"
android:gravity="top"
android:padding="5dp"
android:textColor="@color/colorWhite"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/clientSendBtn"
app:layout_constraintVertical_weight="1" />
</androidx.constraintlayout.widget.ConstraintLayout>
Paso 4: crear un detector de mensajes
Esta será una interfaz con varias devoluciones de llamadas según el estado de la conexión, por ejemplo, cuando se conectó correctamente, se cerró, falló, etc.:
MessageListener.kt
interface MessageListener {
fun onConnectSuccess () // successfully connected
fun onConnectFailed () // connection failed
fun onClose () // close
fun onMessage(text: String?)
}
Paso 5: Cree un administrador de Websocket
Crear un WebSocketManager.kt luego comience agregando las siguientes importaciones:
import android.util.Log
import okhttp3.*
import okio.ByteString
import java.util.concurrent.TimeUnit
Cree una clase de objeto WebSocketManager con los siguientes campos privados;
object WebSocketManager {
private val TAG = WebSocketManager::class.java.simpleName
private const val MAX_NUM = 5 // Maximum number of reconnections
private const val MILLIS = 5000 // Reconnection interval, milliseconds
private lateinit var client: OkHttpClient
private lateinit var request: Request
private lateinit var messageListener: MessageListener
private lateinit var mWebSocket: WebSocket
private var isConnect = false
private var connectNum = 0
Luego, la función init, pasa la url y el MessageListener. Inicializas el cliente OkHTTP aquí:
fun init(url: String, _messageListener: MessageListener) {
client = OkHttpClient.Builder()
.writeTimeout(5, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.connectTimeout(10, TimeUnit.SECONDS)
.build()
request = Request.Builder().url(url).build()
messageListener = _messageListener
}
Ahora crea una función para conectar:
fun connect() {
if (isConnect()) {
Log.i(TAG, "web socket connected")
return
}
client.newWebSocket(request, createListener())
}
También crea una función para volver a conectar:
fun reconnect() {
if (connectNum <= MAX_NUM) {
try {
Thread.sleep(MILLIS.toLong())
connect()
connectNum++
} catch (e: InterruptedException) {
e.printStackTrace ()
}
} else {
Log.i(
TAG,
"reconnect over $MAX_NUM,please check url or network"
)
}
}
También tendremos funciones para enviar un mensaje:
fun sendMessage(text: String): Boolean {
return if (!isConnect()) false else mWebSocket.send(text)
}
fun sendMessage(byteString: ByteString): Boolean {
return if (!isConnect()) false else mWebSocket.send(byteString)
}
Y una función para cerrar la conexión:
fun close() {
if (isConnect()) {
mWebSocket.cancel()
mWebSocket.close( 1001 , "The client actively closes the connection " )
}
}
Aquí está el código completo:
WebSocketManager.kt
import android.util.Log
import okhttp3.*
import okio.ByteString
import java.util.concurrent.TimeUnit
object WebSocketManager {
private val TAG = WebSocketManager::class.java.simpleName
private const val MAX_NUM = 5 // Maximum number of reconnections
private const val MILLIS = 5000 // Reconnection interval, milliseconds
private lateinit var client: OkHttpClient
private lateinit var request: Request
private lateinit var messageListener: MessageListener
private lateinit var mWebSocket: WebSocket
private var isConnect = false
private var connectNum = 0
fun init(url: String, _messageListener: MessageListener) {
client = OkHttpClient.Builder()
.writeTimeout(5, TimeUnit.SECONDS)
.readTimeout(5, TimeUnit.SECONDS)
.connectTimeout(10, TimeUnit.SECONDS)
.build()
request = Request.Builder().url(url).build()
messageListener = _messageListener
}
/**
* connect
*/
fun connect() {
if (isConnect()) {
Log.i(TAG, "web socket connected")
return
}
client.newWebSocket(request, createListener())
}
/**
* Reconnection
*/
fun reconnect() {
if (connectNum <= MAX_NUM) {
try {
Thread.sleep(MILLIS.toLong())
connect()
connectNum++
} catch (e: InterruptedException) {
e.printStackTrace ()
}
} else {
Log.i(
TAG,
"reconnect over $MAX_NUM,please check url or network"
)
}
}
/**
* Whether to connect
*/
fun isConnect(): Boolean {
return isConnect
}
/**
* send messages
*
* @param text string
* @return boolean
*/
fun sendMessage(text: String): Boolean {
return if (!isConnect()) false else mWebSocket.send(text)
}
/**
* send messages
*
* @param byteString character set
* @return boolean
*/
fun sendMessage(byteString: ByteString): Boolean {
return if (!isConnect()) false else mWebSocket.send(byteString)
}
/**
* Close connection
*/
fun close() {
if (isConnect()) {
mWebSocket.cancel()
mWebSocket.close( 1001 , "The client actively closes the connection " )
}
}
private fun createListener(): WebSocketListener {
return object : WebSocketListener() {
override fun onOpen(
webSocket: WebSocket,
response: Response
) {
super.onOpen(webSocket, response)
Log.d(TAG, "open:$response")
mWebSocket = webSocket
isConnect = response.code() == 101
if (!isConnect) {
reconnect()
} else {
Log.i(TAG, "connect success.")
messageListener.onConnectSuccess()
}
}
override fun onMessage(webSocket: WebSocket, text: String) {
super.onMessage(webSocket, text)
messageListener.onMessage(text)
}
override fun onMessage(webSocket: WebSocket, bytes: ByteString) {
super.onMessage(webSocket, bytes)
messageListener.onMessage(bytes.base64())
}
override fun onClosing(
webSocket: WebSocket,
code: Int,
reason: String
) {
super.onClosing(webSocket, code, reason)
isConnect = false
messageListener.onClose()
}
override fun onClosed(
webSocket: WebSocket,
code: Int,
reason: String
) {
super.onClosed(webSocket, code, reason)
isConnect = false
messageListener.onClose()
}
override fun onFailure(
webSocket: WebSocket,
t: Throwable,
response: Response?
) {
super.onFailure(webSocket, t, response)
if (response != null) {
Log.i(
TAG,
"connect failed:" + response.message()
)
}
Log.i(
TAG,
"connect failed throwable:" + t.message
)
isConnect = false
messageListener.onConnectFailed()
reconnect()
}
}
}
}
Paso 6: Escriba el código de MainActivity
Aquí está el código completo para MainActivity:
Actividad principal.kt
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import kotlin.concurrent.thread
class MainActivity : AppCompatActivity(), MessageListener {
private val serverUrl = "ws://192.168.18.145:8086/socketServer/abc"
override fun onCreate(savedInstanceState: Bundle?) {
super .onCreate (savedInstanceState)
setContentView(R.layout.activity_main)
WebSocketManager.init(serverUrl, this)
connectBtn.setOnClickListener {
thread {
kotlin.run {
WebSocketManager.connect()
}
}
}
clientSendBtn.setOnClickListener {
if ( WebSocketManager .sendMessage( " Client send " )) {
addText( " Send from the client \n " )
}
}
closeConnectionBtn.setOnClickListener {
WebSocketManager.close()
}
}
override fun onConnectSuccess() {
addText( " Connected successfully \n " )
}
override fun onConnectFailed() {
addText( " Connection failed \n " )
}
override fun onClose() {
addText( " Closed successfully \n " )
}
override fun onMessage(text: String?) {
addText( " Receive message: $text \n " )
}
private fun addText(text: String?) {
runOnUiThread {
contentEt.text.append(text)
}
}
override fun onDestroy() {
super .onDestroy ()
WebSocketManager.close()
}
}
Correr
Copie el código o descárguelo en el enlace a continuación, compilar y ejecutar.
Referencia
Aquí están los enlaces de referencia:
| Número | Enlace |
|---|---|
| 1. | Descargar Ejemplo |
| 2. | Seguir autor del código |