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

  1. 依赖库
    使用 OkHttp 的WebSocket支持。

在 build.gradle 中添加依赖:

implementation 'com.squareup.okhttp3:okhttp:4.9.3'
  1. WebSocket工具类实现
import okhttp3.*;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class WebSocketManager {
    private static final String TAG = "WebSocketManager";

    private OkHttpClient client;
    private WebSocket webSocket;
    private String wsUrl;
    private AtomicInteger reconnectCount = new AtomicInteger(0);
    private boolean isConnecting = false;
    private boolean isConnected = false;
    private Handler mainHandler = new Handler(Looper.getMainLooper());
    private Runnable heartbeatRunnable;
    private ConcurrentLinkedQueue<String> messageQueue = new ConcurrentLinkedQueue<>(); // 线程安全的消息队列
    private ExecutorService executorService = Executors.newSingleThreadExecutor(); // 线程池

    private int maxReconnectCount = 5; // 最大重连次数
    private long reconnectInterval = 5000; // 重连间隔时间(毫秒)
    private long heartbeatInterval = 30000; // 心跳间隔时间(毫秒)
    private long heartbeatTimeout = 60000; // 心跳超时时间(毫秒)

    private WebSocketCallback callback;

    private WebSocketListener webSocketListener = new WebSocketListener() {
        @Override
        public void onOpen(WebSocket webSocket, Response response) {
            Log.d(TAG, "WebSocket connected");
            isConnecting = false;
            isConnected = true;
            reconnectCount.set(0); // 重置重连次数
            startHeartbeat(); // 开始心跳
            sendQueuedMessages(); // 发送缓存的消息
            if (callback != null) {
                mainHandler.post(() -> callback.onConnected());
            }
        }

        @Override
        public void onMessage(WebSocket webSocket, String text) {
            Log.d(TAG, "Received message: " + text);
            if (callback != null) {
                mainHandler.post(() -> callback.onMessage(text));
            }
        }

        @Override
        public void onClosed(WebSocket webSocket, int code, String reason) {
            Log.d(TAG, "WebSocket closed: " + reason);
            isConnecting = false;
            isConnected = false;
            stopHeartbeat(); // 停止心跳
            if (callback != null) {
                mainHandler.post(() -> callback.onDisconnected());
            }
        }

        @Override
        public void onFailure(WebSocket webSocket, Throwable t, Response response) {
            Log.e(TAG, "WebSocket failed: " + t.getMessage());
            isConnecting = false;
            isConnected = false;
            stopHeartbeat(); // 停止心跳
            if (callback != null) {
                mainHandler.post(() -> callback.onError(t));
            }
            reconnect(); // 尝试重连
        }
    };

    // 私有构造函数,使用Builder模式创建实例
    private WebSocketManager(Builder builder) {
        this.wsUrl = builder.wsUrl;
        this.maxReconnectCount = builder.maxReconnectCount;
        this.reconnectInterval = builder.reconnectInterval;
        this.heartbeatInterval = builder.heartbeatInterval;
        this.heartbeatTimeout = builder.heartbeatTimeout;

        client = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .build();
    }

    // 连接WebSocket
    public void connect() {
        if (!isConnecting && !isConnected) {
            isConnecting = true;
            executorService.submit(() -> {
                Request request = new Request.Builder().url(wsUrl).build();
                webSocket = client.newWebSocket(request, webSocketListener);
            });
        }
    }

    // 断开连接
    public void disconnect() {
        if (webSocket != null) {
            executorService.submit(() -> webSocket.close(1000, "Normal closure"));
        }
        releaseResources();
    }

    // 发送消息
    public void sendMessage(String message) {
        if (webSocket != null && isConnected) {
            executorService.submit(() -> {
                boolean sent = webSocket.send(message);
                if (!sent) {
                    // 发送失败,将消息加入队列
                    messageQueue.offer(message);
                }
            });
        } else {
            // 网络未连接时,将消息加入队列
            messageQueue.offer(message);
        }
    }

    // 重连机制
    private void reconnect() {
        if (reconnectCount.get() < maxReconnectCount) {
            reconnectCount.incrementAndGet();
            mainHandler.postDelayed(() -> {
                Log.d(TAG, "Reconnecting... Attempt: " + reconnectCount.get());
                connect();
            }, reconnectInterval);
        } else {
            Log.e(TAG, "Max reconnection attempts reached");
        }
    }

    // 发送缓存的消息
    private void sendQueuedMessages() {
        executorService.submit(() -> {
            while (!messageQueue.isEmpty()) {
                String message = messageQueue.poll();
                if (message != null) {
                    boolean sent = webSocket.send(message);
                    if (!sent) {
                        // 发送失败,将消息重新加入队列
                        messageQueue.offer(message);
                        break;
                    }
                }
            }
        });
    }

    // 开始心跳
    private void startHeartbeat() {
        heartbeatRunnable = new Runnable() {
            @Override
            public void run() {
                if (isConnected) {
                    webSocket.send("Heartbeat"); // 发送心跳消息
                    mainHandler.postDelayed(this, heartbeatInterval);
                }
            }
        };
        mainHandler.post(heartbeatRunnable);
    }

    // 停止心跳
    private void stopHeartbeat() {
        mainHandler.removeCallbacks(heartbeatRunnable);
    }

    // 释放资源
    private void releaseResources() {
        executorService.shutdown();
        mainHandler.removeCallbacksAndMessages(null);
    }

    // 设置回调
    public void setWebSocketCallback(WebSocketCallback callback) {
        this.callback = callback;
    }

    // Builder模式
    public static class Builder {
        private String wsUrl;
        private int maxReconnectCount = 5;
        private long reconnectInterval = 5000;
        private long heartbeatInterval = 30000;
        private long heartbeatTimeout = 60000;

        public Builder(String wsUrl) {
            this.wsUrl = wsUrl;
        }

        public Builder setMaxReconnectCount(int maxReconnectCount) {
            this.maxReconnectCount = maxReconnectCount;
            return this;
        }

        public Builder setReconnectInterval(long reconnectInterval) {
            this.reconnectInterval = reconnectInterval;
            return this;
        }

        public Builder setHeartbeatInterval(long heartbeatInterval) {
            this.heartbeatInterval = heartbeatInterval;
            return this;
        }

        public Builder setHeartbeatTimeout(long heartbeatTimeout) {
            this.heartbeatTimeout = heartbeatTimeout;
            return this;
        }

        public WebSocketManager build() {
            return new WebSocketManager(this);
        }
    }

    // 回调接口
    public interface WebSocketCallback {
        void onMessage(String message);
        void onConnected();
        void onDisconnected();
        void onError(Throwable t);
    }
}
  1. 功能说明
    3.1 连接状态管理
    增加 isConnecting 状态,区分连接中和已连接状态。

