Android WebSocket工具类:重连、心跳、消息队列一站式办理方案

[复制链接]
发表于 2025-10-19 01:41:02 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

  • 依赖库
    使用 OkHttp 的WebSocket支持。
在 build.gradle 中添加依赖:
  1. implementation 'com.squareup.okhttp3:okhttp:4.9.3'
复制代码

  • WebSocket工具类实现
  1. import okhttp3.*;
  2. import android.os.Handler;
  3. import android.os.Looper;
  4. import android.util.Log;
  5. import java.util.concurrent.ConcurrentLinkedQueue;
  6. import java.util.concurrent.ExecutorService;
  7. import java.util.concurrent.Executors;
  8. import java.util.concurrent.TimeUnit;
  9. import java.util.concurrent.atomic.AtomicInteger;
  10. public class WebSocketManager {
  11.     private static final String TAG = "WebSocketManager";
  12.     private OkHttpClient client;
  13.     private WebSocket webSocket;
  14.     private String wsUrl;
  15.     private AtomicInteger reconnectCount = new AtomicInteger(0);
  16.     private boolean isConnecting = false;
  17.     private boolean isConnected = false;
  18.     private Handler mainHandler = new Handler(Looper.getMainLooper());
  19.     private Runnable heartbeatRunnable;
  20.     private ConcurrentLinkedQueue<String> messageQueue = new ConcurrentLinkedQueue<>(); // 线程安全的消息队列
  21.     private ExecutorService executorService = Executors.newSingleThreadExecutor(); // 线程池
  22.     private int maxReconnectCount = 5; // 最大重连次数
  23.     private long reconnectInterval = 5000; // 重连间隔时间(毫秒)
  24.     private long heartbeatInterval = 30000; // 心跳间隔时间(毫秒)
  25.     private long heartbeatTimeout = 60000; // 心跳超时时间(毫秒)
  26.     private WebSocketCallback callback;
  27.     private WebSocketListener webSocketListener = new WebSocketListener() {
  28.         @Override
  29.         public void onOpen(WebSocket webSocket, Response response) {
  30.             Log.d(TAG, "WebSocket connected");
  31.             isConnecting = false;
  32.             isConnected = true;
  33.             reconnectCount.set(0); // 重置重连次数
  34.             startHeartbeat(); // 开始心跳
  35.             sendQueuedMessages(); // 发送缓存的消息
  36.             if (callback != null) {
  37.                 mainHandler.post(() -> callback.onConnected());
  38.             }
  39.         }
  40.         @Override
  41.         public void onMessage(WebSocket webSocket, String text) {
  42.             Log.d(TAG, "Received message: " + text);
  43.             if (callback != null) {
  44.                 mainHandler.post(() -> callback.onMessage(text));
  45.             }
  46.         }
  47.         @Override
  48.         public void onClosed(WebSocket webSocket, int code, String reason) {
  49.             Log.d(TAG, "WebSocket closed: " + reason);
  50.             isConnecting = false;
  51.             isConnected = false;
  52.             stopHeartbeat(); // 停止心跳
  53.             if (callback != null) {
  54.                 mainHandler.post(() -> callback.onDisconnected());
  55.             }
  56.         }
  57.         @Override
  58.         public void onFailure(WebSocket webSocket, Throwable t, Response response) {
  59.             Log.e(TAG, "WebSocket failed: " + t.getMessage());
  60.             isConnecting = false;
  61.             isConnected = false;
  62.             stopHeartbeat(); // 停止心跳
  63.             if (callback != null) {
  64.                 mainHandler.post(() -> callback.onError(t));
  65.             }
  66.             reconnect(); // 尝试重连
  67.         }
  68.     };
  69.     // 私有构造函数,使用Builder模式创建实例
  70.     private WebSocketManager(Builder builder) {
  71.         this.wsUrl = builder.wsUrl;
  72.         this.maxReconnectCount = builder.maxReconnectCount;
  73.         this.reconnectInterval = builder.reconnectInterval;
  74.         this.heartbeatInterval = builder.heartbeatInterval;
  75.         this.heartbeatTimeout = builder.heartbeatTimeout;
  76.         client = new OkHttpClient.Builder()
  77.                 .connectTimeout(10, TimeUnit.SECONDS)
  78.                 .writeTimeout(10, TimeUnit.SECONDS)
  79.                 .readTimeout(10, TimeUnit.SECONDS)
  80.                 .build();
  81.     }
  82.     // 连接WebSocket
  83.     public void connect() {
  84.         if (!isConnecting && !isConnected) {
  85.             isConnecting = true;
  86.             executorService.submit(() -> {
  87.                 Request request = new Request.Builder().url(wsUrl).build();
  88.                 webSocket = client.newWebSocket(request, webSocketListener);
  89.             });
  90.         }
  91.     }
  92.     // 断开连接
  93.     public void disconnect() {
  94.         if (webSocket != null) {
  95.             executorService.submit(() -> webSocket.close(1000, "Normal closure"));
  96.         }
  97.         releaseResources();
  98.     }
  99.     // 发送消息
  100.     public void sendMessage(String message) {
  101.         if (webSocket != null && isConnected) {
  102.             executorService.submit(() -> {
  103.                 boolean sent = webSocket.send(message);
  104.                 if (!sent) {
  105.                     // 发送失败,将消息加入队列
  106.                     messageQueue.offer(message);
  107.                 }
  108.             });
  109.         } else {
  110.             // 网络未连接时,将消息加入队列
  111.             messageQueue.offer(message);
  112.         }
  113.     }
  114.     // 重连机制
  115.     private void reconnect() {
  116.         if (reconnectCount.get() < maxReconnectCount) {
  117.             reconnectCount.incrementAndGet();
  118.             mainHandler.postDelayed(() -> {
  119.                 Log.d(TAG, "Reconnecting... Attempt: " + reconnectCount.get());
  120.                 connect();
  121.             }, reconnectInterval);
  122.         } else {
  123.             Log.e(TAG, "Max reconnection attempts reached");
  124.         }
  125.     }
  126.     // 发送缓存的消息
  127.     private void sendQueuedMessages() {
  128.         executorService.submit(() -> {
  129.             while (!messageQueue.isEmpty()) {
  130.                 String message = messageQueue.poll();
  131.                 if (message != null) {
  132.                     boolean sent = webSocket.send(message);
  133.                     if (!sent) {
  134.                         // 发送失败,将消息重新加入队列
  135.                         messageQueue.offer(message);
  136.                         break;
  137.                     }
  138.                 }
  139.             }
  140.         });
  141.     }
  142.     // 开始心跳
  143.     private void startHeartbeat() {
  144.         heartbeatRunnable = new Runnable() {
  145.             @Override
  146.             public void run() {
  147.                 if (isConnected) {
  148.                     webSocket.send("Heartbeat"); // 发送心跳消息
  149.                     mainHandler.postDelayed(this, heartbeatInterval);
  150.                 }
  151.             }
  152.         };
  153.         mainHandler.post(heartbeatRunnable);
  154.     }
  155.     // 停止心跳
  156.     private void stopHeartbeat() {
  157.         mainHandler.removeCallbacks(heartbeatRunnable);
  158.     }
  159.     // 释放资源
  160.     private void releaseResources() {
  161.         executorService.shutdown();
  162.         mainHandler.removeCallbacksAndMessages(null);
  163.     }
  164.     // 设置回调
  165.     public void setWebSocketCallback(WebSocketCallback callback) {
  166.         this.callback = callback;
  167.     }
  168.     // Builder模式
  169.     public static class Builder {
  170.         private String wsUrl;
  171.         private int maxReconnectCount = 5;
  172.         private long reconnectInterval = 5000;
  173.         private long heartbeatInterval = 30000;
  174.         private long heartbeatTimeout = 60000;
  175.         public Builder(String wsUrl) {
  176.             this.wsUrl = wsUrl;
  177.         }
  178.         public Builder setMaxReconnectCount(int maxReconnectCount) {
  179.             this.maxReconnectCount = maxReconnectCount;
  180.             return this;
  181.         }
  182.         public Builder setReconnectInterval(long reconnectInterval) {
  183.             this.reconnectInterval = reconnectInterval;
  184.             return this;
  185.         }
  186.         public Builder setHeartbeatInterval(long heartbeatInterval) {
  187.             this.heartbeatInterval = heartbeatInterval;
  188.             return this;
  189.         }
  190.         public Builder setHeartbeatTimeout(long heartbeatTimeout) {
  191.             this.heartbeatTimeout = heartbeatTimeout;
  192.             return this;
  193.         }
  194.         public WebSocketManager build() {
  195.             return new WebSocketManager(this);
  196.         }
  197.     }
  198.     // 回调接口
  199.     public interface WebSocketCallback {
  200.         void onMessage(String message);
  201.         void onConnected();
  202.         void onDisconnected();
  203.         void onError(Throwable t);
  204.     }
  205. }
