HarmonyOS 实时股票行情 App 开发实战
摘要
本文基于 HarmonyOS 原生开发框架,结合 WebSocket 长连接技术,完成一款具备实时股票行情推送、标的动态订阅/取消、数据本地解析、界面实时刷新的股票行情应用。文章从整体架构设计、环境准备、核心模块拆分、WebSocket 通信封装、业务逻辑实现到完整代码落地进行全流程讲解,兼顾工程化规范与实战落地性,同时针对金融行情场景下的长连接保活、动态订阅、异常容错等问题给出解决方案。适合鸿蒙应用开发者、金融类客户端研发人员参考学习。
一、整体架构设计
1.1 技术选型
- 应用框架:HarmonyOS ArkTS + ArkUI(声明式UI),适配鸿蒙标准开发范式,跨设备兼容;
- 通信方案:WebSocket 长连接,对接股票行情 API,实现低延迟实时数据推送;
- 数据管理:内存集合维护订阅标的状态,轻量状态管理,保障动态订阅逻辑一致性;
- 线程模型:鸿蒙异步任务分发,网络通信独立子线程执行,避免主线程阻塞、界面卡顿;
- 容错机制:连接心跳保活、断连自动重连、数据空值校验、异常捕获,提升应用稳定性。
1.2 整体分层架构
采用分层解耦的工程化架构,自上而下分为四层,职责清晰、便于后期迭代维护:
- UI 表现层:ArkUI 页面组件,负责行情列表渲染、用户交互(添加/移除自选股票)、界面刷新;
- 业务逻辑层:封装标的管理、指令组装、数据解析、状态同步等核心业务;
- 网络通信层:统一封装 WebSocket 客户端,提供连接、断连、发指令、消息监听通用能力;
- 基础工具层:公共工具类,包含 JSON 序列化、异常日志、心跳检测、线程调度。
1.3 核心业务流程
- 应用启动 → 初始化 WebSocket 客户端并建立长连接;
- 页面加载 → 初始化默认股票标的,发送订阅指令;
- 用户操作 → 新增/删除自选股,本地更新订阅列表 + 同步向服务端下发订阅/取消指令;
- 服务端推送行情数据 → 客户端解析数据 → 回调通知 UI 层刷新列表;
- 网络异常/连接断开 → 自动执行重连逻辑,恢复订阅状态,保障数据连续性。
二、开发环境与前置准备
2.1 开发环境
- 开发工具:DevEco Studio 最新稳定版
- 编译 SDK:HarmonyOS SDK 8+
- 开发语言:ArkTS
- 运行设备:鸿蒙手机/模拟器(API 8 及以上)
2.2 接口前置说明
本文对接标准股票 WebSocket 行情接口,遵循通用金融行情协议:
- 服务端地址:
wss://quote.alltick.co/quote-stock-b-ws-api?token=YOUR_TOKEN - 协议帧标识:
cmd_id: 22004 - 操作指令:
subscribe(订阅)、unsubscribe(取消订阅) - 标的字段:
code存储股票代码,支持单只/批量传递
说明:请将代码中
YOUR_TOKEN替换为实际有效的接口密钥。
三、核心模块实现
按照工程化拆分原则,将项目划分为网络封装模块、标的管理模块、页面UI模块、入口应用模块,逐个实现核心功能。
3.1 工具常量类(Constants.ets)
统一管理接口地址、指令、标识位,集中配置便于后期维护修改。
/**
* 全局常量配置
*/
export class Constants {
// 股票WebSocket服务端地址
public static readonly WS_STOCK_URL: string = "wss://quote.alltick.co/quote-stock-b-ws-api?token=YOUR_TOKEN";
// 协议指令ID
public static readonly CMD_ID: number = 22004;
// 订阅指令
public static readonly ACTION_SUBSCRIBE: string = "subscribe";
// 取消订阅指令
public static readonly ACTION_UNSUBSCRIBE: string = "unsubscribe";
// 心跳间隔 单位:毫秒
public static readonly PING_INTERVAL: number = 10000;
}
3.2 WebSocket 网络封装模块(StockWebSocket.ets)
独立封装 WebSocket 客户端,实现连接建立、消息监听、指令发送、心跳保活、断连重连、资源释放,完全解耦业务层。
import webSocket from '@ohos.net.webSocket';
import { Constants } from './Constants';
import hilog from '@ohos.hilog';
/**
* 股票行情WebSocket客户端封装
*/
export class StockWebSocket {
private ws: webSocket.WebSocket | null = null;
// 心跳定时器
private pingTimer: number | null = null;
// 重连定时器
private reconnectTimer: number | null = null;
// 重连次数限制
private readonly MAX_RECONNECT_COUNT: number = 5;
private reconnectCount: number = 0;
// 消息回调、连接状态回调
public onMessageCallback: (data: string) => void | null = null;
public onConnectCallback: () => void | null = null;
public onDisConnectCallback: () => void | null = null;
/**
* 建立WebSocket连接
*/
public connect(): void {
if (this.ws) {
return;
}
let wsInstance = webSocket.createWebSocket();
this.ws = wsInstance;
// 连接成功回调
wsInstance.on('open', () => {
hilog.info(0x0001, 'StockWS', 'WebSocket 连接成功');
this.reconnectCount = 0;
this.startPing();
this.onConnectCallback?.();
});
// 接收服务端消息
wsInstance.on('message', (data: string | ArrayBuffer) => {
if (typeof data === 'string') {
this.onMessageCallback?.(data);
}
});
// 连接关闭
wsInstance.on('close', (code: number, reason: string) => {
hilog.warn(0x0001, 'StockWS', `连接关闭: ${code}, ${reason}`);
this.stopPing();
this.onDisConnectCallback?.();
this.reconnect();
});
// 网络异常
wsInstance.on('error', (err: Error) => {
hilog.error(0x0001, 'StockWS', `WebSocket异常: ${JSON.stringify(err)}`);
});
// 发起连接
wsInstance.connect(Constants.WS_STOCK_URL);
}
/**
* 发送消息指令
* @param msg 待发送JSON字符串
*/
public sendMessage(msg: string): void {
if (!this.ws) {
hilog.warn(0x0001, 'StockWS', 'WebSocket未连接,无法发送指令');
return;
}
this.ws.send(msg);
}
/**
* 主动关闭连接
*/
public close(): void {
this.stopPing();
this.stopReconnect();
if (this.ws) {
this.ws.close();
this.ws = null;
}
}
/**
* 启动心跳保活
*/
private startPing(): void {
this.stopPing();
this.pingTimer = setInterval(() => {
// 此处可根据接口要求补充心跳报文
}, Constants.PING_INTERVAL);
}
/**
* 停止心跳
*/
private stopPing(): void {
if (this.pingTimer) {
clearInterval(this.pingTimer);
this.pingTimer = null;
}
}
/**
* 自动重连逻辑
*/
private reconnect(): void {
if (this.reconnectCount >= this.MAX_RECONNECT_COUNT) {
hilog.error(0x0001, 'StockWS', '重连次数超限,停止重连');
return;
}
this.stopReconnect();
this.reconnectTimer = setTimeout(() => {
this.reconnectCount++;
this.connect();
}, 3000);
}
/**
* 停止重连定时器
*/
private stopReconnect(): void {
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
this.reconnectTimer = null;
}
}
}
3.3 标的管理与业务逻辑模块(StockManager.ets)
核心业务层,维护本地订阅标的集合、组装订阅/取消指令、解析行情数据,衔接网络层与UI层,保证本地状态与服务端一致。
import { StockWebSocket } from './StockWebSocket';
import { Constants } from './Constants';
import hilog from '@ohos.hilog';
/**
* 股票标的管理、业务逻辑封装
*/
export class StockManager {
private static instance: StockManager;
// 单例WebSocket实例
private wsClient: StockWebSocket = new StockWebSocket();
// 本地订阅标的集合,防止重复订阅
private subscribeSet: Set<string> = new Set<string>();
// 行情数据回调,通知UI刷新
public onStockDataCallback: (stockCode: string, data: object) => void | null = null;
private constructor() {
this.initWebSocket();
}
/**
* 单例获取
*/
public static getInstance(): StockManager {
if (!StockManager.instance) {
StockManager.instance = new StockManager();
}
return StockManager.instance;
}
/**
* 初始化WebSocket及回调
*/
private initWebSocket(): void {
this.wsClient.onMessageCallback = (msg: string) => {
this.parseStockData(msg);
};
this.wsClient.connect();
}
/**
* 初始化默认订阅标的
* @param codeList 默认股票代码列表
*/
public initDefaultSubscribe(codeList: string[]): void {
this.addSubscribe(codeList);
}
/**
* 动态新增订阅标的
* @param codeList 股票代码数组
*/
public addSubscribe(codeList: string[]): void {
const validList: string[] = codeList.filter(item => !this.subscribeSet.has(item));
if (validList.length === 0) {
return;
}
// 更新本地状态
validList.forEach(code => this.subscribeSet.add(code));
// 组装订阅指令
const sendMsg = JSON.stringify({
cmd_id: Constants.CMD_ID,
action: Constants.ACTION_SUBSCRIBE,
code: validList
});
this.wsClient.sendMessage(sendMsg);
}
/**
* 动态取消订阅标的
* @param codeList 股票代码数组
*/
public removeSubscribe(codeList: string[]): void {
const validList: string[] = codeList.filter(item => this.subscribeSet.has(item));
if (validList.length === 0) {
return;
}
// 更新本地状态
validList.forEach(code => this.subscribeSet.delete(code));
// 组装取消订阅指令
const sendMsg = JSON.stringify({
cmd_id: Constants.CMD_ID,
action: Constants.ACTION_UNSUBSCRIBE,
code: validList
});
this.wsClient.sendMessage(sendMsg);
}
/**
* 解析服务端推送的行情数据
* @param msg 原始字符串数据
*/
private parseStockData(msg: string): void {
try {
const data = JSON.parse(msg);
const stockCode: string = data.code || "";
if (!stockCode) {
return;
}
// 回调通知UI更新
this.onStockDataCallback?.(stockCode, data);
} catch (e) {
hilog.error(0x0001, 'StockManager', `数据解析异常: ${JSON.stringify(e)}`);
}
}
/**
* 释放资源
*/
public release(): void {
this.wsClient.close();
this.subscribeSet.clear();
}
}
3.4 页面 UI 实现模块(Index.ets)
基于 ArkUI 声明式语法实现主页面,包含股票列表展示、添加/删除自选股交互、实时数据刷新,完成用户交互与视图渲染。
import { StockManager } from './StockManager';
// 股票数据实体
interface StockInfo {
code: string;
price: string;
change: string;
}
@Entry
@Component
struct Index {
// 标的管理实例
stockManager: StockManager = StockManager.getInstance();
// 页面数据源
@State stockList: Array<StockInfo> = [];
// 输入框股票代码
@State inputCode: string = "";
aboutToAppear() {
// 初始化默认标的
const defaultCodes: string[] = ["stock_a", "stock_b"];
this.stockManager.initDefaultSubscribe(defaultCodes);
// 注册数据回调,刷新UI
this.stockManager.onStockDataCallback = (code: string, data: object) => {
this.updateStockView(code, data);
}
}
aboutToDisappear() {
// 页面销毁释放资源
this.stockManager.release();
}
/**
* 更新单只股票视图数据
*/
updateStockView(code: string, data: object): void {
let target = this.stockList.find(item => item.code === code);
if (target) {
target.price = data["price"] ?? "0.00";
target.change = data["change"] ?? "0.00";
} else {
this.stockList.push({
code: code,
price: data["price"] ?? "0.00",
change: data["change"] ?? "0.00"
})
}
}
build() {
Column() {
// 标题
Text("HarmonyOS 实时股票行情")
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 15 })
// 输入框 + 操作按钮
Row() {
TextInput({ text: this.inputCode, placeholder: "请输入股票代码" })
.layoutWeight(1)
.onChange((value: string) => {
this.inputCode = value;
})
Button("添加")
.margin({ left: 10 })
.onClick(() => {
if (this.inputCode.trim()) {
this.stockManager.addSubscribe([this.inputCode.trim()]);
this.inputCode = "";
}
})
}.width("100%").margin({ bottom: 15 })
// 股票行情列表
List({ space: 8 }) {
ForEach(this.stockList, (item: StockInfo) => {
ListItem() {
Row() {
Text(item.code)
.layoutWeight(1)
.fontSize(16)
Text(`价格: ${item.price}`)
.margin({ left: 10 })
.fontSize(16)
Text(`涨跌: ${item.change}`)
.margin({ left: 10 })
.fontSize(16)
Button("移除")
.margin({ left: 10 })
.fontSize(14)
.onClick(() => {
this.stockManager.removeSubscribe([item.code]);
// 移除本地列表
const index = this.stockList.findIndex(s => s.code === item.code);
if (index > -1) {
this.stockList.splice(index, 1);
}
})
}.width("100%").padding(10)
}
})
}
.layoutWeight(1)
.width("100%")
}
.width("100%")
.height("100%")
.padding(15)
}
}
四、工程化规范与项目目录结构
4.1 标准目录结构
遵循鸿蒙应用工程化规范,目录职责划分清晰,便于团队协作与后期维护:
entry ├── ets │ ├── components # 公共UI组件(可扩展复用组件) │ ├── pages # 页面文件 │ │ └── Index.ets # 行情主页面 │ ├── utils # 工具类、网络、常量、业务管理类 │ │ ├── Constants.ets │ │ ├── StockWebSocket.ets │ │ └── StockManager.ets ├── resources # 图片、字符串、样式等资源文件 └── module.json5 # 应用配置文件
4.2 工程化要点说明
- 分层解耦:网络、业务、UI 完全拆分,单一职责原则,修改某一模块不影响其他逻辑;
- 单例管理:行情管理器使用单例,全局共用一套 WebSocket 连接,避免多连接资源浪费;
- 状态防护:本地集合管控订阅状态,严格规避重复订阅、无效取消订阅;
- 异常容错:内置心跳保活、自动重连、JSON解析异常捕获、空值判断,提升线上稳定性;
- 资源释放:页面生命周期回调中统一释放网络连接、定时器,防止内存泄漏。
五、功能测试与问题优化
5.1 核心功能测试点
- 应用启动自动建立 WebSocket 连接,默认标的正常接收行情数据;
- 输入股票代码点击添加,动态完成订阅并展示实时数据;
- 点击移除按钮,取消对应标的订阅,列表同步删除条目;
- 网络断开后自动重连,恢复原有订阅状态,数据正常推送。
5.2 常见问题与优化方案
-
界面卡顿
原因:网络回调在主线程频繁刷新UI。
优化:鸿蒙异步分发任务,数据解析与预处理放在子线程,仅最终视图更新回调至主线程。 -
重复订阅
优化:依托本地Set集合做前置校验,重复标的不再向服务端发送指令。 -
连接长期空闲断开
优化:启用定时心跳报文,维持长连接活性,适配服务端空闲断开策略。 -
重连后数据丢失
优化:重连成功后,自动读取本地订阅列表,批量重新下发订阅指令。
六、总结与扩展方向
6.1 文章总结
本文基于 HarmonyOS 完整实现了实时股票行情 App,采用「UI层-业务层-网络层-工具层」分层架构,通过 WebSocket 长连接实现实时数据推送与标的动态订阅/取消。代码遵循鸿蒙工程化开发规范,具备完善的异常处理、心跳保活、自动重连、资源释放能力,可直接作为金融类鸿蒙应用的基础框架使用。
整套方案既满足金融行情低延迟、数据连续的业务要求,也兼顾了移动端应用的稳定性与可维护性。
6.2 后续扩展方向
- 增加本地数据缓存,应用后台保活后恢复历史行情;
- 实现多页面状态同步,跨页面共享订阅标的;
- 增加行情走势图、K线图等可视化组件;
- 对接本地数据库,持久化存储用户自选股列表;
- 增加网络状态监听,动态提示用户网络异常。
补充说明
- 运行前务必替换代码中
YOUR_TOKEN为合法的接口访问令牌; - 该项目基于 HarmonyOS ArkTS 开发,兼容手机、平板、鸿蒙折叠屏等多端设备;
- 所有网络逻辑独立封装,可快速替换为其他行情 WebSocket 接口。
更多推荐



所有评论(0)