3.2 消息重发机制
在发送失败时,将消息重新加入队列,等待重连后发送。

3.3 动态心跳机制
支持动态调整心跳间隔和超时时间。

3.4 资源释放
在断开连接时,释放线程池和Handler资源,避免内存泄漏。

3.5 日志分级
通过 Log.d 和 Log.e 区分调试日志和错误日志。

  1. 使用示例
    4.1 初始化并连接WebSocket
WebSocketManager webSocketManager = new WebSocketManager.Builder("ws://your-websocket-url")
        .setMaxReconnectCount(10)
        .setReconnectInterval(3000)
        .setHeartbeatInterval(60000)
        .setHeartbeatTimeout(120000)
        .build();

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());
    }
});

webSocketManager.connect();

4.2 发送消息

webSocketManager.sendMessage("Hello, WebSocket!");

4.3 断开连接

webSocketManager.disconnect();

4.4 处理生命周期

@Override
protected void onDestroy() {
    super.onDestroy();
    webSocketManager.disconnect();
}

在Activity中使用WebSocket工具类非常简单。我们需要确保WebSocket的生命周期与Activity的生命周期绑定,避免内存泄漏和资源浪费。以下是完整的示例代码,展示如何在Activity中初始化、使用和释放WebSocket工具类。

在Activity中使用WebSocket工具类

  1. Activity代码示例
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();

        // 发送消息
        webSocketManager.sendMessage("Hello, WebSocket!");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 断开WebSocket连接并释放资源
        if (webSocketManager != null) {
            webSocketManager.disconnect();
        }
    }
}
  1. 代码说明
    2.1 初始化WebSocketManager
    在 onCreate 方法中,使用 Builder 模式初始化 WebSocketManager,并设置最大重连次数、重连间隔、心跳间隔和超时时间。
webSocketManager = new WebSocketManager.Builder("ws://your-websocket-url")
        .setMaxReconnectCount(10)
        .setReconnectInterval(3000)
        .setHeartbeatInterval(60000)
        .setHeartbeatTimeout(120000)
        .build();

2.2 设置回调
通过 setWebSocketCallback 方法设置回调接口,处理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());
        // 在这里处理错误事件
    }
});

2.3 连接WebSocket
在 onCreate 方法中调用 connect() 方法,启动WebSocket连接。

webSocketManager.connect();