复制代码

  • 功能阐明
    3.1 毗连状态管理
    增长 isConnecting 状态,区分毗连中和已毗连状态。
3.2 消息重发机制
在发送失败时,将消息重新参加队列,等待重连后发送。
3.3 动态心跳机制
支持动态调解心跳隔断和超时时间。
3.4 资源开释
在断开毗连时,开释线程池和Handler资源,制止内存走漏。
3.5 日志日志分级
通过 Log.d 和 Log.e 区分调试日志日志和错误日志日志。

  • 使用示例
    4.1 初始化并毗连WebSocket
  1. WebSocketManager webSocketManager = new WebSocketManager.Builder("ws://your-websocket-url")
  2.         .setMaxReconnectCount(10)
  3.         .setReconnectInterval(3000)
  4.         .setHeartbeatInterval(60000)
  5.         .setHeartbeatTimeout(120000)
  6.         .build();
  7. webSocketManager.setWebSocketCallback(new WebSocketManager.WebSocketCallback() {
  8.     @Override
  9.     public void onMessage(String message) {
  10.         Log.d(TAG, "Received: " + message);
  11.     }
  12.     @Override
  13.     public void onConnected() {
  14.         Log.d(TAG, "Connected");
  15.     }
  16.     @Override
  17.     public void onDisconnected() {
  18.         Log.d(TAG, "Disconnected");
  19.     }
  20.     @Override
  21.     public void onError(Throwable t) {
  22.         Log.e(TAG, "Error: " + t.getMessage());
  23.     }
  24. });
  25. webSocketManager.connect();
