健康数据仪表盘设计与实现

一、项目概述

基于HarmonyOS Design规范的智能健康数据仪表盘,整合步数、心率等传感器数据,采用跨设备数据同步技术实现多终端健康状态可视化。系统借鉴《鸿蒙跨端U同步》中的状态同步机制,构建统一健康数据展示平台。

二、架构设计

+---------------------+
|  数据采集层         |
|  (传感器/模拟数据)   |
+----------+----------+
           |
+----------v----------+    +---------------------+
|  数据处理引擎       |<--->| 分布式数据同步      |
|  (Data Processor)   |    | (Data Synchronizer) |
+----------+----------+    +---------------------+
           |
+----------v----------+
|  可视化展示层       |
|  (Chart Dashboard)  |
+---------------------+

三、核心代码实现

1. 健康数据模型

// 健康数据实体类
public class HealthData {
    private int steps;
    private int heartRate;
    private long timestamp;
    
    // JSON序列化
    public String toJson() {
        JSONObject json = new JSONObject();
        try {
            json.put("steps", steps);
            json.put("heartRate", heartRate);
            json.put("timestamp", timestamp);
        } catch (JSONException e) {
            return "{}";
        }
        return json.toString();
    }
    
    // JSON反序列化
    public static HealthData fromJson(String jsonStr) {
        try {
            JSONObject json = new JSONObject(jsonStr);
            HealthData data = new HealthData();
            data.steps = json.getInt("steps");
            data.heartRate = json.getInt("heartRate");
            data.timestamp = json.getLong("timestamp");
            return data;
        } catch (JSONException e) {
            return null;
        }
    }
    
    // Getters & Setters
    public int getSteps() { return steps; }
    public void setSteps(int steps) { this.steps = steps; }
    public int getHeartRate() { return heartRate; }
    public void setHeartRate(int heartRate) { this.heartRate = heartRate; }
    public long getTimestamp() { return timestamp; }
    public void setTimestamp(long timestamp) { this.timestamp = timestamp; }
}

2. 数据模拟与同步

// 健康数据管理器
public class HealthDataManager {
    private static final String SYNC_CHANNEL = "health_data_sync";
    private DistributedDataManager dataManager;
    private HealthDataListener listener;
    private Timer timer;
    private String userId;
    
    public HealthDataManager(Context context, String userId) {
        this.userId = userId;
        this.dataManager = DistributedDataManagerFactory.getInstance()
            .createDistributedDataManager(context);
        
        // 启动数据模拟
        startDataSimulation();
    }
    
    // 启动数据模拟
    private void startDataSimulation() {
        timer = new Timer();
        
        // 模拟步数数据(每5秒更新)
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                int steps = 50 + (int)(Math.random() * 20);
                notifyStepsUpdated(steps);
            }
        }, 0, 5000);
        
        // 模拟心率数据(每3秒更新)
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                int heartRate = 60 + (int)(Math.random() * 40);
                notifyHeartRateUpdated(heartRate);
            }
        }, 0, 3000);
    }
    
    // 通知步数更新
    private void notifyStepsUpdated(int steps) {
        HealthData data = new HealthData();
        data.setSteps(steps);
        data.setTimestamp(System.currentTimeMillis());
        
        // 本地回调
        if (listener != null) {
            listener.onStepsUpdated(steps);
        }
        
        // 同步到其他设备
        syncData(data);
    }
    
    // 通知心率更新
    private void notifyHeartRateUpdated(int heartRate) {
        HealthData data = new HealthData();
        data.setHeartRate(heartRate);
        data.setTimestamp(System.currentTimeMillis());
        
        // 本地回调
        if (listener != null) {
            listener.onHeartRateUpdated(heartRate);
        }
        
        // 同步到其他设备
        syncData(data);
    }
    
    // 同步数据到其他设备
    private void syncData(HealthData data) {
        dataManager.putString(
            SYNC_CHANNEL + "_" + userId,
            data.toJson()
        );
    }
    
    // 注册数据接收监听
    public void registerDataListener(HealthDataListener listener) {
        this.listener = listener;
        
        dataManager.registerDataChangeListener(
            SYNC_CHANNEL + "_" + userId,
            new DataChangeListener() {
                @Override
                public void onDataChanged(String deviceId, String key, String value) {
                    HealthData data = HealthData.fromJson(value);
                    if (data != null && listener != null) {
                        if (data.getSteps() > 0) {
                            listener.onStepsUpdated(data.getSteps());
                        }
                        if (data.getHeartRate() > 0) {
                            listener.onHeartRateUpdated(data.getHeartRate());
                        }
                    }
                }
            }
        );
    }
    
    public interface HealthDataListener {
        void onStepsUpdated(int steps);
        void onHeartRateUpdated(int heartRate);
    }
}

