Android WebSocket工具类:重连、心跳、消息队列一站式解决方案
- 依赖库
使用 OkHttp 的WebSocket支持。
在 build.gradle 中添加依赖:
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
- 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() {@Overridepublic 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());}}@Overridepublic void onMessage(WebSocket webSocket, String text) {Log.d(TAG, "Received message: " + text);if (callback != null) {mainHandler.post(() -> callback.onMessage(text));}}@Overridepublic 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());}}@Overridepublic 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();}// 连接WebSocketpublic 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() {@Overridepublic 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);}
}
- 功能说明
3.1 连接状态管理
增加 isConnecting 状态,区分连接中和已连接状态。
3.2 消息重发机制
在发送失败时,将消息重新加入队列,等待重连后发送。
3.3 动态心跳机制
支持动态调整心跳间隔和超时时间。
3.4 资源释放
在断开连接时,释放线程池和Handler资源,避免内存泄漏。
3.5 日志分级
通过 Log.d 和 Log.e 区分调试日志和错误日志。
- 使用示例
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() {@Overridepublic void onMessage(String message) {Log.d(TAG, "Received: " + message);}@Overridepublic void onConnected() {Log.d(TAG, "Connected");}@Overridepublic void onDisconnected() {Log.d(TAG, "Disconnected");}@Overridepublic 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工具类
- 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;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 初始化WebSocketManagerwebSocketManager = new WebSocketManager.Builder("ws://your-websocket-url").setMaxReconnectCount(10).setReconnectInterval(3000).setHeartbeatInterval(60000).setHeartbeatTimeout(120000).build();// 设置WebSocket回调webSocketManager.setWebSocketCallback(new WebSocketManager.WebSocketCallback() {@Overridepublic void onMessage(String message) {Log.d(TAG, "Received: " + message);// 在这里处理接收到的消息}@Overridepublic void onConnected() {Log.d(TAG, "Connected");// 在这里处理连接成功事件}@Overridepublic void onDisconnected() {Log.d(TAG, "Disconnected");// 在这里处理连接断开事件}@Overridepublic void onError(Throwable t) {Log.e(TAG, "Error: " + t.getMessage());// 在这里处理错误事件}});// 连接WebSocketwebSocketManager.connect();// 发送消息webSocketManager.sendMessage("Hello, WebSocket!");}@Overrideprotected void onDestroy() {super.onDestroy();// 断开WebSocket连接并释放资源if (webSocketManager != null) {webSocketManager.disconnect();}}
}
- 代码说明
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() {@Overridepublic void onMessage(String message) {Log.d(TAG, "Received: " + message);// 在这里处理接收到的消息}@Overridepublic void onConnected() {Log.d(TAG, "Connected");// 在这里处理连接成功事件}@Overridepublic void onDisconnected() {Log.d(TAG, "Disconnected");// 在这里处理连接断开事件}@Overridepublic 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();}
}
- 注意事项
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握手,无需额外配置。
- 扩展功能
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 区分调试日志和错误日志,方便调试和生产环境使用。
- 总结
在Activity中使用优化后的WebSocket工具类非常简单。通过生命周期绑定、回调接口和资源释放机制,可以确保WebSocket的高效运行和资源管理。以下是完整的流程:
初始化:在 onCreate 中初始化 WebSocketManager。
设置回调:处理连接、消息、断开和错误事件。
连接WebSocket:调用 connect() 方法。
发送消息:通过 sendMessage 方法发送消息。
释放资源:在 onDestroy 中调用 disconnect() 方法。
相关文章:
Android WebSocket工具类:重连、心跳、消息队列一站式解决方案
依赖库 使用 OkHttp 的WebSocket支持。 在 build.gradle 中添加依赖: implementation com.squareup.okhttp3:okhttp:4.9.3WebSocket工具类实现 import okhttp3.*; import android.os.Handler; import android.os.Looper; import android.util.Log;import java.ut…...
认识vue2脚手架
1.认识脚手架结构 使用VSCode将vue项目打开: package.json:包的说明书(包的名字,包的版本,依赖哪些库)。该文件里有webpack的短命令: serve(启动内置服务器) build命令…...
【STM32】STM32系列产品以及新手入门的STM32F103
📢 STM32F103xC/D/E 系列是一款高性能、低功耗的 32 位 MCU,适用于工业、汽车、消费电子等领域;基于 ARM Cortex-M3,主频最高 72MHz,支持 512KB Flash、64KB SRAM,适合复杂嵌入式应用,提供丰富的…...
<建模软件安装教程1>Blender4.2系列
Blender4.2安装教程 0注意:Windows环境下安装 第一步,百度网盘提取安装包。百度网盘链接:通过网盘分享的文件:blender.zip 链接: https://pan.baidu.com/s/1OG0jMMtN0qWDSQ6z_rE-9w 提取码: 0309 --来自百度网盘超级会员v3的分…...
CentOS Docker 安装指南
CentOS Docker 安装指南 引言 Docker 是一个开源的应用容器引擎,它允许开发者打包他们的应用以及应用的依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。Docker 容器是完全使用沙箱机制,相互之…...
分布式ID生成方案:数据库号段、Redis与第三方开源实现
分布式ID生成方案:数据库号段、Redis与第三方开源实现 引言 在分布式系统中,全局唯一ID生成是核心基础能力之一。本文针对三种主流分布式ID生成方案(数据库号段模式、Redis方案、第三方开源框架)进行解析,从实现原理…...
tcc编译器教程2 编译lua解释器
本文主要介绍了使用tcc编译器编译lua解释器源码。 1 介绍 lua是一门编程语言,开源且源码很容易编译,我平时用来测试C语言编程环境时经常使用。一般能编译成功就说明编程环境设置正常。下面用之前设置好的tcc编程环境进行测试。 2 获取源码 我一般有保留多个版本的lua源码进…...
利用 requestrepo 工具验证 XML外部实体注入漏洞
1. 前言 在数字化浪潮席卷的当下,网络安全的重要性愈发凸显。应用程序在便捷生活与工作的同时,也可能暗藏安全风险。XXE(XML外部实体)漏洞作为其中的典型代表,攻击者一旦利用它,便能窃取敏感信息、掌控服务…...
在 Maven 中使用 <scope> 元素:全面指南
目录 前言 在 Maven 中, 元素用于定义依赖项的作用范围,即依赖项在项目生命周期中的使用方式。正确使用 可以帮助我们优化项目的构建过程,减少不必要的依赖冲突,并提高构建效率。本文将详细介绍 的使用步骤、常见作用范围、代码…...
uni_app实现下拉刷新
1. 在页面配置中启用下拉刷新 首先,你需要在页面的 pages.json 文件中启用下拉刷新功能。 {"pages": [{"path": "pages/index/index","style": {"navigationBarTitleText": "首页","enablePull…...
PCIe协议之RCB、MPS、MRRS详解
✨前言: PCIe总线的存储器写请求、存储器读完成等TLP中含有数据负载,即Data Payload。Data Payload的长度和MPS(Max Payload Size)、MRRS(Max Read Request Size)和RCB(Read Completion Bounda…...
达梦数据库在Linux,信创云 安装,备份,还原
(一)系统环境检查 1操作系统:确认使用的是国产麒麟操作系统,检查系统版本是否兼容达梦数据库 V8。可以通过以下命令查看系统版本: cat /etc/os-release 2硬件资源:确保服务器具备足够的硬件资源࿰…...
使用Dockerfile打包java项目生成镜像部署到Linux_java项目打docker镜像的dockerfile
比起容器、镜像来说,Dockerfile 非常普通,它就是一个纯文本,里面记录了一系列的构建指令,比如选择基础镜像、拷贝文件、运行脚本等等,每个指令都会生成一个 Layer,而 Docker 顺序执行这个文件里的所有步骤&…...
爬虫案例九js逆向爬取CBA中国篮球网
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、CBA网站分析二、代码 前言 提示:这里可以添加本文要记录的大概内容: 爬取CBA中国篮球网 提示:以下是本篇文章正文内容…...
【DeepSeek】Ubuntu快速部署DeepSeek(Ollama方式)
文章目录 人人都该学习的DeepSeekDeepSeek不同版本功能差异DeepSeek与硬件直接的关系DeepSeek系统兼容性部署方式选择部署步骤(Ollama方式)1.选定适合的deepseek版本2.环境准备3.安装Ollama4.部署deepseek5.测试使用 人人都该学习的DeepSeek DeepSeek 作…...
C++后端服务器开发技术栈有哪些?有哪些资源或开源库拿来用?
一、 C后台服务器开发是一个涉及多方面技术选择的复杂领域,特别是在高性能、高并发的场景下。以下是C后台服务器开发的一种常见技术路线,涵盖了从基础到高级的技术栈。 1. 基础技术栈 C标准库 C11/C14/C17/C20:使用现代C特性,如…...
基于SpringBoot的餐厅点餐管理系统设计与实现(源码+SQL脚本+LW+部署讲解等)
专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…...
服务端和客户端通信(TCP)
服务端 using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks;namespace TeachTcpServer {class Program{static void Main(string[] args){#region 知识点一 …...
Java 大视界 -- Java 大数据在智能体育赛事运动员表现分析与训练优化中的应用(122)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
基于Spring Boot的多级缓存架构实现
基于Spring Boot的多级缓存架构实现 以下是一个基于Spring Boot的多级缓存架构实现示例 多级缓存架构实现方案 1. 依赖配置(pom.xml) <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-star…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)
目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 编辑编辑 UDP的特征 socke函数 bind函数 recvfrom函数(接收函数) sendto函数(发送函数) 五、网络编程之 UDP 用…...
WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...
32位寻址与64位寻址
32位寻址与64位寻址 32位寻址是什么? 32位寻址是指计算机的CPU、内存或总线系统使用32位二进制数来标识和访问内存中的存储单元(地址),其核心含义与能力如下: 1. 核心定义 地址位宽:CPU或内存控制器用32位…...
SQL注入篇-sqlmap的配置和使用
在之前的皮卡丘靶场第五期SQL注入的内容中我们谈到了sqlmap,但是由于很多朋友看不了解命令行格式,所以是纯手动获取数据库信息的 接下来我们就用sqlmap来进行皮卡丘靶场的sql注入学习,链接:https://wwhc.lanzoue.com/ifJY32ybh6vc…...