复制代码
4.2 发送消息
  1. webSocketManager.sendMessage("Hello, WebSocket!");
复制代码
4.3 断开毗连
  1. webSocketManager.disconnect();
复制代码
4.4 处置惩罚生命周期
  1. @Overrideprotected void onDestroy() {    super.onDestroy();    webSocketManager.disconnect();
  2. }
复制代码
在Activity中使用WebSocket工具类非常简单。我们须要确保WebSocket的生命周期与Activity的生命周期绑定,制止内存走漏和资源浪费。以下是完备的示例代码,展示如安在Activity中初始化、使用和开释WebSocket工具类。
在Activity中使用WebSocket工具类

  • Activity代码示例
  1. import android.os.Bundle;import android.util.Log;import androidx.annotation.Nullable;import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {    private static final String TAG = "MainActivity";    private WebSocketManager webSocketManager;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        // 初始化WebSocketManager        webSocketManager = new WebSocketManager.Builder("ws://your-websocket-url")                .setMaxReconnectCount(10)                .setReconnectInterval(3000)                .setHeartbeatInterval(60000)                .setHeartbeatTimeout(120000)                .build();        // 设置WebSocket回调        webSocketManager.setWebSocketCallback(new WebSocketManager.WebSocketCallback() {            @Override            public void onMessage(String message) {                Log.d(TAG, "Received: " + message);                // 在这里处置惩罚汲取到的消息            }            @Override            public void onConnected() {                Log.d(TAG, "Connected");                // 在这里处置惩罚毗连乐成变乱            }            @Override            public void onDisconnected() {                Log.d(TAG, "Disconnected");                // 在这里处置惩罚毗连断开变乱            }            @Override            public void onError(Throwable t) {                Log.e(TAG, "Error: " + t.getMessage());                // 在这里处置惩罚错误变乱            }        });        // 毗连WebSocket        webSocketManager.connect();
  2.         // 发送消息        webSocketManager.sendMessage("Hello, WebSocket!");
  3.     }    @Override    protected void onDestroy() {        super.onDestroy();        // 断开WebSocket毗连并开释资源        if (webSocketManager != null) {            webSocketManager.disconnect();
  4.         }    }}