3. 仪表盘UI实现

// 健康仪表盘AbilitySlice
public class HealthDashboardSlice extends AbilitySlice 
    implements HealthDataManager.HealthDataListener {
    
    private Text stepsText, heartRateText;
    private LineChartView stepsChart, heartRateChart;
    private HealthDataManager dataManager;
    
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        initUI();
        
        // 初始化数据管理器
        String userId = "user123"; // 实际应用中从账户系统获取
        dataManager = new HealthDataManager(this, userId);
        dataManager.registerDataListener(this);
    }
    
    private void initUI() {
        DirectionalLayout rootLayout = new DirectionalLayout(this);
        rootLayout.setOrientation(Component.VERTICAL);
        rootLayout.setPadding(32, 32, 32, 32);
        rootLayout.setBackground(new ShapeElement().setShape(ShapeElement.RECTANGLE)
            .setRgbColor(RgbColor.fromArgbInt(0xFFF5F5F5)));
        super.setUIContent(rootLayout);
        
        // 标题
        Text title = new Text(this);
        title.setText("健康数据仪表盘");
        title.setTextSize(32);
        title.setTextColor(RgbColor.fromArgbInt(0xFF333333));
        rootLayout.addComponent(title);
        
        // 实时数据面板
        DirectionalLayout realtimePanel = createRealtimePanel();
        rootLayout.addComponent(realtimePanel);
        
        // 图表区域
        DirectionalLayout chartArea = new DirectionalLayout(this);
        chartArea.setOrientation(Component.VERTICAL);
        chartArea.setMarginTop(24);
        
        // 步数图表
        Text stepTitle = new Text(this);
        stepTitle.setText("今日步数趋势");
        stepTitle.setTextSize(24);
        chartArea.addComponent(stepTitle);
        
        stepsChart = new LineChartView(this);
        stepsChart.setHeight(300);
        stepsChart.setMarginTop(12);
        chartArea.addComponent(stepsChart);
        
        // 心率图表
        Text hrTitle = new Text(this);
        hrTitle.setText("心率变化趋势");
        hrTitle.setTextSize(24);
        hrTitle.setMarginTop(24);
        chartArea.addComponent(hrTitle);
        
        heartRateChart = new LineChartView(this);
        heartRateChart.setHeight(300);
        heartRateChart.setMarginTop(12);
        chartArea.addComponent(heartRateChart);
        
        rootLayout.addComponent(chartArea);
    }
    
    private DirectionalLayout createRealtimePanel() {
        DirectionalLayout panel = new DirectionalLayout(this);
        panel.setOrientation(Component.HORIZONTAL);
        panel.setPadding(24, 24, 24, 24);
        panel.setBackground(new ShapeElement().setShape(ShapeElement.RECTANGLE)
            .setRgbColor(RgbColor.fromArgbInt(0xFFFFFFFF))
            .setCornerRadius(16));
        
        // 步数卡片
        DirectionalLayout stepCard = createDataCard("步数", "步");
        stepsText = (Text) stepCard.getComponentAt(1);
        panel.addComponent(stepCard);
        
        // 心率卡片
        DirectionalLayout hrCard = createDataCard("心率", "bpm");
        heartRateText = (Text) hrCard.getComponentAt(1);
        hrCard.setMarginLeft(24);
        panel.addComponent(hrCard);
        
        return panel;
    }
    
    private DirectionalLayout createDataCard(String title, String unit) {
        DirectionalLayout card = new DirectionalLayout(this);
        card.setOrientation(Component.VERTICAL);
        
        Text titleView = new Text(this);
        titleView.setText(title);
        titleView.setTextSize(20);
        titleView.setTextColor(RgbColor.fromArgbInt(0xFF666666));
        card.addComponent(titleView);
        
        Text valueView = new Text(this);
        valueView.setText("--");
        valueView.setTextSize(36);
        valueView.setTextColor(RgbColor.fromArgbInt(0xFF333333));
        valueView.setMarginTop(8);
        card.addComponent(valueView);
        
        Text unitView = new Text(this);
        unitView.setText(unit);
        unitView.setTextSize(16);
        unitView.setTextColor(RgbColor.fromArgbInt(0xFF999999));
        unitView.setMarginTop(4);
        card.addComponent(unitView);
        
        return card;
    }
    
    // 实现HealthDataListener接口
    @Override
    public void onStepsUpdated(int steps) {
        getUITaskDispatcher().asyncDispatch(() -> {
            stepsText.setText(String.valueOf(steps));
            stepsChart.addDataPoint(steps);
        });
    }
    
    @Override
    public void onHeartRateUpdated(int heartRate) {
        getUITaskDispatcher().asyncDispatch(() -> {
            heartRateText.setText(String.valueOf(heartRate));
            heartRateChart.addDataPoint(heartRate);
        });
    }
    
    @Override
    protected void onStop() {
        super.onStop();
        if (dataManager != null) {
            dataManager = null;
        }
    }
}