2.4 发送消息
通过 sendMessage 方法发送消息。

webSocketManager.sendMessage("Hello, WebSocket!");

2.5 释放资源
在 onDestroy 方法中调用 disconnect() 方法,断开WebSocket连接并释放资源。

@Override
protected void onDestroy() {
    super.onDestroy();
    if (webSocketManager != null) {
        webSocketManager.disconnect();
    }
}
  1. 注意事项
    3.1 生命周期绑定
    确保WebSocket的生命周期与Activity的生命周期绑定,避免内存泄漏。

在 onDestroy 中释放资源。

3.2 线程安全
WebSocket的回调方法(如 onMessage)运行在后台线程,如果需要更新UI,请使用 Handler 或 runOnUiThread。

3.3 网络权限
在 AndroidManifest.xml 中添加网络权限:

<!--    网络权限-->
    <uses-permission android:name="android.permission.INTERNET"/>
<!--    wifi权限-->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>

3.4 SSL/TLS支持
如果WebSocket服务器使用 wss 协议(即基于SSL/TLS的安全连接),OkHttp 会自动处理SSL/TLS握手,无需额外配置。

  1. 扩展功能
    4.1 动态调整心跳间隔
    可以根据服务器响应动态调整心跳间隔。例如,在收到服务器的心跳响应后,延长心跳间隔。
@Override
public void onMessage(String message) {
    if ("HeartbeatResponse".equals(message)) {
        // 动态调整心跳间隔
        webSocketManager.setHeartbeatInterval(120000);
    }
}

4.2 消息重发机制
在发送失败时,将消息加入队列,等待重连后重新发送。

webSocketManager.sendMessage("Hello, WebSocket!");

4.3 日志分级
通过 Log.d 和 Log.e 区分调试日志和错误日志,方便调试和生产环境使用。

  1. 总结
    在Activity中使用优化后的WebSocket工具类非常简单。通过生命周期绑定、回调接口和资源释放机制,可以确保WebSocket的高效运行和资源管理。以下是完整的流程:

初始化:在 onCreate 中初始化 WebSocketManager。

设置回调:处理连接、消息、断开和错误事件。

连接WebSocket:调用 connect() 方法。

发送消息:通过 sendMessage 方法发送消息。

释放资源:在 onDestroy 中调用 disconnect() 方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/984024.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FPGA|Verilog-SPI驱动

最近准备蓝桥杯FPGA的竞赛&#xff0c;因为感觉官方出的IIC的驱动代码思路非常好&#xff0c;写的内容非常有逻辑并且规范。也想学习一下SPI的协议&#xff0c;所以准备自己照着写一下。直到我打开他们给出的SPI底层驱动&#xff0c;我整个人傻眼了&#xff0c;我只能说&#x…

python语言总结(持续更新)

本文主要是总结各函数&#xff0c;简单的函数不会给予示例&#xff0c;如果在平日遇到一些新类型将会添加 基础知识 输入与输出 print([要输出的内容])输出函数 input([提示内容]如果输入提示内容会在交互界面显示&#xff0c;用以提示用户)输入函数 注释 # 单行注释符&…

NO.26十六届蓝桥杯备战|字符数组七道练习|islower|isupper|tolower|toupper|strstr(C++)

P5733 【深基6.例1】自动修正 - 洛谷 小写字母 - 32 大写字母 大写字母 32 小写字母 #include <bits/stdc.h> using namespace std;const int N 110; char a[N] { 0 };int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cin >> a;int i 0;while (a…

笔记四:C语言中的文件和文件操作

Faye&#xff1a;只要有正确的伴奏&#xff0c;什么都能变成好旋律。 ---------《寻找天堂》 目录 一、文件介绍 1.1程序文件 1.2 数据文件 1.3 文件名 二、文件的打开和关闭 2.1 文件指针 2.2.文件的打开和关闭 2.3 文件读取结束的判定 三、 文件的顺序读写 3.1 顺序读写…

DeepSeek进阶应用(一):结合Mermaid绘图(流程图、时序图、类图、状态图、甘特图、饼图)

&#x1f31f;前言: 在软件开发、项目管理和系统设计等领域&#xff0c;图表是表达复杂信息的有效工具。随着AI助手如DeepSeek的普及&#xff0c;我们现在可以更轻松地创建各种专业图表。 名人说&#xff1a;博观而约取&#xff0c;厚积而薄发。——苏轼《稼说送张琥》 创作者&…

【OneAPI】网页截图API-V2