复制代码

  • 代码阐明
    2.1 初始化WebSocketManager
    在 onCreate 方法中,使用 Builder 模式初始化 WebSocketManager,并设置最大重连次数、重连隔断、心跳隔断和超时时间。
  1. webSocketManager = new WebSocketManager.Builder("ws://your-websocket-url")
  2.         .setMaxReconnectCount(10)
  3.         .setReconnectInterval(3000)
  4.         .setHeartbeatInterval(60000)
  5.         .setHeartbeatTimeout(120000)
  6.         .build();
复制代码
2.2 设置回调
通过 setWebSocketCallback 方法设置回调接口,处置惩罚WebSocket的毗连、消息、断开和错误变乱。
  1. webSocketManager.setWebSocketCallback(new WebSocketManager.WebSocketCallback() {
  2.     @Override
  3.     public void onMessage(String message) {
  4.         Log.d(TAG, "Received: " + message);
  5.         // 在这里处理接收到的消息
  6.     }
  7.     @Override
  8.     public void onConnected() {
  9.         Log.d(TAG, "Connected");
  10.         // 在这里处理连接成功事件
  11.     }
  12.     @Override
  13.     public void onDisconnected() {
  14.         Log.d(TAG, "Disconnected");
  15.         // 在这里处理连接断开事件
  16.     }
  17.     @Override
  18.     public void onError(Throwable t) {
  19.         Log.e(TAG, "Error: " + t.getMessage());
  20.         // 在这里处理错误事件
  21.     }
  22. });
复制代码
2.3 毗连WebSocket
在 onCreate 方法中调用 connect() 方法,启动WebSocket毗连。
  1. webSocketManager.connect();
复制代码
2.4 发送消息
通过 sendMessage 方法发送消息。
  1. webSocketManager.sendMessage("Hello, WebSocket!");
复制代码
2.5 开释资源
在 onDestroy 方法中调用 disconnect() 方法,断开WebSocket毗连并开释资源。
  1. @Overrideprotected void onDestroy() {    super.onDestroy();    if (webSocketManager != null) {        webSocketManager.disconnect();
  2.     }}
复制代码

  • 注意事项
    3.1 生命周期绑定
    确保WebSocket的生命周期与Activity的生命周期绑定,制止内存走漏。
在 onDestroy 中开释资源。
3.2 线程安全
WebSocket的回调方法(如 onMessage)运行在配景线程,如果须要更新UI,请使用 Handler 或 runOnUiThread。
3.3 网络权限
在 AndroidManifest.xml 中添加网络权限:
  1. <!--    网络权限-->
  2.     <uses-permission android:name="android.permission.INTERNET"/>
  3. <!--    wifi权限-->
  4.     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
  5.     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
  6.     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  7.     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
复制代码
3.4 SSL/TLS支持
如果WebSocket服务器使用 wss 协议(即基于SSL/TLS的安全毗连),OkHttp 会自动处置惩罚SSL/TLS握手,无需额外设置。

  • 扩展功能
    4.1 动态调解心跳隔断
    可以根据服务器相应动态调解心跳隔断。比方,在收到服务器的心跳相应后,延伸心跳隔断。
  1. @Override
  2. public void onMessage(String message) {
  3.     if ("HeartbeatResponse".equals(message)) {
  4.         // 动态调整心跳间隔
  5.         webSocketManager.setHeartbeatInterval(120000);
  6.     }
  7. }
复制代码
4.2 消息重发机制
在发送失败时,将消息参加队列,等待重连后重新发送。
  1. webSocketManager.sendMessage("Hello, WebSocket!");
复制代码
4.3 日志分级
通过 Log.d 和 Log.e 区分调试日志和错误日志,方便调试和生产环境使用。

  • 总结
    在Activity中使用优化后的WebSocket工具类非常简单。通过生命周期绑定、回调接口和资源开释机制,可以确保WebSocket的高效运行和资源管理。以下是完备的流程:
初始化:在 onCreate 中初始化 WebSocketManager。
设置回调:处置惩罚毗连、消息、断开和错误变乱。
毗连WebSocket:调用 connect() 方法。
发送消息:通过 sendMessage 方法发送消息。
开释资源:在 onDestroy 中调用 disconnect() 方法。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表