You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular订阅Observable数据在移动设备无法显示问题排查

Angular WebSocket 移动端数据不显示问题排查与解决

我用Angular创建了一个WebSocket服务,接收JSON格式数据,组件订阅Observable后将数据存储到数组中。桌面浏览器能正常显示数据,但移动浏览器看不到,组件内其他值显示正常。

相关代码

服务代码

import { Injectable } from "@angular/core";
import * as socketIO from "socket.io-client";
import { Observable, fromEvent, map } from "rxjs";

@Injectable({
    providedIn: "root",
})
export class SocketService {
    private socket;

    constructor() {
        this.socket = socketIO.io("http://localhost:5000");
    }

    onData(): Observable<SensorData[]> {
        return fromEvent(this.socket, "on_data").pipe(map((value: string) => JSON.parse(value)));
    }
}

export interface SensorData {
    name: string;
    subject: string;
    unit: string;
    value: number;
}

组件代码

import { Component } from "@angular/core";
import { Observable } from "rxjs";
import { SocketService, SensorData } from "src/app/socket.service";

@Component({
    selector: "app-view-sensors",
    templateUrl: "./view-sensors.component.html",
    styleUrls: ["./view-sensors.component.scss"],
})
export class ViewSensorsComponent {
    constructor(private socketService: SocketService) {}

    data$: SensorData[] = [];

    ngOnInit() {
        this.socketService.onData().subscribe((datastream) => {
            this.data$ = [];
            for (let entry of datastream) {
                let a: SensorData = { name: entry.name, subject: entry.subject, unit: entry.unit, value: entry.value };
                this.data$.push(a);
            }
        });
    }
}

模板代码

<div class="card-container">
    <ng-container *ngIf="data$">
        <mat-card class="card" *ngFor="let datapoint of data$">
            <mat-card-header>
                <mat-card-title class="title-subtitle">
                    {{ datapoint.subject }}
                </mat-card-title>
                <mat-card-subtitle class="title-subtitle">
                    {{ datapoint.unit }}
                </mat-card-subtitle>
            </mat-card-header>
            <mat-card-content>
                {{ datapoint.value | number : "1.0-0" }}
            </mat-card-content>
        </mat-card>
    </ng-container>
</div>

已做排查

  • 移除Angular Material组件后问题依旧,排除Material影响
  • 模板中写入静态值可正常显示,排除插值绑定问题
  • 禁用组件CSS后数据仍不显示,排除样式隐藏问题
    怀疑订阅环节存在问题,但不知如何排查解决。

问题定位与解决步骤

1. 修复WebSocket连接地址的可达性问题

移动设备无法访问localhost:5000——localhost在移动端指向设备自身,而非你的开发服务器。必须将Socket连接地址替换为开发机器的局域网IP(比如http://192.168.1.100:5000),同时确保:

  • Socket.IO服务器配置了跨域允许(通过cors选项)
  • 移动设备与开发机器处于同一局域网

修改SocketService的连接代码:

constructor() {
    // 替换为你的局域网IP
    this.socket = socketIO.io("http://192.168.1.100:5000");
}

2. 确保Angular变更检测触发

移动端可能存在变更检测未自动触发的情况,可通过两种方式优化:

方式1:用BehaviorSubject重构响应式数据流

这种方式更符合Angular响应式编程规范,且能自动触发变更检测:
修改SocketService:

import { Injectable } from "@angular/core";
import * as socketIO from "socket.io-client";
import { BehaviorSubject, Observable, fromEvent, map } from "rxjs";

@Injectable({
    providedIn: "root",
})
export class SocketService {
    private socket;
    private dataSubject = new BehaviorSubject<SensorData[]>([]);
    public data$ = this.dataSubject.asObservable();

    constructor() {
        this.socket = socketIO.io("http://192.168.1.100:5000");
        fromEvent(this.socket, "on_data")
            .pipe(map((value: string) => JSON.parse(value)))
            .subscribe((data) => this.dataSubject.next(data));
    }
}

组件中直接订阅Observable:

import { Component } from "@angular/core";
import { Observable } from "rxjs";
import { SocketService, SensorData } from "src/app/socket.service";

@Component({
    selector: "app-view-sensors",
    templateUrl: "./view-sensors.component.html",
    styleUrls: ["./view-sensors.component.scss"],
})
export class ViewSensorsComponent {
    data$: Observable<SensorData[]>;

    constructor(private socketService: SocketService) {
        this.data$ = socketService.data$;
    }
}

模板改用异步管道(自动处理订阅和变更检测):

<div class="card-container">
    <ng-container *ngIf="data$ | async as data">
        <mat-card class="card" *ngFor="let datapoint of data">
            <mat-card-header>
                <mat-card-title class="title-subtitle">
                    {{ datapoint.subject }}
                </mat-card-title>
                <mat-card-subtitle class="title-subtitle">
                    {{ datapoint.unit }}
                </mat-card-subtitle>
            </mat-card-header>
            <mat-card-content>
                {{ datapoint.value | number : "1.0-0" }}
            </mat-card-content>
        </mat-card>
    </ng-container>
</div>

方式2:手动触发变更检测

若不想重构现有代码,可在组件中注入ChangeDetectorRef手动标记变更:

import { Component, ChangeDetectorRef } from "@angular/core";
import { Observable } from "rxjs";
import { SocketService, SensorData } from "src/app/socket.service";

@Component({
    selector: "app-view-sensors",
    templateUrl: "./view-sensors.component.html",
    styleUrls: ["./view-sensors.component.scss"],
})
export class ViewSensorsComponent {
    constructor(private socketService: SocketService, private cdr: ChangeDetectorRef) {}

    data$: SensorData[] = [];

    ngOnInit() {
        this.socketService.onData().subscribe((datastream) => {
            this.data$ = [];
            for (let entry of datastream) {
                let a: SensorData = { name: entry.name, subject: entry.subject, unit: entry.unit, value: entry.value };
                this.data$.push(a);
            }
            // 手动触发变更检测
            this.cdr.markForCheck();
        });
    }
}

3. 移动端调试排查

使用Chrome远程调试功能连接移动设备,查看:

  • Console面板是否有WebSocket连接错误、JSON解析错误
  • Network面板查看WebSocket帧是否正常接收
  • Elements面板确认数据是否已渲染(再次排除隐藏可能性)

内容的提问来源于stack exchange,提问作者MichaelJeremias

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 15:35:26