API简介 生成指定URL的网页截图或缩略图。 旧版本请参考&#xff1a;网页截图 V2版本新增全屏截图、带壳截图等功能&#xff0c;并修复了一些已知问题。 全屏截图&#xff1a; 支持全屏截图&#xff0c;通过设置fullscreentrue来支持全屏截图。全屏模式下&#xff0c;系统…

基于SpringBoot的餐厅点餐管理系统设计与实现(源码+SQL脚本+LW+部署讲解等)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

Windows Server 2022:赋能未来,打造智能高效的企业数字基座---免费下载

免费下载地址 Windows Server 2022&#xff1a;赋能未来&#xff0c;打造智能高效的企业数字基座‌ 在数字化转型的浪潮中&#xff0c;企业需要更安全、更灵活、更智能的基础设施支撑。‌Windows Server 2022‌作为微软新一代服务器操作系统&#xff0c;以革新性的技术架构和行…

支持向量简要理解

决策方程符合感知机区分理论&#xff0c;我们基于线性代数来看这满足子空间理论&#xff0c;可以获取得到超平面。 支持向量机的目标是寻找最与超平面最近的点的最大距离&#xff0c;而距离计算如上&#xff0c;符合数学上计算点到线&#xff08;面&#xff09;的距离公式。 …

USB2.0 学习(1)字段和包

目录 1 字段 1.1 包识别字段PID 1.2 地址字段 1.3帧号字段 1.4 数据字段 1.5 CRC字段 2 包 2.1令牌包 2.2帧起始包 2.3数据包 2.4SPLIT包(分割事务包) 2.5握手包 参考 USB包的构成是一个逐层的过程,首先这些串行数据按照特定的规则构成字段,字段是构成包的基本…

AI 人工智能深度解析:从基础到前沿,全面掌握未来科技

AI 人工智能深度解析&#xff1a;从基础到前沿&#xff0c;全面掌握未来科技 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;可以分享一下给大家。点击跳转到网站。 https://www.captainbed.cn/ccc 文章目录 AI 人工智能深度解析…

2025-03-09 学习记录--C/C++-PTA 习题11-1 输出月份英文名

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、题目描述 ⭐️ 裁判测试程序样例&#xff1a; #include <stdio.h>char *getmonth( int n );int main() {int n;char …

【音视频 | AAC】AAC编码库faac介绍、使用步骤、例子代码

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

macos 程序 运行

sudo xattr -r -d com.apple.quarantine [/Applications/Name]使用stow 管理配置文件

JavaWeb后端基础(7)AOP

AOP是Spring框架的核心之一&#xff0c;那什么是AOP&#xff1f;AOP&#xff1a;Aspect Oriented Programming&#xff08;面向切面编程、面向方面编程&#xff09;&#xff0c;其实说白了&#xff0c;面向切面编程就是面向特定方法编程。AOP是一种思想&#xff0c;而在Spring框…

STM32驱动OLED屏幕全解析:从原理到温度显示实战(上) | 零基础入门STM32第五十三步

主题内容教学目的/扩展视频OLED显示屏重点课程电路原理&#xff0c;手册分析&#xff0c;驱动程序。初始化&#xff0c;清屏&#xff0c;ASCII字库&#xff0c;显示分区。调用显示函数。做带有加入图形和汉字显示的RTC时钟界面。讲字库的设计原理。 师从洋桃电子&#xff0c;杜…

基于YOLO11深度学习的运动品牌LOGO检测与识别系统【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

ctfshow做题笔记—栈溢出—pwn65~pwn68

目录 前言 一、pwn65(你是一个好人) 二、pwn66(简单的shellcode&#xff1f;不对劲&#xff0c;十分得有十二分的不对劲) 三、pwn67(32bit nop sled)&#xff08;确实不会&#xff09; 四、pwn68(64bit nop sled) 前言 做起来比较吃力哈哈&#xff0c;自己还是太菜了&…

【新手指南】pyqt可视化远程部署deepseek7B蒸馏版模型

本地效果&#xff1a;&#xff08;如果想做这个的本科毕设&#xff0c;建议美化界面。&#xff09; 总结&#xff1a;MobaXterm远程连接autodl服务器&#xff0c;在MobaXterm上利用X11转发使pyqt可视化页面在自己的电脑上展现出来。 1. 官网下载MobaXterm MobaXterm free Xse…

SpringBoot(一)--搭建架构5种方法

目录 一、⭐Idea从spring官网下载打开 2021版本idea 1.打开创建项目 2.修改pom.xml文件里的版本号 2017版本idea 二、从spring官网下载再用idea打开 三、Idea从阿里云的官网下载打开 ​编辑 四、Maven项目改造成springboot项目 五、从阿里云官网下载再用idea打开 Spri…