4. 折线图组件实现

// 折线图组件(遵循HarmonyOS Design规范)
public class LineChartView extends Component {
    private static final int MAX_DATA_POINTS = 10;
    private List<Integer> dataPoints = new ArrayList<>();
    private Paint linePaint = new Paint();
    private Paint pointPaint = new Paint();
    private Paint gridPaint = new Paint();
    private Paint textPaint = new Paint();
    
    public LineChartView(Context context) {
        super(context);
        initPaints();
    }
    
    private void initPaints() {
        // 折线样式
        linePaint.setColor(RgbColor.fromArgbInt(0xFF007DFF).getValue());
        linePaint.setStrokeWidth(5);
        linePaint.setStyle(Paint.Style.STROKE);
        linePaint.setAntiAlias(true);
        
        // 数据点样式
        pointPaint.setColor(RgbColor.fromArgbInt(0xFF007DFF).getValue());
        pointPaint.setStyle(Paint.Style.FILL);
        pointPaint.setAntiAlias(true);
        
        // 网格样式
        gridPaint.setColor(RgbColor.fromArgbInt(0xFFE0E0E0).getValue());
        gridPaint.setStrokeWidth(1);
        
        // 文本样式
        textPaint.setColor(RgbColor.fromArgbInt(0xFF666666).getValue());
        textPaint.setTextSize(24);
    }
    
    public void addDataPoint(int value) {
        dataPoints.add(value);
        if (dataPoints.size() > MAX_DATA_POINTS) {
            dataPoints.remove(0);
        }
        invalidate();
    }
    
    @Override
    public void onDraw(ComponentCanvas canvas) {
        super.onDraw(canvas);
        
        if (dataPoints.isEmpty()) return;
        
        int width = getWidth();
        int height = getHeight();
        int padding = 20;
        
        // 绘制背景网格
        drawGrid(canvas, width, height, padding);
        
        // 计算最大值用于缩放
        int maxValue = Collections.max(dataPoints);
        if (maxValue == 0) maxValue = 1;
        
        // 绘制折线
        Path path = new Path();
        for (int i = 0; i < dataPoints.size(); i++) {
            float x = padding + i * (width - 2 * padding) / (dataPoints.size() - 1);
            float y = height - padding - (dataPoints.get(i) * (height - 2 * padding) / maxValue);
            
            if (i == 0) {
                path.moveTo(x, y);
            } else {
                path.lineTo(x, y);
            }
            
            // 绘制数据点
            canvas.drawCircle(x, y, 8, pointPaint);
        }
        
        canvas.drawPath(path, linePaint);
    }
    
    private void drawGrid(ComponentCanvas canvas, int width, int height, int padding) {
        // 水平网格线
        for (int i = 0; i < 5; i++) {
            float y = padding + i * (height - 2 * padding) / 4;
            canvas.drawLine(padding, y, width - padding, y, gridPaint);
        }
        
        // 垂直网格线
        for (int i = 0; i < dataPoints.size(); i++) {
            float x = padding + i * (width - 2 * padding) / (dataPoints.size() - 1);
            canvas.drawLine(x, padding, x, height - padding, gridPaint);
        }
    }
}

四、技术创新点

  1. ​多设备数据同步​​:基于分布式数据管理实现跨设备健康数据共享
  2. ​实时数据可视化​​:动态图表展示健康指标变化趋势
  3. ​HarmonyOS Design规范​​:严格遵循华为设计语言和交互规范
  4. ​模拟数据生成​​:在没有真实传感器时提供模拟数据支持
  5. ​性能优化​​:高效的数据处理和UI渲染机制

五、总结

本健康数据仪表盘系统实现了以下核心价值:

  1. ​全面监测​​:整合步数、心率等关键健康指标
  2. ​直观展示​​:通过图表清晰呈现数据变化趋势
  3. ​多端协同​​:基于《鸿蒙跨端U同步》技术实现跨设备数据共享
  4. ​设计规范​​:符合HarmonyOS Design设计语言
  5. ​扩展性强​​:支持接入更多健康传感器和指标

系统借鉴了游戏场景中的多设备同步机制,将其应用于健康数据领域,为用户提供统一的健康管理体验。未来可结合AI分析提供健康建议,并增加更多生物特征监测功能。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